Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,251 @@
# Restrict Content Pro - REST API
This plugin provides a REST API for [Restrict Content Pro](http://restrictcontentpro.com). It is dependent upon the [WordPress REST API](http://wp-api.org) and does not function without it.
### Endpoint:
The RCP REST API is available at `/wp-json/rcp/`.
If the default `wp-json` endpoint has been changed, the `rcp` endpoint will respect that change, so adjust accordingly.
### Versioning:
Each distinct version of the REST API is accessible via the `rcp` endpoint. Versions may be deprecated at anytime but at no time will breaking changes be implementing without incrementing the version number. Past versions are expected to be kept available for at least six months beyond the release of the proceeding version.
- /wp-json/rcp/{version}/{route}
Example:
- /wp-json/rcp/v1/{route}
### Authentication
The RCP REST API requires authenticating with a WordPress user account that has the necessary capabilities in order to view, modify, and delete information via the REST API.
Please see the [WordPress REST API Authentication](http://v2.wp-api.org/guide/authentication/) documentation to instructions on how to authenticate with the API.
### Routes
There are four routes provided with this API:
#### Members:
- `GET` /wp-json/rcp/{version}/members/
- `GET` /wp-json/rcp/{version}/members/{member_id}
- `POST` /wp-json/rcp/{version}/members/new
- `POST` /wp-json/rcp/{version}/members/update/{member_id}
- `DELETE` /wp-json/rcp/{version}/members/
Each of the three HTTP methods support additional arguments that can be passed in with the `body` of the request.
*GET* `/wp-json/rcp/{version}/members/`:
Required parameters:
None.
Optional parameters:
- `status` - Retrieve only members with the specified status
- - `active`, `pending`, `cancelled`, `expired`
- `subscription` - The subscription level ID from which to retrieve members
- `recurring` - Whether to include recurring or non-recurring members only
- - `1`, `0`
- `number` - The total of members to retrieve per page
- `offset` - The number of members to skip (for pagination purposes)
- `orderby` - The field on which to order the members returned
- - Any field allowed to be passed to [get_users()](#)
- `order` - The direction which to sort members
- - `ASC`, `DESC`
- `s` - Search value, such as the name, email, or user log in of the member
*GET* `/wp-json/rcp/{version}/members/{member_id}`:
Required parameters:
- `id` - The member ID to retrieve. Can be passed in the URL or as part of the body.
Optional parameters:
None.
*POST* `/wp-json/rcp/{version}/members/new`:
Required parameters:
- `login` - The log in name to assign to the newly created member account
Optional parameters:
- `status` - The subscription status to assign to the member
- `expiration` - The expiration date to assign to the member
- `subscription` - The subscription level ID to assign to the member
- `profile_id` - The payment profile ID of the member
- `recurring` - Boolean flag that indicates if the subscription is recurring or one-time only
- - `1` or `0`
- Any parameter supported by [wp_insert_user()](#)
*POST* `/wp-json/rcp/{version}/members/update/{member_id}`:
Required parameters:
- `id` - The member ID to update. Can be passed in the URL or as part of the body.
Optional parameters:
- `status` - The subscription status to assign to the member
- `expiration` - The expiration date to assign to the member
- `subscription` - The subscription level ID to assign to the member
- `profile_id` - The payment profile ID of the member
- `recurring` - Boolean flag that indicates if the subscription is recurring or one-time only
- - `1` or `0`
- Any parameter supported by [wp_insert_user()](#)
*DELETE* `/wp-json/rcp/{version}/members/delete`:
Required parameters:
- `id` - The ID of the member account to delete
Optional parameters:
None.
#### Payments:
- `GET` /wp-json/rcp/{version}/payments/
- `GET` /wp-json/rcp/{version}/payments/{payment_id}
- `POST` /wp-json/rcp/{version}/payments/new
- `POST` /wp-json/rcp/{version}/payments/update/{payment_id}
- `DELETE` /wp-json/rcp/{version}/payments/
Each of the three HTTP methods support additional arguments that can be passed in with the `body` of the request.
*POST* `/wp-json/rcp/{version}/payments/new`:
Required parameters:
- `user_id` - The member account ID the payment belongs to
- `amount` - The total amount of the payment
- `subscription` - The name of the subscription level the payment was recorded for
Optional parameters:
- `status` - The status of the payment
- - `complete` or `refunded`
- `subscription_key` - The subscription key of the level the payment was recorded for
- `transaction_id` - The transaction ID from the merchant processor of the payment
- `date` - The date the payment was processed
- `payment_type` - A descriptor of the payment type
- - Example: `Credit Card`, `PayPal`, or `Credit Card One Time`
*POST* `/wp-json/rcp/{version}/payments/update/{payment_id}`:
- `id` - The payment ID to update. Can be passed in the URL or as part of the body.
Optional parameters:
- `amount` - The total amount of the payment
- `user_id` - The member account ID the payment belongs to
- `status` - The status of the payment
- - `complete` or `refunded`
- `subscription` - The name of the subscription level the payment was recorded for
- `subscription_key` - The subscription key of the level the payment was recorded for
- `transaction_id` - The transaction ID from the merchant processor of the payment
- `date` - The date the payment was processed
- `payment_type` - A descriptor of the payment type
- - Example: `Credit Card`, `PayPal`, or `Credit Card One Time`
*DELETE* `/wp-json/rcp/{version}/payments/delete`:
Required parameters:
- `id` - The ID of the payment record to delete
Optional parameters:
None.
#### Earnings:
- `GET` /wp-json/rcp/{version}/earnings/
#### Levels:
- `GET` /wp-json/rcp/{version}/levels/
- `GET` /wp-json/rcp/{version}/levels/{level_id}
- `POST` /wp-json/rcp/{version}/levels/new
- `POST` /wp-json/rcp/{version}/levels/update/{level_id}
- `DELETE` /wp-json/rcp/{version}/levels/
Each of the three HTTP methods support additional arguments that can be passed in with the `body` of the request.
*GET* `/wp-json/rcp/{version}/levels/`:
Required parameters:
None.
Optional parameters:
- `status` - Default is `all`. Set to `active` or `inactive` to only retrieve those levels.
- `limit` - Number of levels to return in the results. Default is `null` to retrieve all levels.
- `orderby` - Database column name used to order the results. Default is `list_order`.
*GET* `/wp-json/rcp/{version}/levels/{level_id}`:
Required parameters:
- `id` - The ID of the membership level to retrieve. Can be passed in the URL or as part of the body.
Optional parameters:
None.
*POST* `/wp-json/rcp/{version}/levels/new`:
Required parameters:
- `name` - The name of the membership level.
Optional parameters:
- `description` - Description of the level.
- `duration` - Integer length of the level or "unlimited".
- `duration_unit` - Duration unit, such as "day", "month", or "year".
- `trial_duration` - Integer length of the integrated free trial, or `0` for none.
- `trial_duration_unit` - Trial duration unit, such as "day", "month", or "year".
- `price` - Integer or float price for the level. `0` for free.
- `fee` - Integer or float signup fee.
- `list_order` - Integer. Determines where in the registration list the level appears. Lower numbers appear first.
- `level` - Integer. Associated access level (1-10).
- `status` - `active` or `inactive`.
- `role` - Associated user role granted to members of this level.
*POST* `/wp-json/rcp/{version}/levels/update/{level_id}`:
- `id` - The membership level ID to update. Can be passed in the URL or as part of the body.
Optional parameters:
- `name` - Name of the level.
- `description` - Description of the level.
- `duration` - Integer length of the level or "unlimited".
- `duration_unit` - Duration unit, such as "day", "month", or "year".
- `trial_duration` - Integer length of the integrated free trial, or `0` for none.
- `trial_duration_unit` - Trial duration unit, such as "day", "month", or "year".
- `price` - Integer or float price for the level. `0` for free.
- `fee` - Integer or float signup fee.
- `list_order` - Integer. Determines where in the registration list the level appears. Lower numbers appear first.
- `level` - Integer. Associated access level (1-10).
- `status` - `active` or `inactive`.
- `role` - Associated user role granted to members of this level.
*DELETE* `/wp-json/rcp/{version}/levels/delete`:
Required parameters:
- `id` - The ID of the membership level to delete.
Optional parameters:
None.

View File

@@ -0,0 +1,17 @@
{
"name": "restrictcontentpro/rcp-rest-api",
"type": "wordpress-plugin",
"description": "Adds a REST API to Restrict Content Pro",
"keywords": [ "api", "plugin"],
"homepage": "http://restrictcontentpro.com",
"authors": [
{
"name": "Pippin Williamson",
"email": "pippin@pippinsplugins.com",
"homepage": "http://pippin.com"
}
],
"require": {
"composer/installers": "~1.0.6"
}
}

View File

@@ -0,0 +1,2 @@
1.2.2 - 2020-09-01 - Chris Jean
Added new updater.

View File

@@ -0,0 +1,155 @@
<?php
/**
* Membership Level
*
* @package rcp-rest-api
* @copyright Copyright (c) 2018, Restrict Content Pro team
* @license GPL2+
* @since 1.1
*/
class RCP_REST_API_Level {
/**
* @var int ID of the membership level.
*/
public $id = 0;
/**
* @var string Membership level name.
*/
public $name = '';
/**
* @var string Description.
*/
public $description = '';
/**
* @var int Duration of the membership period. 0 for unlimited.
*/
public $duration = 0;
/**
* @var string Duration unit.
*/
public $duration_unit = 'month';
/**
* @var int Duration of the integrated trial. 0 for none.
*/
public $trial_duration = 0;
/**
* @var string Duration unit for the integrated trial.
*/
public $trial_duration_unit = 'day';
/**
* @var int Price of the membership level. 0 for free.
*/
public $price = 0;
/**
* @var int Signup fee amount.
*/
public $fee = 0;
/**
* @var int List order.
*/
public $list_order = 0;
/**
* @var int Access level granted to members of this level.
*/
public $level = 0;
/**
* @var string Membership level status - "active" or "inactive".
*/
public $status = 'inactive';
/**
* @var string User role granted to members of this level.
*/
public $role = 'subscriber';
/**
* RCP_REST_API_Level constructor.
*
* @param int $_id
*
* @access public
* @since 1.1
*/
public function __construct( $_id = 0 ) {
$this->setup( $_id );
}
/**
* Initialize the membership level object
*
* @param int $_id
*
* @access public
* @since 1.1
* @return void
*/
public function setup( $_id = 0 ) {
if ( empty( $_id ) ) {
return;
}
$db = new RCP_Levels();
$level = $db->get_level( $_id );
if ( $level ) {
foreach ( $level as $key => $value ) {
$this->$key = $value;
}
}
}
/**
* Sanitize membership level arguments for update / new queries.
*
* @param array $args
*
* @access public
* @since 1.1
* @return array
*/
public function sanitize_level_args( $args = array() ) {
$whitelist = array(
'name', // Name of the membership level.
'description', // Description of the level.
'duration', // Integer length of the level or "unlimited".
'duration_unit', // Duration unit, such as "day", "month", "year".
'trial_duration', // Integer length of the integrated free trial, or `0` for none.
'trial_duration_unit', // Trial duration unit, such as "day", "month", "year".
'price', // Integer or float price for the level. `0` for free.
'fee', // Integer or float signup fee.
'list_order', // Determines where in the list the level appears.
'level', // Associated access level (integer).
'status', // Active or inactive.
'role' // Associated user role granted to members of this level.
);
foreach ( $args as $key => $value ) {
// Do not allow empty values
if ( empty( $key ) || empty( $value ) || ! in_array( $key, $whitelist ) ) {
unset( $args[ $key ] );
}
}
return $args;
}
}

View File

@@ -0,0 +1,78 @@
<?php
class RCP_REST_API_Member extends RCP_Member {
public $subscription_name;
public $subscription_id;
public $subscription_key;
public $access_level;
public $expiration_date;
public $expiration_time;
public $status;
public $is_active;
public $is_recurring;
public $payment_profile_id;
public $notes;
public $payments;
public $is_trialing;
public $has_trialed;
/**
* Setup our member properties
*
* @since 1.0
*/
public function setup( $_id = 0 ) {
$this->subscription_id = $this->get_subscription_id();
$this->subscription_name = $this->get_subscription_name();
$this->subscription_key = $this->get_subscription_key();
$this->access_level = rcp_get_subscription_access_level( $this->subscription_id );
$this->expiration_date = $this->get_expiration_date();
$this->expiration_time = $this->get_expiration_time();
$this->status = $this->get_status();
$this->is_active = $this->is_active();
$this->is_recurring = $this->is_recurring();
$this->is_trialing = $this->is_trialing();
$this->has_trialed = $this->has_trialed();
$this->payment_profile_id = $this->get_payment_profile_id();
$this->notes = $this->get_notes();
$this->payments = $this->get_payments();
}
/**
* Helper method for updating subscription level
*
* @since 1.0
*/
public function set_subscription( $subscription_id = 0 ) {
delete_user_meta( $this->ID, 'rcp_pending_subscription_level' );
update_user_meta( $this->ID, 'rcp_subscription_level', $subscription_id );
}
/**
* Sanitize expiration date to ensure it's sent in with the proper format
*
* @since 1.0
*/
public function sanitize_expiration( $expiration = '' ) {
if( is_int( $expiration ) ) {
$expiration = date( 'Y-n-d H:i:s', $expiration );
} elseif( 'none' === $expiration ) {
$expiration = 'none';
} else {
$expiration = date( 'Y-n-d H:i:s', strtotime( $expiration, current_time( 'timestamp' ) ) );
}
return $expiration;
}
}

View File

@@ -0,0 +1,122 @@
<?php
class RCP_REST_API_Payment {
public $subscription = '';
public $subscription_id = 0;
public $subscription_key = '';
public $date = '00-00-00 00:00:00';
public $amount = '';
public $user_id = 0;
public $transaction_id = '';
public $status = '';
/**
* Get things started
*
* @since 1.0
*/
public function __construct( $_id = 0 ) {
$this->setup( $_id );
}
/**
* Initialize the payment object
*
* @since 1.0
*/
public function setup( $_id = 0 ) {
if( empty( $_id ) ) {
return;
}
$db = new RCP_Payments;
$payment = $db->get_payment( $_id );
if( $payment ) {
foreach( $payment as $key => $value ) {
$this->$key = $value;
}
$this->subscription_id = rcp_get_subscription_details_by_name( $payment->subscription )->id;
}
}
/**
* Sanitize payment arguments for update / new queries
*
* @since 1.0
*/
public function sanitize_payment_args( $args = array() ) {
$whitelist = array(
'subscription', // Name of the associated subscription level.
'object_id', // ID of the associated object (subscription level).
'object_type', // Type of object, such as "subscription".
'date', // Date the payment was made, in MySQL format.
'amount', // Total amount the payment was for, after fees/credits/discounts are applied.
'subtotal', // Base price of the subscription level.
'credits', // Credits applied towards the payment (such as prorated credits).
'fees', // Fees applied towards the payment.
'discount_amount', // Discounted amount.
'discount_code', // Applied discount code, if any.
'user_id', // ID number of the associated user.
'payment_type', // Type of payment, i.e. "Credit card one time".
'subscription_key', // Unique key for this subscription.
'transaction_id', // Transaction ID from the gateway for this payment.
'status', // Status of the payment (complete, refunded, pending, etc.).
'gateway', // Slug of the gateway that was used for this payment.
'customer_id', // ID of the associated customer.
'membership_id', // ID of the associated membership.
);
foreach( $args as $key => $value ) {
// Do not allow empty values
if( empty( $key ) || empty( $value ) || ! in_array( $key, $whitelist ) ) {
unset( $args[ $key ] );
}
}
if( isset( $args['subscription'] ) && is_int( $args['subscription'] ) ) {
if( ! empty( $this->subscription ) ) {
$args['subscription'] = $this->subscription;
} else {
if ( empty( $args['object_id'] ) ) {
$args['object_id'] = absint( $args['subscription'] );
}
$args['subscription'] = rcp_get_subscription_name( $args['subscription'] );
}
}
if( isset( $args['subscription_id'] ) ) {
// If `object_id` hasn't been supplied, we can use the subscription ID for this.
if ( empty( $args['object_id'] ) && is_int( $args['subscription_id'] ) ) {
$args['object_id'] = absint( $args['subscription_id'] );
}
unset( $args['subscription_id'] );
}
return $args;
}
}

View File

@@ -0,0 +1,72 @@
<?php
class RCP_REST_API_Routes {
/**
* Holds our routes
*
* @since 1.0
*/
private $routes;
/**
* Get started
*
* @since 1.0
*/
public function __construct() {
$v1_routes = array(
'earnings' => 'RCP_REST_API_Earnings_Route_V1',
'levels' => 'RCP_REST_API_Membership_Level_Route_V1',
'members' => 'RCP_REST_API_Member_Route_V1',
'payments' => 'RCP_REST_API_Payment_Route_V1',
);
if ( defined( 'RCP_PLUGIN_VERSION' ) && version_compare( RCP_PLUGIN_VERSION, '3.0', '>=' ) ) {
$v1_routes['customers'] = 'RCP_REST_API_Customer_Route_V1';
$v1_routes['memberships'] = 'RCP_REST_API_Membership_Route_V1';
}
$this->routes['v1'] = $v1_routes;
$this->load();
foreach( $this->routes as $version => $routes ) {
foreach( $routes as $route ) {
if ( class_exists( $route ) ) {
new $route;
}
}
}
}
/**
* Load our files
*
* @since 1.0
*/
private function load() {
$path = trailingslashit( dirname( __FILE__ ) );
// Load each enabled integrations
require_once $path . 'routes/class-route.php';
foreach( $this->routes as $version => $routes ) {
foreach( $routes as $filename => $class ) {
if( file_exists( $path . 'routes/' . $version . '/class-' . $filename . '-route.php' ) ) {
require_once $path . 'routes/' . $version . '/class-' . $filename . '-route.php';
}
}
}
}
}

View File

@@ -0,0 +1,171 @@
<?php
class RCP_REST_API_Route {
public $id = '';
public $body = array();
public $query_args = array();
/**
* Constructor
*
* @since 1.0
*/
public function __construct() {
$this->init();
$this->actions();
}
/**
* Get things started
*
* @since 1.0
*/
public function init() {}
/**
* Add our actions to register routes
*
* @since 1.0
*/
public function actions() {
add_action( 'rest_api_init', array( $this, 'register_v1_routes' ) );
}
/**
* Register our routes
*
* @since 1.0
*/
public function register_v1_routes() {
register_rest_route( 'rcp/v1', '/' . $this->id, array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'process_get_data' ),
'permission_callback' => array( $this, 'can_view' )
) );
register_rest_route( 'rcp/v1', '/' . $this->id . '/(?P<id>\d+)', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'process_get_data' ),
'permission_callback' => array( $this, 'can_view' ),
) );
register_rest_route( 'rcp/v1', '/' . $this->id . '/new', array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'process_new_post_data' ),
'permission_callback' => array( $this, 'can_edit' )
) );
register_rest_route( 'rcp/v1', '/' . $this->id . '/update/(?P<id>\d+)', array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'process_update_post_data' ),
'permission_callback' => array( $this, 'can_edit' )
) );
register_rest_route( 'rcp/v1', '/' . $this->id . '/delete/(?P<id>\d+)', array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'process_delete_data' ),
'permission_callback' => array( $this, 'can_edit' )
) );
}
/**
* Process GET requests
*
* @since 1.0
*/
public function process_get_data( WP_REST_Request $request ) {
$this->query_args = $request->get_params();
return $this->get_data( $request );
}
/**
* Process POST create requests
*
* @since 1.0
*/
public function process_new_post_data( WP_REST_Request $request ) {
$this->body = $request->get_body_params();
return $this->new_post_data( $request );
}
/**
* Process POST update requests
*
* @since 1.0
*/
public function process_update_post_data( WP_REST_Request $request ) {
$this->body = array_merge( $request->get_url_params(), $request->get_body_params() );
return $this->update_post_data( $request );
}
/**
* Process POST delete requests
*
* @since 1.0
*/
public function process_delete_data( WP_REST_Request $request ) {
$this->body = $request->get_params();
return $this->delete_data( $request );
}
/**
* Retrieve response data
*
* @since 1.0
*/
public function get_data( WP_REST_Request $request ) {
$response = new WP_Error( 'invalid_route', __( 'Invalid route', 'rcp-rest' ), array( 'status' => 404 ) );
return new WP_REST_Response( $response );
}
/**
* Retrieve new POST response data
*
* @since 1.0
*/
public function new_post_data( WP_REST_Request $request ) {
$response = new WP_Error( 'invalid_route', __( 'Invalid route', 'rcp-rest' ), array( 'status' => 404 ) );
return new WP_REST_Response( $response );
}
/**
* Retrieve update POST response data
*
* @since 1.0
*/
public function update_post_data( WP_REST_Request $request ) {
$response = new WP_Error( 'invalid_route', __( 'Invalid route', 'rcp-rest' ), array( 'status' => 404 ) );
return new WP_REST_Response( $response );
}
/**
* Retrieve DELETE response data
*
* @since 1.0
*/
public function delete_data( WP_REST_Request $request ) {
$response = new WP_Error( 'invalid_route', __( 'Invalid route', 'rcp-rest' ), array( 'status' => 404 ) );
return new WP_REST_Response( $response );
}
/**
* Determine if authenticated user has permission to access response data
*
* @since 1.0
*/
public function can_view() {
return current_user_can( 'edit_users' );
}
/**
* Determine if authenticated user has permission to edit data
*
* @since 1.0
*/
public function can_edit() {
return current_user_can( 'edit_users' );
}
}

View File

@@ -0,0 +1,312 @@
<?php
/**
* Customer Route
*
* @package rcp
* @copyright Copyright (c) 2019, Restrict Content Pro team
* @license GPL2+
* @since 1.1
*/
class RCP_REST_API_Customer_Route_V1 extends RCP_REST_API_Route {
/**
* Array of whitelisted customer fields.
*
* @var array
*/
private $customer_fields;
/**
* Get things started
*
* @since 1.0
*/
public function init() {
$this->id = 'customers';
// Whitelist of customer fields that can be altered and their associated query arg name.
$this->customer_fields = array(
'id',
'user_id',
'user_args',
'date_registered',
'email_verification',
'has_trialed',
'last_login',
'ips',
'notes'
);
}
/**
* @param RCP_Customer $customer
*
* @since 1.1
* @return object
*/
private function format_customer( RCP_Customer $customer ) {
$data = new stdClass();
$data->id = $customer->get_id();
$data->user_id = $customer->get_user_id();
$data->date_registered = $customer->get_date_registered( false );
$data->email_verification = $customer->get_email_verification_status();
$data->last_login = $customer->get_last_login( false );
$data->ips = $customer->get_ips();
$data->notes = $customer->get_notes();
$membership_ids = array();
$memberships = $customer->get_memberships();
if ( ! empty( $memberships ) ) {
foreach ( $memberships as $membership ) {
/**
* @var RCP_Membership $membership
*/
$membership_ids[] = $membership->get_id();
}
}
$data->memberships = array_map( 'absint', $membership_ids );
return $data;
}
/**
* Get data
*
* If the `id` parameter is provided then information about a single customer is retrieved.
* Otherwise, an array of customer results is returned.
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response
*/
public function get_data( WP_REST_Request $request ) {
$invalid_customer = new WP_Error( 'invalid_customer', __( 'Invalid customer', 'rcp-rest' ), array( 'status' => 404 ) );
if ( $request->get_param( 'id' ) ) {
/**
* Get single customer by ID.
*/
$customer = rcp_get_customer( absint( $request->get_param( 'id' ) ) );
if ( empty( $customer ) ) {
return new WP_REST_Response( $invalid_customer, 404 );
}
return new WP_REST_Response( $this->format_customer( $customer ) );
} elseif ( $request->get_param( 'user_id' ) ) {
/**
* Get single customer by user ID.
*/
$customer = rcp_get_customer_by_user_id( absint( $request->get_param( 'user_id' ) ) );
if ( empty( $customer ) ) {
return new WP_REST_Response( $invalid_customer, 404 );
}
return new WP_REST_Response( $this->format_customer( $customer ) );
} elseif ( $request->get_param( 'user_email' ) ) {
/**
* Get a single customer by email.
*/
$user = get_user_by( 'email', $request->get_param( 'user_email' ) );
if ( ! $user instanceof WP_User ) {
return new WP_REST_Response( $invalid_customer, 404 );
}
$customer = rcp_get_customer_by_user_id( absint( $user->ID ) );
if ( ! $customer instanceof RCP_Customer ) {
return new WP_REST_Response( $invalid_customer, 404 );
}
return new WP_REST_Response( $this->format_customer( $customer ) );
} elseif( $request->get_param( 'user_login' ) ) {
/**
* Get a single customer by user login.
*/
$user = get_user_by( 'login', $request->get_param( 'user_login' ) );
if ( ! $user instanceof WP_User ) {
return new WP_REST_Response( $invalid_customer, 404 );
}
$customer = rcp_get_customer_by_user_id( absint( $user->ID ) );
if ( ! $customer instanceof RCP_Customer ) {
return new WP_REST_Response( $invalid_customer, 404 );
}
return new WP_REST_Response( $this->format_customer( $customer ) );
} else {
/**
* Get array of customers.
*/
$customers = rcp_get_customers( $request->get_params() );
if ( ! empty( $customers ) ) {
$response = array_map( array( $this, 'format_customer' ), $customers );
} else {
$response = new WP_Error( 'no_customers', __( 'No customers found', 'rcp-rest-api' ), array( 'status' => 404 ) );
}
return new WP_REST_Response( $response );
}
}
/**
* Add a new customer
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response ID of the newly created customer on success.
*/
public function new_post_data( WP_REST_Request $request ) {
$args = array();
foreach ( $request->get_params() as $key => $value ) {
if ( in_array( $key, $this->customer_fields ) ) {
$args[ $key ] = wp_slash( $value );
}
}
$customer_id = rcp_add_customer( $args );
if ( empty( $customer_id ) ) {
$invalid_customer = new WP_Error( 'create_failed', __( 'Failed to add new customer', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $invalid_customer );
}
return new WP_REST_Response( absint( $customer_id ) );
}
/**
* Update an existing customer
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response
*/
public function update_post_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
if ( ! $request->get_param( 'id' ) ) {
$response = new WP_Error( 'missing_id', __( 'No customer ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
$args = array();
foreach ( $request->get_params() as $key => $value ) {
if ( in_array( $key, $this->customer_fields ) ) {
$args[ $key ] = wp_slash( $value );
}
}
$updated = rcp_update_customer( absint( $request->get_param( 'id' ) ), $args );
if ( $updated ) {
$response = 1;
} else {
$response = new WP_Error( 'update_failed', __( 'Update Failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
return new WP_REST_Response( $response );
}
/**
* Delete a customer
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response
*/
public function delete_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
if ( ! $request->get_param( 'id' ) ) {
$response = new WP_Error( 'missing_id', __( 'No customer ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
$deleted = rcp_delete_customer( absint( $request->get_param( 'id' ) ) );
if ( $deleted ) {
$response = 1;
} else {
$response = new WP_Error( 'delete_failed', __( 'Delete Failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
return new WP_REST_Response( $response );
}
/**
* Determine if authenticated user has permission to access response data
*
* @since 1.1
* @return bool
*/
public function can_view() {
return current_user_can( 'rcp_view_members' );
}
/**
* Determine if authenticated user has permission to edit data
*
* @since 1.1
* @return bool
*/
public function can_edit() {
return current_user_can( 'rcp_manage_members' );
}
}

View File

@@ -0,0 +1,67 @@
<?php
class RCP_REST_API_Earnings_Route_V1 extends RCP_REST_API_Route {
/**
* @var RCP_Payments $db
*/
protected $db;
/**
* Get things started
*
* @since 1.0
*/
public function init() {
$this->id = 'earnings';
$this->db = new RCP_Payments;
}
/**
* Retrieve response data
*
* @since 1.0
*/
public function get_data( WP_REST_Request $request ) {
$current_time = current_time( 'timestamp' );
$today = array(
'day' => date( 'd', $current_time ),
'month' => date( 'n', $current_time ),
'year' => date( 'Y', $current_time )
);
$month = array(
'month' => date( 'n', $current_time ),
'year' => date( 'Y', $current_time )
);
$year = array(
'year' => date( 'Y', $current_time )
);
$response = array(
'today' => $this->db->get_earnings( array( 'date' => $today ) ),
'month' => $this->db->get_earnings( array( 'date' => $month ) ),
'year' => $this->db->get_earnings( array( 'date' => $year ) ),
'currency' => array(
'code' => rcp_get_currency(),
'symbol' => rcp_get_currency_symbol()
)
);
return new WP_REST_Response( $response );
}
/**
* Determine if authenticated user has permission to access response data
*
* @since 1.0
*/
public function can_view() {
return current_user_can( 'rcp_view_payments' );
}
}

View File

@@ -0,0 +1,196 @@
<?php
/**
* Membership Levels Route
*
* @package rcp-rest-api
* @copyright Copyright (c) 2018, Restrict Content Pro team
* @license GPL2+
* @since 1.1
*/
class RCP_REST_API_Membership_Level_Route_V1 extends RCP_REST_API_Route {
/**
* @var RCP_Levels $db
*/
protected $db;
/**
* Get things started
*
* @access public
* @since 1.1
* @return void
*/
public function init() {
$this->id = 'levels';
$this->db = new RCP_Levels();
}
/**
* Retrieve response data
*
* @param WP_REST_Request $request
*
* @access public
* @since 1.1
* @return RCP_REST_API_Level|WP_Error|WP_REST_Response
*/
public function get_data( WP_REST_Request $request ) {
if ( $request->get_param( 'id' ) ) {
// Get a single membership level.
$level = new RCP_REST_API_Level( $request->get_param( 'id' ) );
if ( empty( $level->id ) ) {
$level = new WP_Error( 'no_level', __( 'Invalid membership level', 'rcp-rest' ), array( 'status' => 404 ) );
}
return $level;
}
// Get multiple levels.
return new WP_REST_Response( $this->get_levels() );
}
/**
* Create a new membership level.
*
* @param WP_REST_Request $request
*
* @access public
* @since 1.1
* @return WP_REST_Response
*/
public function new_post_data( WP_REST_Request $request ) {
if ( ! $request->get_param( 'name' ) ) {
$response = new WP_Error( 'missing_name', __( 'No membership level name supplied', 'rcp-rest' ), array( 'status' => 500 ) );
}
if ( $request->get_param( 'trial_duration' ) && ( ! $request->get_param( 'price' ) || ! $request->get_param( 'duration' ) ) ) {
$response = new WP_Error( 'invalid_trial', __( 'Invalid trial configuration. A trial cannot be assigned to a free or lifetime membership.', 'rcp-rest' ), array( 'status' => 500 ) );
}
if ( empty( $response ) ) {
$level = new RCP_REST_API_Level();
$args = $level->sanitize_level_args( $request->get_params() );
$level_id = $this->db->insert( $args );
if ( $level_id ) {
$response = $level_id;
} else {
$response = new WP_Error( 'create_failed', __( 'Membership level creation failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
}
return new WP_REST_Response( $response );
}
/**
* Update an existing membership level.
*
* @param WP_REST_Request $request
*
* @access public
* @since 1.1
* @return WP_REST_Response
*/
public function update_post_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
if ( ! $request->get_param( 'id' ) ) {
$response = new WP_Error( 'missing_id', __( 'No membership level ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
$level = new RCP_REST_API_Level( $request->get_param( 'id' ) );
$fields = (array) $level;
$args = wp_parse_args( $request->get_params(), $fields );
$args = $level->sanitize_level_args( $args );
if ( $this->db->update( $request->get_param( 'id' ), $args ) ) {
$response = 1;
} else {
$response = new WP_Error( 'update_failed', __( 'Update Failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
return new WP_REST_Response( $response );
}
/**
* Delete a membership level.
*
* @param WP_REST_Request $request
*
* @access public
* @since 1.1
* @return WP_REST_Response
*/
public function delete_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
$this->db->remove( $request->get_param( 'id' ) );
return new WP_REST_Response( 1 );
}
/**
* Retrieve membership levels.
*
* @access private
* @since 1.1
* @return array
*/
private function get_levels() {
$args = wp_parse_args( $this->query_args, array(
'status' => 'all',
'limit' => null,
'orderby' => 'list_order'
) );
$levels = $this->db->get_levels( $args );
return $levels;
}
/**
* Determine if authenticated user has permission to access response data
*
* @access public
* @since 1.1
* @return bool
*/
public function can_view() {
return current_user_can( 'rcp_view_levels' );
}
/**
* Determine if authenticated user has permission to edit data
*
* @access public
* @since 1.1
* @return bool
*/
public function can_edit() {
return current_user_can( 'rcp_manage_levels' );
}
}

View File

@@ -0,0 +1,408 @@
<?php
class RCP_REST_API_Member_Route_V1 extends RCP_REST_API_Route {
private $user_fields;
/**
* Get things started
*
* @since 1.0
*/
public function init() {
$this->id = 'members';
// White list of user fields that can be altered and their associated query arg name
$this->user_fields = array(
'ID' => 'ID',
'login' => 'user_login',
'first_name' => 'first_name',
'last_name' => 'last_name',
'display_name' => 'display_name',
'email' => 'user_email',
'password' => 'user_pass'
);
}
/**
* Retrieve response data
*
* @since 1.0
*/
public function get_data( WP_REST_Request $request ) {
if( $request->get_param( 'id' ) ) {
$member = new RCP_REST_API_Member( $request->get_param( 'id' ) );
if( ! empty( $member->ID ) ) {
$member->setup();
} else {
$member = new WP_Error( 'no_member', 'Invalid member', array( 'status' => 404 ) );
}
/**
* Filters the response for getting data about a single member.
*
* @param RCP_REST_API_Member|WP_Error $member Member object or WP_Error if member cannot be found.
* @param int $id ID of the member to retrieve.
* @param array $query_args Query arguments.
*
* @since 1.0
*/
$member = apply_filters( 'rcp_rest_api_get_member_response', $member, $request->get_param( 'id' ), $this->query_args );
return $member;
}
/**
* Filters the response for getting member data.
*
* @param array $response Array of members.
* @param array $query_args Query arguments for filtering results.
*
* @since 1.1
*/
$response = apply_filters( 'rcp_rest_api_get_members_response', $this->get_members(), $this->query_args );
return new WP_REST_Response( $response );
}
/**
* Retrieve response data for create requests
*
* @since 1.0
*/
public function new_post_data( WP_REST_Request $request ) {
$args = array();
foreach( $request->get_params() as $key => $value ) {
if( array_key_exists( $key, $this->user_fields ) ) {
$args[ $this->user_fields[ $key ] ] = wp_slash( $value );
}
}
// Status is required.
if( ! $request->get_param( 'status' ) ) {
$response = new WP_Error( 'missing_status', __( 'No status supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
if( empty( $args['user_pass'] ) ) {
$args['user_pass'] = wp_generate_password( 20 );
}
$user_id = wp_insert_user( $args );
if( is_wp_error( $user_id ) ) {
return new WP_REST_Response( $user_id );
} else {
$member = new RCP_REST_API_Member( $user_id );
if( $request->has_param( 'subscription' ) ) {
$member->set_subscription( sanitize_text_field( $request->get_param( 'subscription' ) ) );
}
if( $request->has_param( 'status' ) ) {
$member->set_status( sanitize_text_field( $request->get_param( 'status' ) ) );
}
if( $request->has_param( 'expiration' ) ) {
$member->set_expiration_date( $member->sanitize_expiration( $request->get_param( 'expiration' ) ) );
} else {
// Calculate automatically.
$expiration = rcp_calculate_subscription_expiration( $member->get_subscription_id() );
$member->set_expiration_date( $expiration );
}
if( $request->has_param( 'recurring' ) ) {
$member->set_recurring( filter_var( $request->get_param( 'recurring' ), FILTER_VALIDATE_BOOLEAN ) );
}
if( $request->has_param( 'profile_id' ) ) {
$member->set_payment_profile_id( sanitize_text_field( $request->get_param( 'profile_id' ) ) );
}
if( $request->has_param( 'merchant_subscription_id' ) ) {
$member->set_merchant_subscription_id( sanitize_text_field( $request->get_param( 'merchant_subscription_id' ) ) );
}
/**
* Filters the response for successfully adding a new member.
*
* @param int $response Designates a successful response.
* @param RCP_REST_API_Member $member Member object. This is an extension of `RCP_Member`, which extends `WP_User`.
* @param array $body Request parameters.
*
* @since 1.1
*/
$response = apply_filters( 'rcp_rest_api_add_member_response', 1, $member, $request->get_params() );
}
return new WP_REST_Response( $response );
}
/**
* Retrieve response data for update requests
*
* @since 1.0
*/
public function update_post_data( WP_REST_Request $request ) {
if ( $request->has_param( 'id' ) ) {
$request->set_param( 'ID', $request->get_param( 'id' ) );
}
$args = array();
foreach( $request->get_params() as $key => $value ) {
if( array_key_exists( $key, $this->user_fields ) ) {
$args[ $this->user_fields[ $key ] ] = wp_slash( $value );
}
}
if( ! $request->get_param( 'ID' ) ) {
$response = new WP_Error( 'missing_id', __( 'No user ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
if( wp_update_user( $args ) ) {
$member = new RCP_REST_API_Member( $args['ID'] );
if( $request->get_param( 'renew' ) ) {
// Renew membership.
$recurring = $request->has_param( 'recurring' ) ? filter_var( $request->get_param( 'recurring' ), FILTER_VALIDATE_BOOLEAN ) : false;
$member->renew( $recurring );
} elseif ( $request->get_param( 'cancel' ) ) {
// Cancel membership.
if ( $member->can_cancel() ) {
$cancelled = $member->cancel_payment_profile();
if ( true !== $cancelled ) {
$response = new WP_Error( 'cancellation_failed', __( 'Cancellation Failed', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
} else {
$member->cancel();
}
} else {
// Change general membership data.
if( $request->has_param( 'status' ) ) {
$member->set_status( sanitize_text_field( $request->get_param( 'status' ) ) );
}
if( $request->has_param( 'subscription' ) ) {
$member->set_subscription( sanitize_text_field( $request->get_param( 'subscription' ) ) );
}
if( $request->has_param( 'expiration' ) ) {
$member->set_expiration_date( $member->sanitize_expiration( $request->get_param( 'expiration' ) ) );
}
if( $request->has_param( 'recurring' ) ) {
$member->set_recurring( filter_var( $request->get_param( 'recurring' ), FILTER_VALIDATE_BOOLEAN ) );
}
if( $request->has_param( 'profile_id' ) ) {
$member->set_payment_profile_id( sanitize_text_field( $request->get_param( 'profile_id' ) ) );
}
if( $request->has_param( 'merchant_subscription_id' ) ) {
$member->set_merchant_subscription_id( sanitize_text_field( $request->get_param( 'merchant_subscription_id' ) ) );
}
}
/**
* Filters the response for successfully updating an existing member.
*
* @param int $response Designates a successful response.
* @param RCP_REST_API_Member $member Member object. This is an extension of `RCP_Member`, which extends `WP_User`.
* @param array $body Request parameters.
*
* @since 1.1
*/
$response = apply_filters( 'rcp_rest_api_update_member_response', 1, $member, $request->get_params() );
} else {
$response = new WP_Error( 'update_failed', __( 'Update Failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
return new WP_REST_Response( $response );
}
/**
* Retrieve response data for delete requests
*
* @since 1.0
*/
public function delete_data( WP_REST_Request $request ) {
if ( $request->has_param( 'id' ) ) {
$request->set_param( 'ID', $request->get_param( 'id' ) );
}
if( ! $request->get_param( 'ID' ) ) {
$response = new WP_Error( 'missing_id', __( 'No user ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
if( ! function_exists( 'wp_delete_user' ) ) {
require_once ABSPATH . 'wp-admin/includes/user.php';
}
if( wp_delete_user( $request->get_param( 'ID' ) ) ) {
$response = 1;
} else {
$response = new WP_Error( 'delete_failed', __( 'Delete Failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
return new WP_REST_Response( $response );
}
/**
* Retrieve members data
*
* @since 1.0
*/
private function get_members() {
$request = wp_parse_args( $this->query_args, array(
'number' => 20,
'orderby' => 'ID',
'order' => 'DESC',
'offset' => 0,
's' => '',
'status' => '',
'subscription' => 0,
'recurring' => '',
) );
$members = array();
$args = array(
'offset' => $request['offset'],
'number' => $request['number'],
'orderby' => $request['orderby'],
'order' => $request['order'],
'meta_query' => array()
);
if( ! empty( $request['status'] ) ) {
$args['meta_query'][] = array(
'key' => 'rcp_status',
'value' => $request['status']
);
}
if( ! empty( $request['subscription'] ) ) {
$args['meta_query'][] = array(
'key' => 'rcp_subscription_level',
'value' => $request['subscription']
);
}
if( ! empty( $request['recurring'] ) ) {
if( 'no' === $request['recurring'] ) {
// find non recurring users
$args['meta_query'][] = array(
'key' => 'rcp_recurring',
'compare' => 'NOT EXISTS'
);
} else {
// find recurring users
$args['meta_query'][] = array(
'key' => 'rcp_recurring',
'value' => 'yes'
);
}
}
if( ! empty( $request['s'] ) ) {
$args['search'] = sanitize_text_field( $request['s'] );
}
$members = get_users( $args );
if( ! empty( $members ) ) {
foreach( $members as $key => $member ) {
$members[ $key ] = new RCP_REST_API_Member( $member->ID );
$members[ $key ]->setup();
}
}
return $members;
}
/**
* Determine if authenticated user has permission to access response data
*
* @since 1.0
*/
public function can_view() {
return current_user_can( 'rcp_view_members' );
}
/**
* Determine if authenticated user has permission to edit data
*
* @since 1.0
*/
public function can_edit() {
return current_user_can( 'rcp_manage_members' );
}
}

View File

@@ -0,0 +1,407 @@
<?php
/**
* Membership Route
*
* @package rcp
* @copyright Copyright (c) 2019, Restrict Content Pro team
* @license GPL2+
* @since 1.1
*/
class RCP_REST_API_Membership_Route_V1 extends RCP_REST_API_Route {
/**
* Array of whitelisted membership fields.
*
* @var array
*/
private $membership_fields;
/**
* Get things started
*
* @since 1.0
*/
public function init() {
$this->id = 'memberships';
// Whitelist of membership fields that can be altered and their associated query arg name.
$this->membership_fields = array(
'id',
'customer_id',
'object_id',
'object_type',
'currency',
'initial_amount',
'recurring_amount',
'created_date',
'trial_end_date',
'renewed_date',
'cancellation_date',
'expiration_date',
'payment_plan_completed_date',
'auto_renew',
'times_billed',
'maximum_renewals',
'status',
'gateway_customer_id',
'gateway_subscription_id',
'gateway',
'signup_method',
'subscription_key',
'notes',
'upgraded_from',
'disabled'
);
}
/**
* Register our routes
*
* @since 1.0
*/
public function register_v1_routes() {
parent::register_v1_routes();
// Renew a membership
register_rest_route( 'rcp/v1', '/' . $this->id . '/(?P<id>\d+)/renew', array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'renew_membership' ),
'permission_callback' => array( $this, 'can_edit' ),
'args' => array(
'id' => array(
'required' => true,
'sanitize_callback' => function ( $param, $request, $key ) {
return absint( $param );
}
),
'recurring' => array(
'sanitize_callback' => function ( $param, $request, $key ) {
return filter_var( $param, FILTER_VALIDATE_BOOLEAN );
}
),
'status' => array(
'default' => 'active',
'validate_callback' => function ( $param, $request, $key ) {
$statuses = array( 'pending', 'active', 'cancelled', 'expired' );
return in_array( $param, $statuses );
},
'sanitize_callback' => function ( $param, $request, $key ) {
return sanitize_text_field( strtolower( $param ) );
}
),
'expiration' => array(
'validate_callback' => function ( $param, $request, $key ) {
return false !== strtotime( $param );
},
'sanitize_callback' => function ( $param, $request, $key ) {
return date( 'Y-m-d H:i:s', strtotime( $param ) );
}
),
)
) );
// Cancel a membership
register_rest_route( 'rcp/v1', '/' . $this->id . '/(?P<id>\d+)/cancel', array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'cancel_membership' ),
'permission_callback' => array( $this, 'can_edit' ),
'args' => array(
'id' => array(
'required' => true,
'sanitize_callback' => function ( $param, $request, $key ) {
return absint( $param );
}
)
)
) );
}
/**
* @param RCP_Membership $membership
*
* @since 1.1
* @return object
*/
private function format_membership( RCP_Membership $membership ) {
$data = new stdClass();
$data->id = $membership->get_id();
$data->customer_id = $membership->get_customer_id();
$data->object_id = $membership->get_object_id();
$data->object_type = $membership->get_object_type();
$data->currency = $membership->get_currency();
$data->initial_amount = $membership->get_initial_amount();
$data->recurring_amount = $membership->get_recurring_amount();
$data->created_date = $membership->get_created_date( false );
$data->trial_end_date = $membership->get_trial_end_date();
$data->renewed_date = $membership->get_renewed_date( false );
$data->cancellation_date = $membership->get_cancellation_date( false );
$data->expiration_date = $membership->get_expiration_date( false );
$data->payment_plan_completed_date = $membership->get_payment_plan_completed_date();
$data->auto_renew = $membership->is_recurring();
$data->times_billed = $membership->get_times_billed();
$data->maximum_renewals = $membership->get_maximum_renewals();
$data->status = $membership->get_status();
$data->gateway_customer_id = $membership->get_gateway_customer_id();
$data->gateway_subscription_id = $membership->get_gateway_subscription_id();
$data->gateway = $membership->get_gateway();
$data->signup_method = $membership->get_signup_method();
$data->subscription_key = $membership->get_subscription_key();
$data->notes = $membership->get_notes();
$data->upgraded_from = $membership->get_upgraded_from();
$data->disabled = $membership->is_disabled();
return $data;
}
/**
* Get data
*
* If the `id` parameter is provided then information about a single membership is retrieved.
* Otherwise, an array of membership results is returned.
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response
*/
public function get_data( WP_REST_Request $request ) {
if ( $request->get_param( 'id' ) ) {
/**
* Get single membership by ID.
*/
$membership = rcp_get_membership( absint( $request->get_param( 'id' ) ) );
if ( empty( $membership ) ) {
return new WP_REST_Response( new WP_Error( 'invalid_membership', __( 'Invalid membership', 'rcp-rest' ), array( 'status' => 404 ) ), 404 );
}
return new WP_REST_Response( $this->format_membership( $membership ) );
} else {
/**
* Get array of memberships.
*/
$memberships = rcp_get_memberships( $this->query_args );
if ( ! empty( $memberships ) ) {
$response = array_map( array( $this, 'format_membership' ), $memberships );
} else {
$response = new WP_Error( 'no_memberships', __( 'No memberships found', 'rcp-rest-api' ), array( 'status' => 404 ) );
}
return new WP_REST_Response( $response );
}
}
/**
* Renew a membership
*
* @param WP_REST_Request $request
*
* @since 1.2
* @return WP_REST_Response Updated membership object on success.
*/
public function renew_membership( WP_REST_Request $request ) {
$membership = rcp_get_membership( $request->get_param( 'id' ) );
if ( ! $membership instanceof RCP_Membership ) {
return new WP_REST_Response( new WP_Error( 'invalid_membership', __( 'Invalid membership', 'rcp-rest' ), array( 'status' => 404 ) ), 404 );
}
$recurring = $request->has_param( 'recurring' ) ? $request->get_param( 'recurring' ) : $membership->is_recurring();
$status = $request->get_param( 'status' );
$expiration = $request->get_param( 'expiration' );
$result = $membership->renew( $recurring, $status, $expiration );
if ( ! $result ) {
return new WP_REST_Response( new WP_Error( 'membership_renewal_failed', __( 'Renewal failed', 'rcp-rest' ), array( 'status' => 400 ) ), 400 );
}
return new WP_REST_Response( $this->format_membership( $membership ) );
}
/**
* Cancel a membership
*
* @param WP_REST_Request $request
*
* @since 1.2
* @return WP_REST_Response Updated membership object on success.
*/
public function cancel_membership( WP_REST_Request $request ) {
$membership = rcp_get_membership( $request->get_param( 'id' ) );
if ( ! $membership instanceof RCP_Membership ) {
return new WP_REST_Response( new WP_Error( 'invalid_membership', __( 'Invalid membership', 'rcp-rest' ), array( 'status' => 404 ) ), 404 );
}
if ( $membership->can_cancel() ) {
// Cancel recurring billing if possible.
$cancelled = $membership->cancel_payment_profile();
if ( is_wp_error( $cancelled ) ) {
return new WP_REST_Response( new WP_Error( $cancelled->get_error_code(), $cancelled->get_error_message(), array( 'status' => 400 ) ), 400 );
}
} else {
// Just changes the membership status.
$membership->cancel();
}
return new WP_REST_Response( $this->format_membership( $membership ) );
}
/**
* Add a new membership
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response ID of the newly created membership on success.
*/
public function new_post_data( WP_REST_Request $request ) {
$args = array();
foreach ( $request->get_params() as $key => $value ) {
if ( in_array( $key, $this->membership_fields ) ) {
$args[$key] = wp_slash( $value );
}
}
// Customer ID is required.
if ( ! $request->get_param( 'customer_id' ) ) {
$response = new WP_Error( 'missing_customer_id', __( 'No customer ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
// Object ID is required.
if ( ! $request->get_param( 'object_id' ) ) {
$response = new WP_Error( 'missing_object_id', __( 'No object ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
$membership_id = rcp_add_membership( $args );
if ( empty( $membership_id ) ) {
return new WP_REST_Response( new WP_Error( 'create_failed', __( 'Failed to add new membership', 'rcp-rest' ), array( 'status' => 500 ) ) );
}
return new WP_REST_Response( absint( $membership_id ) );
}
/**
* Update an existing membership
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response
*/
public function update_post_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
if ( ! $request->get_param( 'id' ) ) {
$response = new WP_Error( 'missing_id', __( 'No membership ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
$args = array();
foreach ( $request->get_params() as $key => $value ) {
if ( in_array( $key, $this->membership_fields ) ) {
$args[ $key ] = wp_slash( $value );
}
}
$updated = rcp_update_membership( absint( $request->get_param( 'id' ) ), $args );
if ( $updated ) {
$response = 1;
} else {
$response = new WP_Error( 'update_failed', __( 'Update Failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
return new WP_REST_Response( $response );
}
/**
* Delete a membership
*
* @param WP_REST_Request $request
*
* @since 1.1
* @return WP_REST_Response
*/
public function delete_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
$membership = rcp_get_membership( absint( $request->get_param( 'id' ) ) );
if ( empty( $membership ) ) {
return new WP_REST_Response( new WP_Error( 'invalid_membership', __( 'Invalid membership', 'rcp-rest' ), array( 'status' => 404 ) ) );
}
$membership->disable();
return new WP_REST_Response( 1 );
}
/**
* Determine if authenticated user has permission to access response data
*
* @since 1.1
* @return bool
*/
public function can_view() {
return current_user_can( 'rcp_view_members' );
}
/**
* Determine if authenticated user has permission to edit data
*
* @since 1.1
* @return bool
*/
public function can_edit() {
return current_user_can( 'rcp_manage_members' );
}
}

View File

@@ -0,0 +1,197 @@
<?php
class RCP_REST_API_Payment_Route_V1 extends RCP_REST_API_Route {
protected $db;
/**
* Get things started
*
* @since 1.0
*/
public function init() {
$this->id = 'payments';
$this->db = new RCP_Payments;
}
/**
* Retrieve response data
*
* @since 1.0
*/
public function get_data( WP_REST_Request $request ) {
if( $request->get_param( 'id' ) ) {
$payment = new RCP_REST_API_Payment( $request->get_param( 'id' ) );
if( ! empty( $payment->id ) ) {
$payment->setup();
} else {
$payment = new WP_Error( 'no_payment', __( 'Invalid payment', 'rcp-rest' ), array( 'status' => 404 ) );
}
return $payment;
}
return new WP_REST_Response( $this->get_payments() );
}
/**
* Retrieve response data for create requests
*
* @since 1.0
*/
public function new_post_data( WP_REST_Request $request ) {
if( ! $request->has_param( 'amount' ) ) {
$response = new WP_Error( 'missing_amount', __( 'No payment amount supplied', 'rcp-rest' ), array( 'status' => 500 ) );
}
if( ! $request->get_param( 'subscription' ) ) {
$response = new WP_Error( 'missing_subscription', __( 'No subscription name supplied', 'rcp-rest' ), array( 'status' => 500 ) );
}
if( ! $request->get_param( 'user_id' ) ) {
$response = new WP_Error( 'missing_user_id', __( 'No user ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
}
if( empty( $response ) ) {
$payment = new RCP_REST_API_Payment;
$args = $payment->sanitize_payment_args( $request->get_params() );
$payment_id = $this->db->insert( $args );
if( $payment_id ) {
$response = 1;
} else {
$response = new WP_Error( 'create_failed', __( 'Payment creation failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
}
return new WP_REST_Response( $response );
}
/**
* Retrieve response data for update requests
*
* @since 1.0
*/
public function update_post_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
if( ! $request->get_param( 'id' ) ) {
$response = new WP_Error( 'missing_id', __( 'No payment ID supplied', 'rcp-rest' ), array( 'status' => 500 ) );
return new WP_REST_Response( $response );
}
$payment = new RCP_REST_API_Payment( $request->get_param( 'id' ) );
$fields = (array) $payment;
$args = wp_parse_args( $request->get_params(), $fields );
$args = $payment->sanitize_payment_args( $args );
if( $this->db->update( $request->get_param( 'id' ), $args ) ) {
$response = 1;
} else {
$response = new WP_Error( 'update_failed', __( 'Update Failed', 'rcp-rest' ), array( 'status' => 500 ) );
}
return new WP_REST_Response( $response );
}
/**
* Retrieve response data for delete requests
*
* @since 1.0
*/
public function delete_data( WP_REST_Request $request ) {
if ( $request->has_param( 'ID' ) ) {
$request->set_param( 'id', $request->get_param( 'ID' ) );
}
$this->db->delete( $request->get_param( 'id' ) );
return new WP_REST_Response( 1 );
}
/**
* Retrieve payment data
*
* @since 1.0
*/
private function get_payments() {
$args = wp_parse_args( $this->query_args, array(
'number' => 20,
'orderby' => 'id',
'order' => 'DESC',
'offset' => 0,
's' => '',
'status' => '',
'date' => '',
'fields' => '*',
'subscription' => 0,
) );
if( ! empty( $this->query_args['member'] ) ) {
$args['user_id'] = absint( $this->query_args['member'] );
}
$payments = $this->db->get_payments( $args );
if( ! empty( $payments ) ) {
foreach( $payments as $key => $payment ) {
$payments[ $key ] = new RCP_REST_API_Payment( $payment->id );
}
}
return $payments;
}
/**
* Determine if authenticated user has permission to access response data
*
* @since 1.0
*/
public function can_view() {
return current_user_can( 'rcp_view_payments' );
}
/**
* Determine if authenticated user has permission to edit data
*
* @since 1.0
*/
public function can_edit() {
return current_user_can( 'rcp_manage_payments' );
}
}

View File

@@ -0,0 +1 @@
<?php // Silence is golden.

View File

@@ -0,0 +1,252 @@
<?php
/*
Set up admin interface elements.
Written by Chris Jean for iThemes.com
Version 1.2.2
Version History
1.0.0 - 2013-09-19 - Chris Jean
Split off from the old Ithemes_Updater_Init class.
1.1.0 - 2013-10-02 - Chris Jean
Added support for themes through the filter_plugins_api function (since themes don't have a "View version *** details" feature.
1.2.0 - 2013-10-23 - Chris Jean
Changed how the licensing page is registered for multisite. It now will only load on multisite sites if the user is a super user (network admin).
Removed the code that handled the setting to show or hide the licensing page on multisite sites.
1.2.1 - 2013-10-25 - Chris Jean
Added "License" links to Network Admin Plugins and Themes pages.
1.2.2 - 2014-10-23 - Chris Jean
Updated code formating to WordPress coding standards.
*/
class Ithemes_Updater_Admin {
private $page_name = 'ithemes-licensing';
private $package_details = false;
private $registration_link = false;
private $page_ref;
public function __construct() {
require_once( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
if ( ! is_multisite() || is_super_admin() ) {
add_action( 'admin_menu', array( $this, 'add_admin_pages' ) );
}
add_action( 'network_admin_menu', array( $this, 'add_network_admin_pages' ) );
add_action( 'admin_head-plugins.php', array( $this, 'show_activation_message' ) );
add_action( 'admin_head-themes.php', array( $this, 'show_activation_message' ) );
add_action( 'deactivated_plugin', array( $this, 'clear_activation_package' ) );
add_filter( 'upgrader_pre_install', array( $this, 'filter_upgrader_pre_install' ) );
add_filter( 'upgrader_post_install', array( $this, 'filter_upgrader_post_install' ), 10, 3 );
add_filter( 'plugins_api', array( $this, 'filter_plugins_api' ), 10, 3 );
if ( ! is_multisite() || is_super_admin() ) {
add_filter( 'plugin_action_links', array( $this, 'filter_plugin_action_links' ), 10, 4 );
add_filter( 'theme_action_links', array( $this, 'filter_theme_action_links' ), 10, 2 );
}
add_filter( 'network_admin_plugin_action_links', array( $this, 'filter_plugin_action_links' ), 10, 4 );
add_filter( 'network_admin_theme_action_links', array( $this, 'filter_theme_action_links' ), 10, 2 );
}
public function filter_plugins_api( $value, $action, $args ) {
$options = $GLOBALS['ithemes-updater-settings']->get_options();
if ( ! isset( $args->slug ) ) {
return $value;
}
foreach ( (array) $options['update_plugins'] as $path => $data ) {
if ( $data->slug == $args->slug ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
return Ithemes_Updater_Information::get_plugin_information( $path );
}
}
foreach ( (array) $options['update_themes'] as $path => $data ) {
if ( $path == $args->slug ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
return Ithemes_Updater_Information::get_theme_information( $path );
}
}
$dir = WP_PLUGIN_DIR . '/' . $args->slug;
$dh = @opendir( $dir );
if ( ! $dh ) {
return $value;
}
while ( false !== ( $file = readdir( $dh ) ) ) {
if ( ! is_file( "$dir/$file" ) ) {
continue;
}
if ( '.php' !== substr( $file, -4 ) ) {
continue;
}
$plugin_data = get_plugin_data( "$dir/$file", false, false );
if ( ! empty ( $plugin_data['Name'] ) ) {
$plugin_file = basename( $file );
}
}
closedir( $dh );
if ( empty( $plugin_file ) ) {
return $value;
}
require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
$information = Ithemes_Updater_Information::get_plugin_information( "{$args->slug}/$plugin_file" );
if ( false !== $information ) {
return $information;
}
return $value;
}
public function filter_upgrader_pre_install( $value ) {
$this->set_package_details();
return $value;
}
public function filter_upgrader_post_install( $value, $hook_extra, $result ) {
$options = $GLOBALS['ithemes-updater-settings']->queue_flush();
return $value;
}
public function clear_activation_package( $deactivated_path ) {
$packages = $GLOBALS['ithemes-updater-settings']->get_packages();
$options = $GLOBALS['ithemes-updater-settings']->get_options();
$deactivated_path = WP_PLUGIN_DIR . "/$deactivated_path";
foreach ( $packages as $package => $paths ) {
if ( ! in_array( $deactivated_path, $paths ) || ( count( $paths ) > 1 ) ) {
continue;
}
$index = array_search( $package, $options['packages'] );
if ( false === $index ) {
return;
}
unset( $options['packages'][$index] );
$GLOBALS['ithemes-updater-settings']->update_options( $options );
return;
}
}
public function show_activation_message() {
$new_packages = $GLOBALS['ithemes-updater-settings']->get_new_packages();
if ( empty( $new_packages ) ) {
return;
}
natcasesort( $new_packages );
require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
$names = array();
foreach ( $new_packages as $package ) {
$names = Ithemes_Updater_Functions::get_package_name( $package );
}
if ( is_multisite() && is_network_admin() ) {
$url = network_admin_url( 'settings.php' ) . "?page={$this->page_name}";
} else {
$url = admin_url( 'options-general.php' ) . "?page={$this->page_name}";
}
echo '<div class="updated fade"><p>' . wp_sprintf( __( 'To receive automatic updates for %l, use the <a href="%s">iThemes Licensing</a> page found in the Settings menu.', 'rcp-rest' ), $names, $url ) . '</p></div>';
$GLOBALS['ithemes-updater-settings']->update_packages();
}
public function add_admin_pages() {
$this->page_ref = add_options_page( __( 'iThemes Licensing', 'rcp-rest' ), __( 'iThemes Licensing', 'rcp-rest' ), 'manage_options', $this->page_name, array( $this, 'settings_index' ) );
add_action( "load-{$this->page_ref}", array( $this, 'load_settings_page' ) );
}
public function add_network_admin_pages() {
$this->page_ref = add_submenu_page( 'settings.php', __( 'iThemes Licensing', 'rcp-rest' ), __( 'iThemes Licensing', 'rcp-rest' ), 'manage_options', $this->page_name, array( $this, 'settings_index' ) );
add_action( "load-{$this->page_ref}", array( $this, 'load_settings_page' ) );
}
public function load_settings_page() {
require( $GLOBALS['ithemes_updater_path'] . '/settings-page.php' );
}
public function settings_index() {
do_action( 'ithemes_updater_settings_page_index' );
}
private function set_package_details() {
if ( false !== $this->package_details ) {
return;
}
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
$this->package_details = Ithemes_Updater_Packages::get_local_details();
}
private function set_registration_link() {
if ( false !== $this->registration_link ) {
return;
}
$url = admin_url( 'options-general.php' ) . "?page={$this->page_name}";
$this->registration_link = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $url, __( 'Manage iThemes product licenses to receive automatic upgrade support', 'rcp-rest' ), __( 'License', 'rcp-rest' ) );
}
public function filter_plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
$this->set_package_details();
$this->set_registration_link();
if ( isset( $this->package_details[$plugin_file] ) && is_array( $actions ) ) {
$actions[] = $this->registration_link;
}
return $actions;
}
public function filter_theme_action_links( $actions, $theme ) {
$this->set_package_details();
$this->set_registration_link();
if ( is_object( $theme ) ) {
$path = basename( $theme->get_stylesheet_directory() ) . '/style.css';
} else if ( is_array( $theme ) && isset( $theme['Stylesheet Dir'] ) ) {
$path = $theme['Stylesheet Dir'] . '/style.css';
} else {
$path = '';
}
if ( isset( $this->package_details[$path] ) && is_array( $actions ) ) {
$actions[] = $this->registration_link;
}
return $actions;
}
}
new Ithemes_Updater_Admin();

View File

@@ -0,0 +1,347 @@
<?php
/*
Provides an easy to use interface for communicating with the iThemes updater server.
Written by Chris Jean for iThemes.com
Version 1.1.1
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-09-19 - Chris Jean
Updated requires to not use dirname().
Updated ithemes-updater-object to ithemes-updater-settings.
1.1.0 - 2013-10-02 - Chris Jean
Added get_package_changelog().
1.1.1 - 2014-11-13 - Chris Jean
Improved caching.
Updated code to meet WordPress coding standards.
*/
class Ithemes_Updater_API {
public static function activate_package( $username, $password, $packages ) {
return self::get_response( 'activate_package', compact( 'username', 'password', 'packages' ), false );
}
public static function deactivate_package( $username, $password, $packages ) {
return self::get_response( 'deactivate_package', compact( 'username', 'password', 'packages' ), false );
}
public static function get_licensed_site_url() {
$packages = array();
return self::get_response( 'get_licensed_site_url', compact( 'packages' ), false );
}
public static function set_licensed_site_url( $username, $password, $site_url ) {
$packages = array();
return self::get_response( 'set_licensed_site_url', compact( 'username', 'password', 'site_url', 'packages' ), false );
}
public static function get_package_details( $cache = true ) {
$packages = array();
return self::get_response( 'get_package_details', compact( 'packages' ), $cache );
}
public static function get_package_changelog( $package, $cur_version = false ) {
$response = wp_remote_get( 'http://api.ithemes.com/product/changelog?package=' . urlencode( $package ) );
if ( is_wp_error( $response ) ) {
return $response;
}
if ( ! isset( $response['body'] ) ) {
return new WP_Error( 'ithemes-updater-changelog-bad-wp-remote-get-response', __( 'Unrecognized response from <code>wp_remote_get</code>.', 'rcp-rest' ) );
}
if ( isset( $response['response']['code'] ) && ( '200' != $response['response']['code'] ) ) {
return new WP_Error( 'ithemes-updater-wp-remote-get-error-' . $response['response']['code'], $response['response']['message'] );
}
$body = $response['body'];
if ( '{' === substr( $body, 0, 1 ) ) {
$error = json_decode( $body, true );
if ( is_array( $error ) && isset( $error['error'] ) && is_array( $error['error'] ) && isset( $error['error']['type'] ) && isset( $error['error']['message'] ) ) {
return new WP_Error( 'ithemes-updater-json-decode-error-' . $error['error']['type'], $error['error']['message'] );
} else {
return new WP_Error( 'ithemes-updater-changelog-bad-json-decode-result', __( 'Unrecognized response from iThemes API server.', 'rcp-rest' ) );
}
}
$versions = array();
$version = false;
$depth = 0;
$lines = preg_split( '/[\n\r]+/', $body );
foreach ( $lines as $line ) {
if ( preg_match( '/^\d/', $line ) ) {
if ( ! empty( $version ) && ( $depth > 0 ) ) {
while ( $depth-- > 0 ) {
$versions[$version] .= "</ul>\n";
}
}
$depth = 0;
$parts = preg_split( '/\s+-\s+/', $line );
$version = $parts[0];
if ( version_compare( $version, $cur_version, '<=' ) ) {
$version = '';
continue;
}
$versions[$version] = '';
continue;
} else if ( preg_match( '/^\S/', $line ) ) {
$version = '';
continue;
} else if ( empty( $version ) ) {
continue;
}
$line = str_replace( ' ', "\t", $line );
$line = str_replace( "\t", '', $line, $count );
$line = preg_replace( '/^\s+/', '', $line );
if ( empty( $line ) ) {
continue;
}
$details = '';
if ( $count > $depth ) {
$details .= "<ul>\n";
$depth++;
} else if ( $count < $depth ) {
$details .= "</ul>\n";
$depth--;
}
$details .= "<li>$line</li>\n";
$versions[$version] .= $details;
}
if ( ! empty( $version ) && ( $depth > 0 ) ) {
while ( $depth-- > 0 ) {
$versions[$version] .= "</ul>\n";
}
}
uksort( $versions, 'version_compare' );
$versions = array_reverse( $versions );
$changelog = '';
foreach ( $versions as $version => $details ) {
$changelog .= "<h4>$version</h4>\n$details\n";
}
$changelog = preg_replace( '/\s+$/', '', $changelog );
return $changelog;
}
public static function get_response( $action, $args, $cache ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/server.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/updates.php' );
if ( isset( $args['packages'] ) ) {
$args['packages'] = self::get_request_package_details( $args['packages'] );
}
$response = false;
$source = '';
$cached = true;
$md5 = substr( md5( serialize( $args ) ), 0, 5 );
$time = time();
$cache_var = "it-updater-$action-$md5";
if ( $cache ) {
if ( isset( $GLOBALS[$cache_var] ) ) {
$response = $GLOBALS[$cache_var];
$source = 'GLOBALS';
} else if ( false !== ( $transient = get_site_transient( $cache_var ) ) ) {
$response = $transient;
$source = 'transient';
}
}
if ( false === $response ) {
$response = call_user_func_array( array( 'Ithemes_Updater_Server', $action ), $args );
$source = 'server';
if ( is_wp_error( $response ) ) {
return $response;
}
$cache_length = 86400 * $GLOBALS['ithemes-updater-settings']->get_option( 'timeout-multiplier' );
set_site_transient( $cache_var, $response, $cache_length );
$cached = false;
}
Ithemes_Updater_Updates::process_server_response( $response, $cached );
$GLOBALS[$cache_var] = $response;
return $response;
}
private static function get_request_package_details( $desired_packages = array() ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
$all_packages = Ithemes_Updater_Packages::get_local_details();
reset( $desired_packages );
if ( empty( $desired_packages ) ) {
$desired_packages = $all_packages;
} else if ( is_numeric( key( $desired_packages ) ) ) {
$new_desired_packages = array();
foreach ( $all_packages as $path => $details ) {
foreach ( $desired_packages as $package ) {
if ( $package != $details['package'] ) {
continue;
}
$new_desired_packages[$path] = $details;
break;
}
}
$desired_packages = $new_desired_packages;
}
$packages = array();
$keys = Ithemes_Updater_Keys::get();
$package_slugs = array();
foreach ( $desired_packages as $data ) {
$package_slugs[] = $data['package'];
}
$legacy_keys = Ithemes_Updater_Keys::get_legacy( $package_slugs );
$active_themes = array(
'stylesheet' => get_stylesheet_directory(),
'template' => get_template_directory(),
);
$active_themes = array_unique( $active_themes );
foreach ( $active_themes as $index => $path ) {
$active_themes[$index] = basename( $path );
}
foreach ( $desired_packages as $path => $data ) {
$key = ( isset( $keys[$data['package']] ) ) ? $keys[$data['package']] : '';
$package = array(
'ver' => $data['installed'],
'key' => $key,
);
if ( ! empty( $legacy_keys[$data['package']] ) ) {
$package['old-key'] = $legacy_keys[$data['package']];
}
if ( 'plugins' == $data['type'] ) {
$package['active'] = (int) is_plugin_active( $path );
} else {
$dir = dirname( $path );
$package['active'] = (int) in_array( $dir, $active_themes );
if ( $package['active'] && ( count( $active_themes ) > 1 ) ) {
if ( $dir == $active_themes['stylesheet'] ) {
$package['child-theme'] = 1;
} else {
$package['parent-theme'] = 1;
}
}
}
$package_key = $data['package'];
$counter = 0;
while ( isset( $packages[$package_key] ) ) {
$package_key = "{$data['package']} ||| " . ++$counter;
}
$packages[$package_key] = $package;
}
if ( ! empty( $legacy_keys ) ) {
Ithemes_Updater_Keys::delete_legacy( array_keys( $legacy_keys ) );
}
return $packages;
}
public static function get_error_explanation( $error, $package = '' ) {
$code = $error->get_error_code();
$package_name = Ithemes_Updater_Functions::get_package_name( $package );
$message = '';
switch( $code ) {
case 'ITXAPI_Updater_Bad_Login':
$message = __( 'Incorrect password. Please make sure that you are supplying your iThemes membership username and password details.', 'rcp-rest' );
break;
case 'ITXAPI_Updater_Username_Unknown':
case 'ITXAPI_Updater_Username_Invalid':
$message = __( 'Invalid username. Please make sure that you are supplying your iThemes membership username and password details.', 'rcp-rest' );
break;
case 'ITXAPI_Product_Package_Unknown':
$message = sprintf( __( 'The licensing server reports that the %1$s (%2$s) product is unknown. Please contact support for assistance.', 'rcp-rest' ), $package_name, $package );
break;
case 'ITXAPI_Updater_Too_Many_Sites':
$message = sprintf( __( '%1$s could not be licensed since the membership account is out of available licenses for this product. You can unlicense the product on other sites or upgrade your membership to one with a higher number of licenses in order to increase the amount of available licenses.', 'rcp-rest' ), $package_name );
break;
case 'ITXAPI_License_Key_Generate_Failed':
$message = sprintf( __( '%s could not be licensed due to an internal error. Please try to license %s again at a later time. If this problem continues, please contact iThemes support.', 'rcp-rest' ), $package_name );
break;
}
if ( empty( $message ) ) {
if ( ! empty( $package ) )
$message = sprintf( __( 'An unknown error relating to the %1$s product occurred. Please contact iThemes support. Error details: %2$s', 'rcp-rest' ), $package_name, $error->get_error_message() . " ($code)" );
else
$message = sprintf( __( 'An unknown error occurred. Please contact iThemes support. Error details: %s', 'rcp-rest' ), $error->get_error_message() . " ($code)" );
}
return $message;
}
}

View File

@@ -0,0 +1,40 @@
# iThemes Updater API #
This document lists the different API features of the iThemes Updater system.
Note: This document is in [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown) format.
## Defines ##
The entire updater system can be disabled by creating a define named ITHEMES_UPDATER_DISABLE with a truthy value. For example, the following could be added to the wp-config.php file to disable the updater system:
define( 'ITHEMES_UPDATER_DISABLE', true );
## Query Strings ##
The updater system has built in refresh intervals:
* One minute - When on the Dashboard > Updates or Settings > iThemes Licensing pages, the data will refresh in one minute intervals. This means that once the data is a minute or older, it will be refreshed.
* One hour - When on the Plugins > Installed Plugins or Appearance > Themes pages, the data will refresh in one hour intervals.
* Twelve hours - On all other pages the data will refresh in twelve hour intervals.
Note that data is only refreshed when in the WordPress Dashboard (wp-admin). This prevents adding additional load time when people are browsing the site.
You can force a manual refresh of the data by modifying the URL of the page to include a non-empty query variable named ithemes-updater-force-refresh. This can be helpful if you think that the updater is having a problem and isn't properly refreshing itself.
For example, if you are on an admin page with a URL of http://example.com/wp-admin/plugins.php, you can force a refresh by changing the URL to the following:
http://example.com/wp-admin/plugins.php?ithemes-updater-force-refresh=1
Note that forcing a refresh only works on the WordPress Dashboard and not on the site front-end. In addition, only users with the manage_options capability have the ability to force a refresh. By default, the only users with this capability are the ones in the Administrator role. These restrictions are to help prevent a non-authorized user from consuming server resources by forcing numerous refreshes.
Some of our releases have versions with four digits, such as 3.1.1.1. Releases with a four-digit version are quick releases and are meant for rapid bug fix releases (typically in response to a specific support request). If the version on the site is only different by this last digit in a four-digit version (such as currently running 3.1.1.1 when 3.1.1.4 is available), then the updater will not show an update as available. You can force the updater to make such releases available by modifying an admin page URL to include a non-empty query variable named ithemes-updater-force-minor-update.
For example, if you are on an admin page with a URL of http://example.com/wp-admin/plugins.php, you can force quick bug fix releases to be avaiable by changing the URL to the following:
http://example.com/wp-admin/plugins.php?ithemes-updater-force-minor-update=1
Note: The updater now supports a query variable named ithemes-updater-force-quick-release-update. It has the same functionality as ithemes-updater-force-minor-update.

View File

@@ -0,0 +1 @@
<?php // Silence is golden.

View File

@@ -0,0 +1,58 @@
##
## CA Root Certificate for api.ithemes.com and s3.amazonaws.com
##
## Certificate data from Mozilla as of: Sat Dec 29 20:03:40 2012
##
# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.87 $ $Date: 2012/12/29 16:32:45 $
Go Daddy Class 2 CA
===================
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
vZ8=
-----END CERTIFICATE-----
VeriSign Class 3 Public Primary Certification Authority - G5
============================================================
-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
-----END CERTIFICATE-----

View File

@@ -0,0 +1,143 @@
<?php
//-----------------------------------------------------------------------------
class iThemes_Credentials
{
//-----------------------------------------------------------------------------
protected $hash = 'sha256';
protected $salt_padding = 'wdHVwU&HcYcWnllo%kTUUnxpScy4%ICM29';
protected $iteration_count = 131072;
protected $key_length = 64;
protected $password;
//-----------------------------------------------------------------------------
public function __construct($username, $password, $options = array())
{
$this->username = $username;
$this->password = $password;
if(!empty($options['hash']))
$this->hash = strtolower(trim($options['hash']));
if(!empty($options['iterations']))
$this->iteration_count = intval($options['iterations']);
if(!empty($options['salt']))
$this->salt_padding = $options['salt'];
if(!empty($options['key_length']))
$this->key_length = intval($options['key_length']);
}
//-----------------------------------------------------------------------------
public static function get_password_hash($username, $password, $options = array())
{
$hasher = new iThemes_Credentials($username, $password, $options);
return $hasher->get_pbkdf2();
}
//-----------------------------------------------------------------------------
public function get_salt()
{
return strtolower(trim($this->username)) . $this->salt_padding;
}
//-----------------------------------------------------------------------------
public function get_pbkdf2()
{
return $this->pbkdf2($this->hash,
$this->password,
$this->get_salt(),
$this->iteration_count,
$this->key_length / 2,
false);
}
//-----------------------------------------------------------------------------
/*
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
* $algorithm - The hash algorithm to use. Recommended: SHA256
* $password - The password.
* $salt - A salt that is unique to the password.
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
* $key_length - The length of the derived key in bytes.
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
* Returns: A $key_length-byte key derived from the password and salt.
*
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
*
* This implementation of PBKDF2 was originally created by https://defuse.ca
* With improvements by http://www.variations-of-shadow.com
*/
private function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
if($count <= 0 || $key_length <= 0)
trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);
$hash_length = strlen(hash($algorithm, '', true));
$block_count = ceil($key_length / $hash_length);
$output = '';
for($i = 1; $i <= $block_count; $i++)
{
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++)
{
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
if($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}
//-----------------------------------------------------------------------------
}
//-----------------------------------------------------------------------------

View File

@@ -0,0 +1 @@
<?php // Silence is golden.

View File

@@ -0,0 +1,200 @@
#icon-options-general,
#icon-settings {
background: url( '../images/logo-ithemes.png' ) no-repeat;
}
#ithemes-updater-licensed .subtitle {
background: url( '../images/icon-licensed.png' ) no-repeat;
}
#ithemes-updater-unlicensed .subtitle {
background: url( '../images/icon-unlicensed.png' ) no-repeat;
}
#ithemes-updater-unrecognized .subtitle {
background: url( '../images/icon-unrecognized.png' ) no-repeat;
}
#ithemes-updater-settings .subtitle {
background: url( '../images/icon-settings.png' ) no-repeat;
}
.wrap h2 + .error,
.wrap h2 + .updated {
margin-top: 2em;
}
.wrap .subtitle {
font-size: 23px;
line-height: 30px;
margin: 1.5em 0 .5em;
padding: 0 0 0 35px;
}
.wrap .widefat.ithemes-updater-listing th,
.wrap .widefat.ithemes-updater-listing td {
padding: 0;
vertical-align: middle;
}
.wrap .widefat.ithemes-updater-listing tfoot td {
padding: 13px 10px;
}
.ithemes-updater-listing label {
display: block;
padding: 10px;
}
.widefat.ithemes-updater-listing th.check-column {
}
.widefat.ithemes-updater-listing th.check-column input {
margin: 0;
}
.wrap #ithemes-updater-unrecognized .widefat.ithemes-updater-listing th,
.wrap #ithemes-updater-unrecognized .widefat.ithemes-updater-listing td {
padding: 10px;
}
.widefat.ithemes-updater-listing tr.expiring {
background-color: #FFFFE0;
}
.widefat.ithemes-updater-listing tr.expiring.alt {
background-color: #F5F5D2;
}
.widefat.ithemes-updater-listing tr.expired {
background-color: #FFEBE8;
}
.widefat.ithemes-updater-listing tr.expired.alt {
background-color: #F9E1DD;
}
#ithemes-updater-site-url-confirmation {
padding-left: 13px;
}
#ithemes-updater-site-url-confirmation .ithemes-updater-header {
background: url( '../images/ithemes-logo-header.png' ) no-repeat;
height: 30px;
width: 198px;
display: block;
margin: 29px 0 32px;
}
#ithemes-updater-site-url-confirmation h2 {
font-size: 24px;
}
#ithemes-updater-site-url-confirmation > p {
font-size: 16px;
}
#ithemes-updater-site-url-confirmation #ithemes-updater-table-wrapper {
background-color: #FFFFFF;
padding: 0 20px;
border: 4px solid #FFFFFF;
border-radius: 4px;
max-width: 900px;
}
#ithemes-updater-site-url-confirmation form {
margin: 24px 0;
}
#ithemes-updater-site-url-confirmation table {
margin: 0;
}
#ithemes-updater-site-url-confirmation th {
width: 400px;
}
#ithemes-updater-site-url-confirmation td {
vertical-align: top;
padding: 20px 0 20px 10px;
}
#ithemes-updater-site-url-confirmation th label {
text-transform: uppercase;
}
#ithemes-updater-site-url-confirmation th label+.description {
padding-top: 10px;
}
#ithemes-updater-site-url-confirmation .description {
font-size: 12px;
font-weight: normal;
}
#ithemes-updater-site-url-confirmation .ithemes-updater-description-warning {
font-style: italic;
}
#ithemes-updater-site-url-confirmation .submit input[type="submit"] {
font-size: 16px;
font-weight: bold;
line-height: 16px;
padding: 11px 21px;
border-radius: 4px;
}
#ithemes-updater-relicense {
padding-left: 13px;
}
#ithemes-updater-relicense .ithemes-updater-header {
background: url( '../images/ithemes-logo-header.png' ) no-repeat;
height: 30px;
width: 198px;
display: block;
margin: 29px 0 32px;
}
#ithemes-updater-relicense h2 {
font-size: 24px;
}
#ithemes-updater-relicense > p {
font-size: 16px;
}
#ithemes-updater-relicense #ithemes-updater-table-wrapper {
background-color: #FFFFFF;
padding: 10px;
border: 4px solid #FFFFFF;
border-radius: 4px;
max-width: 900px;
}
#ithemes-updater-relicense form {
margin: 24px 0;
}
#ithemes-updater-relicense table {
margin: 0;
}
#ithemes-updater-relicense th {
width: 250px;
padding: 10px;
}
#ithemes-updater-relicense td {
vertical-align: top;
padding: 10px;
}
#ithemes-updater-relicense th label {
text-transform: uppercase;
}
#ithemes-updater-relicense th label+.description {
padding-top: 10px;
}
#ithemes-updater-relicense th input {
margin-top: 10px;
}
#ithemes-updater-relicense td input[type="radio"] {
margin-left: -23px;
}
#ithemes-updater-relicense .description {
font-size: 12px;
font-weight: normal;
}
#ithemes-updater-relicense .ithemes-updater-description-warning {
font-style: italic;
margin-top: 10px;
}
#ithemes-updater-relicense .ithemes-updater-description-notice {
font-style: italic;
margin-top: 10px;
background-color: #D7F0FC;
border-radius: 3px;
color: #366C92;
padding: 5px 8px 5px 29px;
}
#ithemes-updater-relicense .ithemes-updater-description-notice .dashicons-warning {
margin-left: -23px;
}
#ithemes-updater-relicense .submit input[type="submit"] {
font-size: 16px;
font-weight: bold;
line-height: 16px;
padding: 11px 21px;
border-radius: 4px;
}

View File

@@ -0,0 +1,107 @@
<?php
/*
Misc functions to assist the updater code.
Written by Chris Jean for iThemes.com
Version 1.0.0
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
*/
class Ithemes_Updater_Functions {
public static function get_url( $path ) {
$path = str_replace( '\\', '/', $path );
$wp_content_dir = str_replace( '\\', '/', WP_CONTENT_DIR );
if ( 0 === strpos( $path, $wp_content_dir ) )
return content_url( str_replace( $wp_content_dir, '', $path ) );
$abspath = str_replace( '\\', '/', ABSPATH );
if ( 0 === strpos( $path, $abspath ) )
return site_url( str_replace( $abspath, '', $path ) );
$wp_plugin_dir = str_replace( '\\', '/', WP_PLUGIN_DIR );
$wpmu_plugin_dir = str_replace( '\\', '/', WPMU_PLUGIN_DIR );
if ( 0 === strpos( $path, $wp_plugin_dir ) || 0 === strpos( $path, $wpmu_plugin_dir ) )
return plugins_url( basename( $path ), $path );
return false;
}
public static function get_package_name( $package ) {
$name = str_replace( 'builderchild', 'Builder Child', $package );
$name = str_replace( '-', ' ', $name );
$name = ucwords( $name );
$name = str_replace( 'buddy', 'Buddy', $name );
$name = str_replace( 'Ithemes', 'iThemes', $name );
return $name;
}
public static function get_post_data( $vars, $fill_missing = false ) {
$data = array();
foreach ( $vars as $var ) {
if ( isset( $_POST[$var] ) ) {
$clean_var = preg_replace( '/^it-updater-/', '', $var );
$data[$clean_var] = $_POST[$var];
}
else if ( $fill_missing ) {
$data[$var] = '';
}
}
return stripslashes_deep( $data );
}
public static function get_site_option( $option ) {
global $wpdb;
$options = get_site_option( $option, false );
if ( is_array( $options ) ) {
return $options;
}
// Attempt to get the stored option manually to ensure that the failure wasn't due to a DB or other glitch.
if ( is_multisite() ) {
$network_id = get_current_network_id();
$query = $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d LIMIT 1", $option, $network_id );
$index = 'meta_value';
} else {
$query = $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option );
$index = 'option_value';
}
$result = $wpdb->query( $query );
if ( false === $result ) {
// Something went wrong with the DB.
return false;
}
if ( empty( $wpdb->last_result[0] ) || empty( $wpdb->last_result[0]->$index ) ) {
// The value has not been set yet, return the default value.
return null;
}
$value = $wpdb->last_result[0]->$index;
$options = @unserialize( $value );
if ( is_array( $options ) ) {
return $options;
}
// Seems that we have some bad data.
// TODO: Attempt data restoration.
return null;
}
}

View File

@@ -0,0 +1,60 @@
1.0.0 - 2013-04-11 - Chris Jean
Release ready version.
1.0.1 - 2013-05-01 - Chris Jean
Fixed a compatibility problem with the automatic-updater plugin.
1.0.2 - 2013-06-21 - Chris Jean
Fixed an issue where requests would fail when made by servers with a non-default value for arg_separator.output in the php.ini file.
1.1.0 - 2013-10-02 - Chris Jean
Big rewrite to the updater in order to make the code more flexible. This improves compatibility with plugins that allow for remote updating of plugins and themes.
The updater now supports providing changelog details for plugins and themes that have updates available. These details can be viewed by clicking the "View version **** details" link for the appropriate plugin or theme.
1.2.0 - 2013-10-04 - Chris Jean
Enhancement: When releases with four version digits are released (such as 2.1.0.3), by default, the updater will not offer to update if just this last digit is updated. For instance, it will not automatically offer to update 2.1.0.1 to 2.1.0.3; rather, an automatic upgrade will become available when version 2.1.1 or greater is released. If you wish to force an update to these versions, you can add ithemes-updater-force-minor-update=1 to an admin page request (such as http://domain.com/wp-admin/index.php?ithemes-updater-force-minor-update=1) in order to force the updater make these releases available for an hour. If the update is not performed within the hour, the updater reverts back to default behavior.
Bug Fix: Corrected source of the following error when updating: Download failed. SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Bug Fix: Corrected source of the following warning: Warning: require_once(/api.php) [function.require-once]: failed to open stream: No such file or directory
1.2.1 - 2013-10-07 - Chris Jean
Bug Fix: Corrected another source of the following warning which occur immediate after updating the plugin or theme: Warning: require_once(/api.php) [function.require-once]: failed to open stream: No such file or directory
1.3.0 - 2013-10-23 - Chris Jean
Enhancement: Added a "Quick Release Updates" setting to the bottom of the licensing page. Enabling this option allows the site to receive automatic update notices for product quick releases (releases that do not have automatic update support by default).
Enhancement: Changed how the licensing page works on Multisite. Now it will appear at Settings > iThemes Licensing in the network admin Dashboard and at Settings > iThemes Licensing on sites when the current user is a network admin. This prevents exposing the licensing page to users that don't are not super users and thus should not be performing updates. As this update makes the functionality of the "Licensing Page Access" setting obsolete, the setting has been removed.
Enhancement: Using the ithemes-updater-force-minor-update query string variable will now force a data flush, allowing any available quick release updates to appear instantly.
Enhancement: Added "License" links to the Plugins and Themes pages for the Network Admin Dashboard of multisite installs.
1.3.1 - 2013-12-13 - Chris Jean
Enhancement: Recently updated plugins and themes no longer report that an update is available.
Enhancement: Added alternate line styling to the listings on the licensing page.
Enhancement: Products with iThemes in the name will now properly capitalize the name.
Enhancement: The updater and licensing system now handle iThemes server outages without causing long page delays or by reporting confusing error messages.
1.3.2 - 2013-12-18 - Chris Jean
Bug Fix: Removed unneeded check on package-info.ithemes.com which was causing performance issues on some sites.
1.3.3 - 2013-12-19 - Chris Jean
Bug Fix: Licensing will now be universal across all sites of a multisite network. This means that you will only need to license on one site to have the license apply across the entire network.
1.3.4 - 2014-02-03 - Chris Jean
Bug Fix: Licensing on SSL-enabled sites now works properly.
1.4.0 - 2014-11-14 - Chris Jean
Enhancement: Reduced caching to allow updates to appear more quickly.
Enhancement: Authenticating users now uses the new authentication system.
1.4.1 - 2015-04-23 - Chris Jean
Compatibility Fix: Updated plugin and theme update data format to match changes in WordPress 4.2.
1.4.2 - 2015-07-14 - Chris Jean
Enhancement: Updated link to iThemes support.
1.5.0 - 2018-05-02 - Chris Jean
Bug Fix: Fixed the "View details" link failing to work properly after updating.
Bug Fix: Fixed an issue that could cause data changes to not save properly on specific background page requests.
Bug Fix: Added a compatibility fix to avoid conflicts with plugins that change the plugin_action_links filter value from an array to a string.
Compatibility Fix: Updated handing of wp_remote_get() response due to changes documented in https://core.trac.wordpress.org/ticket/33055.
Enhancement: Added ability to manage licensing from WP-CLI.
1.5.1 - 2018-05-03 - Chris Jean
Bug Fix: Fixed fatal error that could occur when clicking the "View details" link for an available plugin update.
1.5.2 - 2018-05-25 - Chris Jean
Bug Fix: Fixed error in error handler for cases where requests for changelog updates fail.
1.6.0 - 2020-08-06 - Chris Jean
Enhancement: Added the ability for the user to manage the licensed site URL.
1.6.1 - 2020-08-06 - Chris Jean
Bug Fix: Fixed bug that can cause licensed site URL management from working properly on some sites on https connections.
1.6.2 - 2020-08-07 - Chris Jean
Bug Fix: Fixed fatal error that can happen when upgrading to the 1.6.1 version of this code:
Ithemes_Updater_Settings::get_licensed_site_url() in server.php:199".
1.6.4 - 2020-08-11 - Chris Jean
Enhancement: Added support for the auto-update feature introduced in WordPress 5.5.
1.6.4 - 2020-09-01 - Chris Jean
Bug Fix: Fixed source of this warning:
PHP Notice: Undefined index: status in lib/updater/settings-page.php

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1 @@
<?php // Silence is golden.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

View File

@@ -0,0 +1 @@
<?php // Silence is golden.

View File

@@ -0,0 +1,61 @@
<?php
/*
Provides details formatted for use in "View version *** details" boxes.
Written by Chris Jean for iThemes.com
Version 1.1.1
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-09-19 - Chris Jean
Updated requires to not use dirname().
1.1.0 - 2013-10-02 - Chris Jean
Added get_theme_information().
1.1.1 - 2013-12-18 - Chris Jean
Removed unneeded code that checked package-info.ithemes.com.
*/
class Ithemes_Updater_Information {
public static function get_theme_information( $path ) {
return self::get_plugin_information( "$path/style.css" );
}
public static function get_plugin_information( $path ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
$details = Ithemes_Updater_Packages::get_full_details();
if ( ! isset( $details['packages'][$path] ) )
return false;
$package = $details['packages'][$path];
require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
$changelog = Ithemes_Updater_API::get_package_changelog( $package['package'], $details['packages'][$path]['installed'] );
if ( is_wp_error( $changelog ) ) {
/* translators: 1. Error message, 2. Error code */
$changelog = sprintf( __( '<p>Unable to get changelog data at this time.</p><p>%1$s (%2$s)</p>', 'rcp-rest' ), $changelog->get_error_message(), $changelog->get_error_code() );
}
$info = array(
'name' => Ithemes_Updater_Functions::get_package_name( $package['package'] ),
'slug' => dirname( $path ),
'version' => $package['available'],
'author' => '<a href="http://ithemes.com/">iThemes</a>',
'download_link' => $package['package-url'],
'sections' => array(
'changelog' => $changelog,
),
);
return (object) $info;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/*
Load the updater and licensing system without loading unneeded parts.
Written by Chris Jean for iThemes.com
Version 1.2.1
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-05-01 - Chris Jean
Fixed a bug where some plugins caused the filter_update_plugins and filter_update_themes to run when load hadn't run, causing errors.
1.1.0 - 2013-09-19 - Chris Jean
Complete restructuring of this file as most of the code has been relocated to other files.
1.2.0 - 2013-12-13 - Chris Jean
Added the ability to force clear the server timeout hold by adding a query variable named ithemes-updater-force-clear-server-timeout-hold to the URL.
1.2.1 - 2014-10-23 - Chris Jean
Removed ithemes-updater-force-clear-server-timeout-hold code.
*/
if ( defined( 'WP_CLI' ) && WP_CLI && class_exists( 'WP_CLI_Command' ) && ! class_exists( 'Ithemes_Updater_WP_CLI_Ithemes_Licensing' ) ) {
require( dirname( __FILE__ ) . '/wp-cli.php' );
WP_CLI::add_command( 'ithemes-licensing', 'Ithemes_Updater_WP_CLI_Ithemes_Licensing' );
}
if ( defined( 'ITHEMES_UPDATER_DISABLE' ) && ITHEMES_UPDATER_DISABLE ) {
return;
}
$GLOBALS['ithemes_updater_path'] = dirname( __FILE__ );
if ( is_admin() ) {
require( $GLOBALS['ithemes_updater_path'] . '/admin.php' );
}
function ithemes_updater_filter_update_plugins( $update_plugins ) {
if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
}
return $GLOBALS['ithemes-updater-settings']->filter_update_plugins( $update_plugins );
}
add_filter( 'site_transient_update_plugins', 'ithemes_updater_filter_update_plugins' );
add_filter( 'transient_update_plugins', 'ithemes_updater_filter_update_plugins' );
function ithemes_updater_filter_update_themes( $update_themes ) {
if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
}
return $GLOBALS['ithemes-updater-settings']->filter_update_themes( $update_themes );
}
add_filter( 'site_transient_update_themes', 'ithemes_updater_filter_update_themes' );
add_filter( 'transient_update_themes', 'ithemes_updater_filter_update_themes' );
function ithemes_updater_get_licensed_site_url() {
if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
}
return $GLOBALS['ithemes-updater-settings']->get_licensed_site_url();
}
function ithemes_updater_get_seen_hostnames() {
if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
}
return $GLOBALS['ithemes-updater-settings']->get_hostname_history();
}
function ithemes_updater_is_request_on_licensed_site_url() {
if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
}
return $GLOBALS['ithemes-updater-settings']->is_request_on_licensed_site_url();
}
function ithemes_updater_get_change_licensed_site_url( $redirect = '' ) {
return admin_url( 'options-general.php?page=ithemes-licensing&action=change_licensed_site_url&redirect=' . urlencode( $redirect ) );
}
function ithemes_updater_change_licensed_site_url( $redirect = '' ) {
wp_redirect( ithemes_updater_get_change_licensed_site_url( $redirect ) );
exit();
}
function ithemes_updater_is_licensed_site_url_confirmed() {
if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
}
return $GLOBALS['ithemes-updater-settings']->is_licensed_site_url_confirmed();
}

View File

@@ -0,0 +1 @@
<?php // Silence is golden.

View File

@@ -0,0 +1,7 @@
jQuery(document).ready(
function() {
if ( jQuery( '#ithemes-updater-redirect-to-url' ).length ) {
window.location.replace( jQuery( '#ithemes-updater-redirect-to-url' ).val() );
}
}
);

View File

@@ -0,0 +1,177 @@
<?php
/*
Provides license key management.
Written by Chris Jean for iThemes.com
Version 1.0.2
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-09-19 - Chris Jean
Updated requires to no longer use dirname().
1.0.2 - 2014-10-23 - Chris Jean
Updated code to meet WordPress coding standards.
*/
class Ithemes_Updater_Keys {
private static $option_name = 'ithemes-updater-keys';
public static function get( $packages = array() ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
$all_keys = Ithemes_Updater_Functions::get_site_option( self::$option_name );
if ( false === $all_keys ) {
$GLOBALS['ithemes-updater-keys-db-failure'] = true;
} else {
$GLOBALS['ithemes-updater-keys-db-failure'] = false;
}
if ( ! is_array( $all_keys ) ) {
$all_keys = array();
}
if ( '__all__' == $packages ) {
return $all_keys;
}
if ( empty( $packages ) ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
$packages = array_unique( array_values( Ithemes_Updater_Packages::get_all() ) );
}
$keys = array();
foreach ( (array) $packages as $package ) {
if ( ! empty( $all_keys[$package] ) ) {
$keys[$package] = $all_keys[$package];
}
}
if ( ! is_array( $packages ) ) {
return $keys[$packages];
}
return $keys;
}
public static function set( $new_keys, $key = false ) {
$keys = self::get( '__all__' );
if ( false === $key ) {
foreach ( $new_keys as $package => $key ) {
$keys[$package] = $key;
}
} else {
$keys[$new_keys] = $key;
}
if ( ! isset( $GLOBALS['ithemes-updater-keys-db-failure'] ) || false === $GLOBALS['ithemes-updater-keys-db-failure'] ) {
update_site_option( self::$option_name, $keys );
}
}
private static function get_legacy_slug( $raw_slug ) {
$slug = str_replace( '_', '-', $raw_slug );
$slug = preg_replace( '/^(pluginbuddy|ithemes|it)-/', '', $slug );
if ( 'boom-bar' == $slug ) {
$slug = 'boombar';
}
return $slug;
}
public static function delete_legacy( $packages = array() ) {
if ( ! is_array( $packages ) ) {
$packages = array( $packages );
}
$data = get_site_option( 'pluginbuddy_plugins', false );
$remaining_count = 0;
foreach ( $data as $index => $entry ) {
if ( ! is_object( $entry ) || empty( $entry->slug ) ) {
continue;
}
$slug = self::get_legacy_slug( $entry->slug );
if ( in_array( $slug, $packages ) ) {
unset( $data[$index] );
} else {
$remaining_count++;
}
}
if ( 0 == $remaining_count ) {
$data = false;
}
update_site_option( 'pluginbuddy_plugins', $data );
}
public static function get_legacy( $packages = array() ) {
$data = get_site_option( 'pluginbuddy_plugins', false );
if ( empty( $data ) || ! is_array( $data ) ) {
return array();
}
$keys = array();
foreach ( $data as $index => $entry ) {
if ( ! is_object( $entry ) || empty( $entry->slug ) || ! isset( $entry->key ) ) {
continue;
}
$slug = self::get_legacy_slug( $entry->slug );
$keys[$slug] = $entry->key;
}
foreach ( array_keys( $keys ) as $slug ) {
if ( ! isset( $data[$slug] ) ) {
continue;
}
$entry = $data[$slug];
if ( ! is_object( $entry ) || empty( $entry->slug ) || empty( $entry->key ) ) {
continue;
}
$keys[$slug] = $entry->key;
}
if ( empty( $packages ) ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
$packages = array_unique( array_values( Ithemes_Updater_Packages::get_all() ) );
} else if ( is_string( $packages ) ) {
if ( ! empty( $keys[$packages] ) ) {
return $keys[$packages];
}
return false;
}
$package_keys = array();
foreach ( $packages as $package ) {
if ( ! empty( $keys[$package] ) ) {
$package_keys[$package] = $keys[$package];
}
}
return $package_keys;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
Written by Chris Jean for iThemes.com
*/
$it_registration_list_version = '1.6.5';
$it_registration_list_library = 'updater';
$it_registration_list_init_file = dirname( __FILE__ ) . '/init.php';
$GLOBALS['it_classes_registration_list'][$it_registration_list_library][$it_registration_list_version] = $it_registration_list_init_file;
if ( ! function_exists( 'it_registration_list_init' ) ) {
function it_registration_list_init() {
// The $wp_locale variable is set just before the theme's functions.php file is loaded,
// this acts as a good check to ensure that both the plugins and the theme have loaded.
global $wp_locale;
if ( ! isset( $wp_locale ) )
return;
$init_files = array();
foreach ( (array) $GLOBALS['it_classes_registration_list'] as $library => $versions ) {
$max_version = '-10000';
$init_file = '';
foreach ( (array) $versions as $version => $file ) {
if ( version_compare( $version, $max_version, '>' ) ) {
$max_version = $version;
$init_file = $file;
}
}
if ( ! empty( $init_file ) )
$init_files[] = $init_file;
}
unset( $GLOBALS['it_classes_registration_list'] );
foreach ( (array) $init_files as $init_file )
require_once( $init_file );
do_action( 'it_libraries_loaded' );
}
global $wp_version;
if ( version_compare( $wp_version, '2.9.7', '>' ) )
add_action( 'after_setup_theme', 'it_registration_list_init' );
else
add_action( 'set_current_user', 'it_registration_list_init' );
}

View File

@@ -0,0 +1,223 @@
<?php
/*
Provides a reliable way of retrieving which projects have updates.
Written by Chris Jean for iThemes.com
Version 1.0.2
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-09-19 - Chris Jean
Added support for 'upgrade' data for a package.
Updated requires to no longer use dirname().
1.0.2 - 2014-10-23 - Chris Jean
Updated to meet WordPress coding standards.
*/
class Ithemes_Updater_Packages {
public static function flush() {
unset( $GLOBALS['ithemes-updater-packages-all'] );
}
public static function get_full_details( $response = false ) {
if ( false === $response ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/api.php' );
$response = Ithemes_Updater_API::get_package_details();
}
$packages = self::get_local_details();
if ( is_wp_error( $response ) ) {
$expiration = time() + 600;
foreach ( $packages as $path => $data ) {
$packages[$path]['status'] = 'error';
$packages[$path]['error'] = array(
'code' => 'unknown',
'type' => $response->get_error_code(),
'message' => $response->get_error_message(),
);
}
} else {
$expiration = time() + ( 12 * 3600 );
foreach ( $packages as $path => $data ) {
if ( empty( $response['packages'][$data['package']] ) ) {
continue;
}
$package = $response['packages'][$data['package']];
if ( ! empty( $package['error'] ) ) {
if ( in_array( $package['error']['type'], array( 'ITXAPI_License_Key_Unknown', 'ITXAPI_Updater_Missing_Legacy_Key' ) ) ) {
$packages[$path]['status'] = 'unlicensed';
} else {
$packages[$path]['status'] = 'error';
$packages[$path]['error'] = $package['error'];
}
continue;
}
$key_map = array(
'status' => 'status',
'link' => 'package-url',
'ver' => 'available',
'used' => 'used',
'total' => 'total',
'user' => 'user',
'sub_expire' => 'expiration',
'upgrade' => 'upgrade',
);
foreach ( $key_map as $old => $new ) {
if ( isset( $package[$old] ) ) {
$packages[$path][$new] = $package[$old];
} else {
$packages[$path][$new] = null;
}
}
if ( isset( $package['link_expire'] ) ) {
$expiration = min( $expiration, $package['link_expire'] );
}
}
}
$details = compact( 'packages', 'expiration' );
return $details;
}
public static function get_local_details() {
require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
$all_packages = self::get_all();
$keys = Ithemes_Updater_Keys::get();
$packages = array();
foreach ( $all_packages as $file => $slug ) {
$packages[$slug][] = $file;
}
foreach ( $packages as $slug => $paths ) {
$packages[$slug] = array_unique( $paths );
}
$details = array();
foreach ( $packages as $package => $paths ) {
foreach ( $paths as $path ) {
$plugin_path = preg_replace( '/^' . preg_quote( WP_PLUGIN_DIR, '/' ) . '/', '', $path );
if ( $plugin_path != $path ) {
$type = 'plugin';
$rel_path = preg_replace( '|^[/\\\\]|', '', $plugin_path );
$plugin_data = get_plugin_data( $path, false, false );
$version = $plugin_data['Version'];
$info_url = $plugin_data['PluginURI'];
} else {
$type = 'theme';
$dir = basename( dirname( $path ) );
$rel_path = "$dir/" . basename( $path );
if ( function_exists( 'wp_get_theme' ) ) {
$theme_data = wp_get_theme( $dir );
$version = $theme_data->get( 'Version' );
$info_url = $theme_data->get( 'ThemeURI' );
} else {
$theme_data = get_theme( $dir );
$version = $theme_data['Version'];
$info_url = '';
}
}
$details[$rel_path] = array(
'type' => $type,
'package' => $package,
'installed' => $version,
'info-url' => $info_url,
'key' => isset( $keys[$package] ) ? $keys[$package] : '',
);
}
}
return $details;
}
public static function get_all() {
if ( isset( $GLOBALS['ithemes-updater-packages-all'] ) ) {
return $GLOBALS['ithemes-updater-packages-all'];
}
$packages = array();
// Compatibility fix for WP < 3.1 as the global var is empty by default
if ( empty( $GLOBALS['wp_theme_directories'] ) ) {
get_themes();
}
$themes = search_theme_directories();
if ( is_array( $themes ) ) {
foreach ( $themes as $slug => $data ) {
if ( ! file_exists( "{$data['theme_root']}/{$data['theme_file']}" ) ) {
continue;
}
$headers = get_file_data( "{$data['theme_root']}/{$data['theme_file']}", array( 'package' => 'iThemes Package' ), 'theme' );
if ( empty( $headers['package'] ) ) {
continue;
}
$packages["{$data['theme_root']}/{$data['theme_file']}"] = $headers['package'];
}
}
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
$plugins = get_plugins();
foreach ( $plugins as $file => $data ) {
if ( ! file_exists( WP_PLUGIN_DIR . "/$file" ) ) {
continue;
}
$headers = get_file_data( WP_PLUGIN_DIR . "/$file", array( 'package' => 'iThemes Package' ), 'plugin' );
if ( empty( $headers['package'] ) ) {
continue;
}
$packages[WP_PLUGIN_DIR . "/$file"] = $headers['package'];
}
foreach ( $packages as $path => $package ) {
$packages[$path] = strtolower( $package );
}
$GLOBALS['ithemes-updater-packages-all'] = $packages;
return $packages;
}
}

View File

@@ -0,0 +1,258 @@
<?php
/*
Provides an easy to use interface for communicating with the iThemes updater server.
Written by Chris Jean for iThemes.com
Version 1.1.0
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-06-21 - Chris Jean
Updated the http_build_query call to force a separator of & in order to avoid issues with servers that change the arg_separator.output php.ini value.
1.0.2 - 2013-09-19 - Chris Jean
Updated ithemes-updater-object to ithemes-updater-settings.
1.0.3 - 2013-12-18 - Chris Jean
Updated the way that the site URL is generated to ensure consistency across multisite sites.
1.0.4 - 2014-01-31 - Chris Jean
Updated to normalize the site URL used for password hash generation and for sending to the server.
1.1.0 - 2014-10-23 - Chris Jean
Updated auth token generation to use new password hashing.
Added CA patch code.
Updated code to meet WordPress coding standards.
*/
class Ithemes_Updater_Server {
private static $secure_server_url = 'https://api.ithemes.com/updater';
private static $insecure_server_url = 'http://api.ithemes.com/updater';
private static $password_iterations = 8;
public static function activate_package( $username, $password, $packages ) {
$query = array(
'user' => $username
);
$data = array(
'auth_token' => self::get_password_hash( $username, $password ),
'packages' => $packages,
);
return Ithemes_Updater_Server::request( 'package-activate', $query, $data );
}
public static function deactivate_package( $username, $password, $packages ) {
$query = array(
'user' => $username
);
$data = array(
'auth_token' => self::get_password_hash( $username, $password ),
'packages' => $packages,
);
return Ithemes_Updater_Server::request( 'package-deactivate', $query, $data );
}
public static function get_licensed_site_url( $packages ) {
$query = array();
$data = array(
'packages' => $packages
);
return Ithemes_Updater_Server::request( 'licensed-site-url-get', $query, $data );
}
public static function set_licensed_site_url( $username, $password, $site_url, $keys ) {
$query = array(
'user' => $username
);
$data = array(
'auth_token' => self::get_password_hash( $username, $password ),
'site_url' => $site_url,
'keys' => $keys,
);
return Ithemes_Updater_Server::request( 'licensed-site-url-set', $query, $data );
}
public static function get_package_details( $packages ) {
global $rcp_options;
$query = array();
$data = array(
'packages' => $packages
);
if ( ! empty( $rcp_options ) && is_array( $rcp_options ) && ! empty( $rcp_options['license_key'] ) ) {
$data['rcp_license_key'] = $rcp_options['license_key'];
}
return Ithemes_Updater_Server::request( 'package-details', $query, $data );
}
public static function request( $action, $query = array(), $data = array() ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
if ( false !== ( $timeout_start = get_site_option( 'ithemes-updater-server-timed-out' ) ) ) {
// Hold off updates for 30 minutes.
$time_remaining = 1800 - ( time() - $timeout_start );
$minutes_remaining = ceil( $time_remaining / 60 );
if ( $time_remaining < 0 ) {
delete_site_option( 'ithemes-updater-server-timed-out' );
} else {
return new WP_Error( 'ithemes-updater-timed-out-server', sprintf( _n( 'The server could not be contacted. Requests are delayed for %d minute to allow the server to recover.', 'The server could not be contacted. Requests are delayed for %d minutes to allow the server to recover.', $minutes_remaining, 'rcp-rest' ), $minutes_remaining ) );
}
}
if ( isset( $data['auth_token'] ) ) {
$data['iterations'] = self::$password_iterations;
}
$site_url = self::get_site_url();
$default_query = array(
'wp' => $GLOBALS['wp_version'],
'site' => $site_url,
'timestamp' => time(),
'auth_version' => '2',
);
if ( is_multisite() ) {
$default_query['ms'] = 1;
}
$query = array_merge( $default_query, $query );
$request = "/$action/?" . http_build_query( $query, '', '&' );
$post_data = array(
'request' => json_encode( $data ),
);
$remote_post_args = array(
'timeout' => 10,
'body' => $post_data,
);
$options = array(
'use_ca_patch' => false,
'use_ssl' => true,
);
$patch_enabled = $GLOBALS['ithemes-updater-settings']->get_option( 'use_ca_patch' );
if ( $patch_enabled ) {
self::disable_ssl_ca_patch();
}
$response = wp_remote_post( self::$secure_server_url . $request, $remote_post_args );
if ( is_wp_error( $response ) && ( 'connect() timed out!' != $response->get_error_message() ) ) {
self::enable_ssl_ca_patch();
$response = wp_remote_post( self::$secure_server_url . $request, $remote_post_args );
if ( ! is_wp_error( $response ) ) {
$options['use_ca_patch'] = true;
}
}
if ( is_wp_error( $response ) && ( 'connect() timed out!' != $response->get_error_message() ) ) {
$response = wp_remote_post( self::$insecure_server_url . $request, $remote_post_args );
$options['use_ssl'] = false;
}
if ( ! $options['use_ca_patch'] ) {
self::disable_ssl_ca_patch();
}
$GLOBALS['ithemes-updater-settings']->update_options( $options );
if ( is_wp_error( $response ) ) {
if ( 'connect() timed out!' == $response->get_error_message() ) {
// Set option to delay server checks for a period of time.
update_site_option( 'ithemes-updater-server-timed-out', time() );
return new WP_Error( 'http_request_failed', __( 'The server was unable to be contacted.', 'rcp-rest' ) );
}
return $response;
}
$body = json_decode( $response['body'], true );
if ( ! empty( $body['error'] ) ) {
return new WP_Error( $body['error']['type'], sprintf( __( 'An error occurred when communicating with the iThemes update server: %s (%s)', 'rcp-rest' ), $body['error']['message'], $body['error']['code'] ) );
}
return $body;
}
private static function get_site_url() {
require_once( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
// Ensure that a fatal error isn't triggered on upgrade.
if ( is_callable( array( $GLOBALS['ithemes-updater-settings'], 'get_licensed_site_url' ) ) ) {
$site_url = $GLOBALS['ithemes-updater-settings']->get_licensed_site_url();
}
if ( empty( $site_url ) ) {
if ( is_callable( 'network_home_url' ) ) {
$site_url = network_home_url( '', 'http' );
} else {
$site_url = get_bloginfo( 'url' );
}
}
$site_url = preg_replace( '/^https/', 'http', $site_url );
$site_url = preg_replace( '|/$|', '', $site_url );
return $site_url;
}
private static function get_password_hash( $username, $password ) {
require_once( ABSPATH . WPINC . '/class-phpass.php' );
require_once( dirname( __FILE__ ) . '/class-ithemes-credentials.php' );
$password = iThemes_Credentials::get_password_hash( $username, $password );
$salted_password = $password . $username . self::get_site_url() . $GLOBALS['wp_version'];
$salted_password = substr( $salted_password, 0, max( strlen( $password ), 512 ) );
$hasher = new PasswordHash( self::$password_iterations, true );
$auth_token = $hasher->HashPassword( $salted_password );
return $auth_token;
}
public static function enable_ssl_ca_patch() {
add_action( 'http_api_curl', array( __CLASS__, 'add_ca_patch_to_curl_opts' ) );
}
public static function disable_ssl_ca_patch() {
remove_action( 'http_api_curl', array( __CLASS__, 'add_ca_patch_to_curl_opts' ) );
}
public static function add_ca_patch_to_curl_opts( $handle ) {
$url = curl_getinfo( $handle, CURLINFO_EFFECTIVE_URL );
if ( ! preg_match( '{^https://(api|downloads)\.ithemes\.com}', $url ) ) {
return;
}
curl_setopt( $handle, CURLOPT_CAINFO, $GLOBALS['ithemes_updater_path'] . '/ca/roots.crt' );
}
}

View File

@@ -0,0 +1,957 @@
<?php
/*
Code to render and manage the settings page for the updater system.
Written by Chris Jean for iThemes.com
Version 1.1.0
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-09-19 - Chris Jean
Updated requires to not use dirname().
Updated ithemes-updater-object to ithemes-updater-settings.
1.1.0 - 2013-10-23 - Chris Jean
Enhancement: Added the quick_releases setting.
Misc: Removed the show_on_sites setting as it is no longer used.
*/
class Ithemes_Updater_Settings_Page {
private $page_name = 'ithemes-licensing';
private $path_url = '';
private $self_url = '';
private $messages = array();
private $message_strings = array();
private $errors = array();
private $soft_errors = array();
public function __construct() {
require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/api.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
$this->path_url = Ithemes_Updater_Functions::get_url( $GLOBALS['ithemes_updater_path'] );
list( $this->self_url ) = explode( '?', $_SERVER['REQUEST_URI'] );
$this->self_url .= '?page=' . $this->page_name;
add_action( 'ithemes_updater_settings_page_index', array( $this, 'index' ) );
add_action( 'admin_print_scripts', array( $this, 'add_scripts' ) );
add_action( 'admin_print_styles', array( $this, 'add_styles' ) );
}
public function add_scripts() {
wp_enqueue_script( 'ithemes-updater-settings-page-script', "{$this->path_url}/js/settings-page.js", array(), 2 );
}
public function add_styles() {
wp_enqueue_style( 'ithemes-updater-settings-page-style', "{$this->path_url}/css/settings-page.css", array(), 2 );
}
public function index() {
$post_data = Ithemes_Updater_Functions::get_post_data( array( 'it-updater-username', 'it-updater-password', 'packages', 'action', 'site_url', 'redirect', 'relicense_option' ), true );
if ( empty( $post_data['packages'] ) ) {
$post_data['packages'] = array();
}
if ( ! empty( $post_data['action'] ) ) {
$action = $post_data['action'];
} else if ( ! empty( $_REQUEST['action'] ) ) {
$action = $_REQUEST['action'];
} else {
$action = 'list_packages';
}
if ( 'save_licensed_site_url' === $action ) {
$this->save_licensed_site_url( $post_data );
} else if ( 'relicense' === $action ) {
$this->relicense( $post_data );
} else if ( 'change_licensed_site_url' === $action || ! $GLOBALS['ithemes-updater-settings']->is_licensed_site_url_confirmed() ) {
$this->show_licensed_site_url_confirmation_page( $post_data );
} else {
if ( 'license_packages' === $action ) {
$this->license_packages( $post_data );
} else if ( 'unlicense_packages' === $action ) {
$this->unlicense_packages( $post_data );
} else if ( 'save_settings' === $action ) {
$this->save_settings();
}
$this->list_packages( $action, $post_data );
}
}
private function save_settings() {
check_admin_referer( 'save_settings', 'ithemes_updater_nonce' );
$settings_defaults = array(
'quick_releases' => false,
);
$settings = array();
foreach ( $settings_defaults as $var => $val ) {
if ( isset( $_POST[$var] ) )
$settings[$var] = $_POST[$var];
else
$settings[$var] = $val;
}
if ( $settings['quick_releases'] )
$settings['quick_releases'] = true;
$GLOBALS['ithemes-updater-settings']->update_options( $settings );
$GLOBALS['ithemes-updater-settings']->flush( 'settings saved' );
$this->messages[] = __( 'Settings saved', 'rcp-rest' );
}
private function license_packages( $data ) {
check_admin_referer( 'license_packages', 'ithemes_updater_nonce' );
if ( empty( $data['username'] ) && empty( $data['password'] ) )
$this->errors[] = __( 'You must supply an iThemes membership username and password in order to license products.', 'rcp-rest' );
else if ( empty( $data['username'] ) )
$this->errors[] = __( 'You must supply an iThemes membership username in order to license products.', 'rcp-rest' );
else if ( empty( $data['password'] ) )
$this->errors[] = __( 'You must supply an iThemes membership password in order to license products.', 'rcp-rest' );
else if ( empty( $data['packages'] ) )
$this->errors[] = __( 'You must select at least one product to license. Ensure that you select the products that you wish to license in the listing below.', 'rcp-rest' );
if ( ! empty( $this->errors ) )
return;
$response = Ithemes_Updater_API::activate_package( $data['username'], $data['password'], $data['packages'] );
if ( is_wp_error( $response ) ) {
$this->errors[] = Ithemes_Updater_API::get_error_explanation( $response );
return;
}
if ( empty( $response['packages'] ) ) {
$this->errors[] = __( 'An unknown server error occurred. Please try to license your products again at another time.', 'rcp-rest' );
return;
}
uksort( $response['packages'], 'strnatcasecmp' );
$success = array();
$warn = array();
$fail = array();
foreach ( $response['packages'] as $package => $data ) {
if ( preg_match( '/ \|\|\| \d+$/', $package ) )
continue;
$name = Ithemes_Updater_Functions::get_package_name( $package );
if ( ! empty( $data['key'] ) )
$success[] = $name;
else if ( ! empty( $data['status'] ) && ( 'expired' == $data['status'] ) )
$warn[$name] = __( 'Your product subscription has expired', 'rcp-rest' );
else
$fail[$name] = $data['error']['message'];
}
if ( ! empty( $success ) )
$this->messages[] = wp_sprintf( __( 'Successfully licensed %l.', 'rcp-rest' ), $success );
if ( ! empty( $fail ) ) {
foreach ( $fail as $name => $reason )
$this->errors[] = sprintf( __( 'Unable to license %1$s. Reason: %2$s', 'rcp-rest' ), $name, $reason );
}
if ( ! empty( $warn ) ) {
foreach ( $warn as $name => $reason )
$this->soft_errors[] = sprintf( __( 'Unable to license %1$s. Reason: %2$s', 'rcp-rest' ), $name, $reason );
}
}
private function unlicense_packages( $data ) {
check_admin_referer( 'unlicense_packages', 'ithemes_updater_nonce' );
if ( empty( $data['username'] ) && empty( $data['password'] ) )
$this->errors[] = __( 'You must supply an iThemes membership username and password in order to remove licenses.', 'rcp-rest' );
else if ( empty( $data['username'] ) )
$this->errors[] = __( 'You must supply an iThemes membership username in order to remove licenses.', 'rcp-rest' );
else if ( empty( $data['password'] ) )
$this->errors[] = __( 'You must supply an iThemes membership password in order to remove licenses.', 'rcp-rest' );
else if ( empty( $data['packages'] ) )
$this->errors[] = __( 'You must select at least one license to remove. Ensure that you select the licenses that you wish to remove in the listing below.', 'rcp-rest' );
if ( ! empty( $this->errors ) )
return;
$response = Ithemes_Updater_API::deactivate_package( $data['username'], $data['password'], $data['packages'] );
if ( is_wp_error( $response ) ) {
$this->errors[] = Ithemes_Updater_API::get_error_explanation( $response );
return;
}
if ( empty( $response['packages'] ) ) {
$this->errors[] = __( 'An unknown server error occurred. Please try to remove licenses from your products again at another time.', 'rcp-rest' );
return;
}
uksort( $response['packages'], 'strnatcasecmp' );
$success = array();
$fail = array();
foreach ( $response['packages'] as $package => $data ) {
if ( preg_match( '/ \|\|\| \d+$/', $package ) )
continue;
$name = Ithemes_Updater_Functions::get_package_name( $package );
if ( isset( $data['status'] ) && ( 'inactive' == $data['status'] ) )
$success[] = $name;
else if ( isset( $data['error'] ) && isset( $data['error']['message'] ) )
$fail[$name] = $data['error']['message'];
else
$fail[$name] = __( 'Unknown server error.', 'rcp-rest' );
}
if ( ! empty( $success ) )
$this->messages[] = wp_sprintf( _n( 'Successfully removed license from %l.', 'Successfully removed licenses from %l.', count( $success ), 'rcp-rest' ), $success );
if ( ! empty( $fail ) ) {
foreach ( $fail as $name => $reason )
$this->errors[] = sprintf( __( 'Unable to remove license from %1$s. Reason: %2$s', 'rcp-rest' ), $name, $reason );
}
}
public function list_packages( $action = 'list_packages', $post_data = array() ) {
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
$details = Ithemes_Updater_Packages::get_full_details();
$packages = $details['packages'];
$licensed = array();
$unlicensed = array();
$unrecognized = array();
foreach ( $packages as $path => $data ) {
$name = Ithemes_Updater_Functions::get_package_name( $data['package'] );
$data['path'] = $path;
if ( isset( $data['status'] ) && 'unlicensed' == $data['status'] )
$unlicensed[$name] = $data;
else if ( isset( $data['status'] ) && in_array( $data['status'], array( 'active', 'expired' ) ) )
$licensed[$name] = $data;
else
$unrecognized[$name] = $data;
}
if ( ! empty( $_REQUEST['updated_url'] ) ) {
$this->messages[] = __( 'Successfully updated the Licensed URL.', 'rcp-rest' );
}
$this->show_notices();
?>
<div class="wrap">
<h2><?php _e( 'iThemes Licensing', 'rcp-rest' ); ?></h2>
<?php
$this->list_licensed_products( $licensed, $post_data, $action );
$this->list_unlicensed_products( $unlicensed, $post_data, $action );
$this->list_unrecognized_products( $unrecognized );
$this->show_settings();
?>
</div>
<?php
}
private function show_settings() {
$quick_releases = $GLOBALS['ithemes-updater-settings']->get_option( 'quick_releases' );
?>
<form id="posts-filter" enctype="multipart/form-data" method="post" action="<?php echo $this->self_url; ?>">
<?php wp_nonce_field( 'save_settings', 'ithemes_updater_nonce' ); ?>
<div id="ithemes-updater-settings">
<h3 class="subtitle"><?php _e( 'Settings', 'rcp-rest' ); ?></h3>
<table class="form-table">
<tbody>
<tr valign="top">
<th scope="row">
<?php _e( 'Licensed URL', 'rcp-rest' ); ?>
</th>
<td>
<p>
<code><?php echo $GLOBALS['ithemes-updater-settings']->get_licensed_site_url(); ?></code>
<a href="<?php echo admin_url( 'options-general.php?page=ithemes-licensing&action=change_licensed_site_url' ); ?>" class="button button-primary"><?php _e( 'Change', 'rcp-rest' ); ?></a>
</p>
<?php if ( is_multisite() ) : ?>
<p class="description"><?php _e( 'The Licensed URL should be the primary URL of this WordPress network. If this is not set correctly, some features may not function as expected.', 'rcp-rest' ); ?></p>
<?php else : ?>
<p class="description"><?php _e( 'The Licensed URL should be the primary URL of this WordPress site. If this is not set correctly, some features may not function as expected.', 'rcp-rest' ); ?></p>
<?php endif; ?>
</td>
</tr>
<tr valign="top">
<th scope="row">
<label for="quick_releases"><?php _e( 'Quick Release Updates', 'rcp-rest' ); ?></label>
</th>
<td>
<?php $checked = ( $quick_releases ) ? ' checked="checked"' : ''; ?>
<label>
<input id="quick_releases" type="checkbox" name="quick_releases" value="1" <?php echo $checked; ?>/>
<?php _e( 'Enable quick release updates', 'rcp-rest' ); ?>
</label>
<p class="description"><?php _e( 'Some products have quick releases that are created to solve specific issues that some users experience. In order to avoid causing users to have updates show up too frequently, automatic updates to these quick releases are disabled by default. Enabling this feature allows quick releases to be available to the automatic update system. Using this option is only recommended if support has requested that you enable it in order to receive a quick release. You should disable this option at a later time after confirming that the quick release solves the issue for you.', 'rcp-rest' ); ?></p>
</td>
</tr>
</tbody>
</table>
<p class="submit">
<input id="save_settings" class="button button-primary" type="submit" value="<?php _e( 'Save Settings', 'rcp-rest' ); ?>" />
<input type="hidden" name="action" value="save_settings" />
</p>
</div>
</form>
<?php
}
private function list_licensed_products( $products, $post_data, $action ) {
if ( empty( $products ) )
return;
uksort( $products, 'strnatcasecmp' );
$time = time();
$headings = array(
__( 'Product', 'rcp-rest' ),
__( 'Member', 'rcp-rest' ),
__( 'Expiration', 'rcp-rest' ),
__( 'Remaining Licenses', 'rcp-rest' ),
);
if ( ( 'unlicense_packages' != $action ) || empty( $this->errors ) ) {
$post_data = array(
'username' => '',
'password' => '',
'packages' => array(),
);
}
?>
<form id="posts-filter" enctype="multipart/form-data" method="post" action="<?php echo $this->self_url; ?>" autocomplete="off">
<?php wp_nonce_field( 'unlicense_packages', 'ithemes_updater_nonce' ); ?>
<div class="ithemes-updater-products" id="ithemes-updater-licensed">
<h3 class="subtitle"><?php _e( 'Licensed Products', 'rcp-rest' ); ?></h3>
<table class="ithemes-updater-listing widefat">
<thead>
<tr>
<th id="cb" class="manage-column column-cb check-column" scope="col">
<label class="screen-reader-text" for="cb-select-all-1"><?php _e( 'Select All' ); ?></label>
<label>
<input id="cb-select-all-1" type="checkbox" />
</label>
</th>
<th scope="col">
<label for="cb-select-all-1"><?php _e( 'Product', 'rcp-rest' ); ?></label>
</th>
<th scope="col"><?php _e( 'Member', 'rcp-rest' ); ?></th>
<th scope="col"><?php _e( 'Product Status', 'rcp-rest' ); ?></th>
<th scope="col"><?php _e( 'Expiration', 'rcp-rest' ); ?></th>
<th scope="col"><?php _e( 'Remaining Licenses', 'rcp-rest' ); ?></th>
</tr>
</thead>
<tbody>
<?php $count = 0; ?>
<?php foreach ( $products as $name => $data ) : ?>
<?php
if ( -1 == $data['total'] )
$remaining = __( 'unlimited', 'rcp-rest' );
else
$remaining = $data['total'] - $data['used'];
// if ( 0 == $remaining )
// $remaining .= ' <a class="button-secondary upgrade">' . __( 'Upgrade', 'rcp-rest' ) . '</a>';
$expiration = $this->get_expiration_string( $data['expiration'] );
$expiration = '<time datetime="' . date( 'Y-m-d\TH:i:s\Z', $data['expiration'] ) . '">' . $expiration . '</time>';
$time_left = $data['expiration'] - $time;
$class = 'expiring';
if ( $time_left > ( 86400 * 30 ) )
$class = 'active';
else if ( $time_left <= 0 )
$class = 'expired';
if ( 'expired' == $data['status'] ) {
$class = 'expired';
$remaining = '&nbsp;';
}
$status = ucfirst( $class );
if ( ++$count % 2 ) {
$class .= ' alt';
}
$check_id = "cb-select-{$data['package']}";
$checked = ( in_array( $data['package'], $post_data['packages'] ) ) ? ' checked' : '';
?>
<tr class="<?php echo $class; ?>">
<th class="check-column" scope="row">
<label class="screen-reader-text" for="<?php echo $check_id; ?>"><?php printf( __( 'Select %s' ), $name ); ?></label>
<label for="<?php echo $check_id; ?>">
<input id="<?php echo $check_id ?>" name="packages[]" value="<?php echo $data['package']; ?>" type="checkbox"<?php echo $checked; ?>>
</label>
</th>
<td>
<label for="<?php echo $check_id; ?>"><?php echo $name; ?></label>
</td>
<td><?php echo $data['user']; ?></td>
<td><?php echo $status; ?></td>
<td><?php echo $expiration; ?></td>
<td><?php echo $remaining; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<td colspan="6">
<input type="text" name="it-updater-username" placeholder="iThemes Username" value="<?php echo esc_attr( $post_data['username'] ); ?>" autocomplete="off" />
<input type="password" name="it-updater-password" placeholder="Password" value="<?php echo esc_attr( $post_data['password'] ); ?>" />
<input class="button-primary" type="submit" name="submit" value="<?php _e( 'Remove Licenses', 'rcp-rest' ); ?>" />
<input type="hidden" name="action" value="unlicense_packages" />
</td>
</tr>
</tfoot>
</table>
</div>
</form>
<?php
}
private function list_unlicensed_products( $products, $post_data, $action ) {
if ( empty( $products ) )
return;
uksort( $products, 'strnatcasecmp' );
if ( ( 'license_packages' != $action ) || empty( $this->errors ) ) {
$post_data = array(
'username' => '',
'password' => '',
'packages' => array(),
);
foreach ( $products as $name => $data )
$post_data['packages'][] = $data['package'];
}
?>
<form id="posts-filter" enctype="multipart/form-data" method="post" action="<?php echo $this->self_url; ?>" autocomplete="off">
<?php wp_nonce_field( 'license_packages', 'ithemes_updater_nonce' ); ?>
<div class="ithemes-updater-products" id="ithemes-updater-unlicensed">
<h3 class="subtitle"><?php _e( 'Unlicensed Products', 'rcp-rest' ); ?></h3>
<p><?php _e( 'The following products have not been licensed. Licensing a product gives you access to automatic updates from within WordPress.', 'rcp-rest' ); ?></p>
<p><?php _e( 'To license products, select the products you wish to license, enter your iThemes membership username and password, and press the License Products button.', 'rcp-rest' ); ?></p>
<p><?php printf( __( 'Need help? <a href="%s">Click here for a quick video tutorial</a>.', 'rcp-rest' ), 'http://ithemes.com/2013/04/11/introducing-the-new-and-improved-ithemes-licensing-system/' ); ?></p>
<table class="ithemes-updater-listing widefat">
<thead>
<tr>
<th id="cb" class="manage-column column-cb check-column" scope="col">
<label class="screen-reader-text" for="cb-select-all-2"><?php _e( 'Select All' ); ?></label>
<label>
<input id="cb-select-all-2" type="checkbox"<?php if ( count( $post_data['packages'] ) == count( $products ) ) echo ' checked'; ?> />
</label>
</th>
<th scope="col">
<label for="cb-select-all-2"><?php _e( 'Product', 'rcp-rest' ); ?></label>
</th>
</tr>
</thead>
<tbody>
<?php $count = 0; ?>
<?php foreach ( $products as $name => $data ) : ?>
<?php
$check_id = "cb-select-{$data['package']}";
if ( 'license_packages' == $action )
$checked = ( in_array( $data['package'], $post_data['packages'] ) ) ? ' checked' : '';
else
$checked = ' checked';
if ( ++$count % 2 ) {
$class = 'alt';
} else {
$class = '';
}
?>
<tr class="<?php echo $class; ?>">
<th class="check-column" scope="row">
<label class="screen-reader-text" for="<?php echo $check_id; ?>"><?php printf( __( 'Select %s' ), $name ); ?></label>
<label for="<?php echo $check_id; ?>">
<input id="<?php echo $check_id; ?>" name="packages[]" value="<?php echo $data['package']; ?>" type="checkbox" <?php echo $checked; ?>>
</label>
</th>
<td>
<label for="<?php echo $check_id; ?>"><?php echo $name; ?></label>
</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<td colspan="2">
<input type="text" name="it-updater-username" placeholder="iThemes Username" value="<?php echo esc_attr( $post_data['username'] ); ?>" autocomplete="off" />
<input type="password" name="it-updater-password" placeholder="Password" value="<?php echo esc_attr( $post_data['password'] ); ?>" />
<input class="button-primary" type="submit" name="submit" value="<?php _e( 'License Products', 'rcp-rest' ); ?>" />
<input type="hidden" name="action" value="license_packages" />
</td>
</tr>
</tfoot>
</table>
</div>
</form>
<?php
}
private function list_unrecognized_products( $products ) {
if ( empty( $products ) )
return;
uksort( $products, 'strnatcasecmp' );
?>
<div class="ithemes-updater-products" id="ithemes-updater-unrecognized">
<h3 class="subtitle"><?php _e( 'Unrecognized Products', 'rcp-rest' ); ?></h3>
<p><?php _e( 'The following products were not recognized by the licensing system. This can be due to a bug in the product code, a temporary server issue, or because the product is no longer supported.', 'rcp-rest' ); ?></p>
<p><?php printf( __( 'Please check this page again at a later time to see if the problem resolves itself. If the product remains, please contact <a href="%s">iThemes support</a> and provide them with the details given below.', 'rcp-rest' ), 'http://ithemes.com/support/' ); ?></p>
<table class="ithemes-updater-listing widefat">
<thead>
<tr>
<th scope="col"><?php _e( 'Product', 'rcp-rest' ); ?></th>
<th scope="col"><?php _e( 'Type', 'rcp-rest' ); ?></th>
<th scope="col"><?php _e( 'Package', 'rcp-rest' ); ?></th>
<th scope="col"><?php _e( 'Version', 'rcp-rest' ); ?></th>
<th scope="col"><?php _e( 'Server Response', 'rcp-rest' ); ?></th>
</tr>
</thead>
<tbody>
<?php $count = 0; ?>
<?php foreach ( $products as $name => $data ) : ?>
<?php
if ( ( isset( $data['status'] ) && 'error' == $data['status'] ) && ( ! empty( $data['error']['message'] ) ) )
$response = "{$data['error']['message']} ({$data['error']['code']})";
else
$response = __( 'Unknown Error', 'rcp-rest' );
if ( ++$count % 2 ) {
$class = 'alt';
} else {
$class = '';
}
?>
<tr class="<?php echo $class; ?>">
<td><?php echo $name; ?></td>
<td><?php echo $data['type']; ?></td>
<td><?php echo $data['package']; ?></td>
<td><?php echo $data['installed']; ?></td>
<td><?php echo $response; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php
}
public function show_licensed_site_url_confirmation_page( $post_data = array() ) {
$this->show_notices();
$site_url = $GLOBALS['ithemes-updater-settings']->get_licensed_site_url();
if ( empty( $site_url ) ) {
$site_url = network_home_url();
}
if ( empty( $post_data['username'] ) || empty( $this->errors ) ) {
$post_data['username'] = '';
}
if ( empty( $post_data['password'] ) || empty( $this->errors ) ) {
$post_data['password'] = '';
}
if ( ! empty( $post_data['redirect'] ) ) {
$redirect = $post_data['redirect'];
} else if ( ! empty( $_GET['redirect'] ) ) {
$redirect = $_GET['redirect'];
} else {
$redirect = '';
}
?>
<div class="wrap" id="ithemes-updater-site-url-confirmation">
<span class="ithemes-updater-header"></span>
<h2><?php _e( 'Licensing', 'rcp-rest' ); ?></h2>
<p><?php _e( "Please confirm this site's licensed URL.", 'rcp-rest' ); ?></p>
<form id="posts-filter" enctype="multipart/form-data" method="post" action="<?php echo $this->self_url; ?>">
<?php wp_nonce_field( 'save_licensed_site_url', 'ithemes_updater_nonce' ); ?>
<div id="ithemes-updater-settings">
<div id="ithemes-updater-table-wrapper">
<table class="form-table">
<tbody>
<tr valign="top">
<th scope="row">
<label for="site_url"><?php _e( 'Licensed URL', 'rcp-rest' ); ?></label>
<?php if ( is_multisite() ) : ?>
<p class="description"><?php _e( 'The Licensed URL should be the primary URL of this WordPress network.', 'rcp-rest' ); ?></p>
<p class="description ithemes-updater-description-warning"><?php _e( 'If not set correctly, some features may not function as expected.', 'rcp-rest' ); ?></p>
<?php else : ?>
<p class="description"><?php _e( 'The Licensed URL should be the primary URL of this WordPress site.', 'rcp-rest' ); ?></p>
<p class="description ithemes-updater-description-warning"><?php _e( 'If not set correctly, some features may not function as expected.', 'rcp-rest' ); ?></p>
<?php endif; ?>
</th>
<td>
<label>
<input id="site_url" class="regular-text" type="text" name="site_url" value="<?php echo esc_attr( $site_url ); ?>" />
</label>
</td>
</tr>
</tbody>
</table>
</div>
<p class="submit">
<input id="save_licensed_site_url" class="button button-primary" type="submit" value="<?php _e( 'Save', 'rcp-rest' ); ?>" />
<input type="hidden" name="action" value="save_licensed_site_url" />
<input type="hidden" name="redirect" value="<?php echo esc_attr( $redirect ); ?>" />
</p>
</div>
</form>
</div>
<?php
}
private function save_licensed_site_url( $data ) {
check_admin_referer( 'save_licensed_site_url', 'ithemes_updater_nonce' );
if ( empty( $data['site_url'] ) ) {
$this->errors[] = __( 'The licensed URL cannot be blank.', 'rcp-rest' );
} else if ( false === filter_var( $data['site_url'], FILTER_VALIDATE_URL ) ) {
$this->errors[] = __( 'The licensed URL must be a valid URL.', 'rcp-rest' );
}
if ( ! empty( $this->errors ) ) {
$this->show_licensed_site_url_confirmation_page( $data );
return;
}
$site_url = $GLOBALS['ithemes-updater-settings']->get_site_url( $data['site_url'] );
if ( $this->has_license_keys() ) {
$site_url_from_server = $GLOBALS['ithemes-updater-settings']->get_licensed_site_url_from_server();
if ( $site_url_from_server !== $site_url ) {
$data['site_url'] = $site_url;
$this->show_relicensing_page( $data );
return;
}
}
$GLOBALS['ithemes-updater-settings']->set_licensed_site_url( $site_url );
$this->messages[] = __( 'Successfully set the Licensed URL.', 'rcp-rest' );
if ( empty( $data['redirect'] ) ) {
$redirect = admin_url( 'options-general.php?page=ithemes-licensing&updated_url=true' );
} else {
$redirect = $data['redirect'];
}
echo '<input id="ithemes-updater-redirect-to-url" type="hidden" value="' . esc_attr( $redirect ) . '" />' . "\n";
$this->list_packages();
}
public function show_relicensing_page( $data = array() ) {
$this->show_notices();
$site_url_from_server = $GLOBALS['ithemes-updater-settings']->get_licensed_site_url_from_server();
if ( empty( $data['relicense_option'] ) ) {
$data['relicense_option'] = 'relicense';
}
if ( empty( $data['username'] ) ) {
$data['username'] = '';
}
if ( empty( $data['password'] ) ) {
$data['password'] = '';
}
?>
<div class="wrap" id="ithemes-updater-relicense">
<span class="ithemes-updater-header"></span>
<h2><?php _e( 'Licensing', 'rcp-rest' ); ?></h2>
<p><?php printf( __( 'The licenses on this site are for <code>%s</code>.', 'rcp-rest' ), $site_url_from_server ); ?></p>
<form id="posts-filter" enctype="multipart/form-data" method="post" action="<?php echo $this->self_url; ?>">
<?php wp_nonce_field( 'relicense', 'ithemes_updater_nonce' ); ?>
<div id="ithemes-updater-settings">
<div id="ithemes-updater-table-wrapper">
<table class="form-table">
<tbody>
<tr valign="top">
<th scope="row">
<label for="relicense_option">
<?php _e( 'License Option', 'rcp-rest' ); ?>
</label>
</th>
<td>
<p>
<label>
<input type="radio" name="relicense_option" value="relicense" <?php if ( 'relicense' === $data['relicense_option'] ) echo 'checked="checked"'; ?> />
<?php _e( 'Create new licenses for this site.', 'rcp-rest' ); ?>
</label>
</p>
<p class="description ithemes-updater-description-warning"><?php _e( 'Use this option if this site was cloned from another site and needs to have its own licenses.', 'rcp-rest' ); ?></p>
<br />
<p>
<label>
<input type="radio" name="relicense_option" value="update" <?php if ( 'update' === $data['relicense_option'] ) echo 'checked="checked"'; ?> />
<?php printf( __( 'Change the existing licenses to be for <code>%s</code>.', 'rcp-rest' ), $data['site_url'] ); ?>
</label>
</p>
<p class="description ithemes-updater-description-notice">
<span class="dashicons dashicons-warning"></span>
<?php printf( __( 'Note: If the <code>%s</code> site still exists and is different from this site, you will have to create new licenses on that site.', 'rcp-rest' ), $data['site_url'], $site_url_from_server ); ?>
</p>
<p class="description ithemes-updater-description-warning"><?php printf( __( 'Use this option if this site\'s primary URL has changed from <code>%1$s</code> to <code>%2$s</code>.', 'rcp-rest' ), $site_url_from_server, $data['site_url'] ); ?></p>
</td>
</tr>
<tr valign="top">
<th scope="row" colspan="2">
<label for="it-updater-username"><?php _e( 'iThemes Username', 'rcp-rest' ); ?></label>
<br />
<input id="it-updater-username" type="text" name="it-updater-username" value="<?php echo esc_attr( $data['username'] ); ?>" />
</th>
</tr>
<tr valign="top">
<th scope="row" colspan="2">
<label for="it-updater-password"><?php _e( 'iThemes Password', 'rcp-rest' ); ?></label>
<br />
<input id="it-updater-password" type="password" name="it-updater-password" value="<?php echo esc_attr( $data['password'] ); ?>" />
</th>
</tr>
</tbody>
</table>
</div>
<p class="submit">
<input id="relicense" class="button button-primary" type="submit" value="<?php _e( 'Save', 'rcp-rest' ); ?>" />
<input type="hidden" name="action" value="relicense" />
<input type="hidden" name="site_url" value="<?php echo esc_attr( $data['site_url'] ); ?>" />
<input type="hidden" name="redirect" value="<?php echo esc_attr( $data['redirect'] ); ?>" />
</p>
</div>
</form>
</div>
<?php
}
private function relicense( $data ) {
check_admin_referer( 'relicense', 'ithemes_updater_nonce' );
if ( empty( $data['username'] ) && empty( $data['password'] ) ) {
$this->errors[] = __( 'You must supply an iThemes membership username and password in order to change the licensed URL.', 'rcp-rest' );
} else if ( empty( $data['username'] ) ) {
$this->errors[] = __( 'You must supply an iThemes membership username in order to change the licensed URL.', 'rcp-rest' );
} else if ( empty( $data['password'] ) ) {
$this->errors[] = __( 'You must supply an iThemes membership password in order to change the licensed URL.', 'rcp-rest' );
} else if ( empty( $data['site_url'] ) ) {
$this->errors[] = __( 'The licensed URL cannot be blank.', 'rcp-rest' );
} else if ( false === filter_var( $data['site_url'], FILTER_VALIDATE_URL ) ) {
$this->errors[] = __( 'The licensed URL must be a valid URL.', 'rcp-rest' );
} else if ( empty( $data['relicense_option'] ) || ! in_array( $data['relicense_option'], array( 'relicense', 'update' ) ) ) {
$this->errors[] = __( 'You must pick one of the License Option options.', 'rcp-rest' );
}
if ( ! empty( $this->errors ) ) {
$this->show_relicensing_page( $data );
return;
}
if ( 'update' === $data['relicense_option'] ) {
$response = Ithemes_Updater_API::set_licensed_site_url( $data['username'], $data['password'], $data['site_url'] );
if ( is_wp_error( $response ) ) {
$this->errors[] = Ithemes_Updater_API::get_error_explanation( $response );
$this->show_relicensing_page( $data );
return;
}
$GLOBALS['ithemes-updater-settings']->set_licensed_site_url( $data['site_url'] );
$this->messages[] = __( 'Successfully updated the Licensed URL.', 'rcp-rest' );
} else {
require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
$keys = Ithemes_Updater_Keys::get();
$packages = array_keys( $keys );
$response = Ithemes_Updater_API::deactivate_package( $data['username'], $data['password'], $packages );
if ( is_wp_error( $response ) ) {
$this->errors[] = Ithemes_Updater_API::get_error_explanation( $response );
$this->show_relicensing_page( $data );
return;
}
$GLOBALS['ithemes-updater-settings']->set_licensed_site_url( $data['site_url'] );
$this->messages[] = __( 'Successfully updated the Licensed URL.', 'rcp-rest' );
$response = Ithemes_Updater_API::activate_package( $data['username'], $data['password'], $packages );
if ( is_wp_error( $response ) ) {
$this->errors[] = Ithemes_Updater_API::get_error_explanation( $response );
$this->show_relicensing_page( $data );
return;
}
}
if ( empty( $data['redirect'] ) ) {
$redirect = admin_url( 'options-general.php?page=ithemes-licensing&updated_url=true' );
} else {
$redirect = $data['redirect'];
}
echo '<input id="ithemes-updater-redirect-to-url" type="hidden" value="' . esc_attr( $redirect ) . '" />' . "\n";
$this->list_packages();
return;
}
private function show_notices() {
if ( ! empty( $this->messages ) ) {
foreach ( $this->messages as $message ) {
echo "<div class=\"updated fade\"><p><strong>$message</strong></p></div>\n";
}
}
if ( ! empty( $this->errors ) ) {
foreach ( $this->errors as $error ) {
echo "<div class=\"error\"><p><strong>$error</strong></p></div>\n";
}
}
if ( ! empty( $this->soft_errors ) ) {
foreach ( $this->soft_errors as $error ) {
echo "<div class=\"error\"><p><strong>$error</strong></p></div>\n";
}
}
}
private function get_expiration_string( $expiration_timestamp ) {
$time = time();
$time_left = $expiration_timestamp - $time;
$expired = false;
if ( $time_left < 0 ) {
$expired = true;
$time_left = abs( $time_left );
}
if ( $time_left > ( 86400 * 30 ) )
$expiration = date( 'Y-m-d', $expiration_timestamp );
else {
if ( $time_left > 86400 )
$expiration = sprintf( _n( '%d day', '%d days', intval( $time_left / 86400 ), 'rcp-rest' ), intval( $time_left / 86400 ) );
else if ( $time_left > 3600 )
$expiration = sprintf( _n( '%d hour', '%d hours', intval( $time_left / 3600 ), 'rcp-rest' ), intval( $time_left / 3600 ) );
else if ( $time_left > 60 )
$expiration = sprintf( _n( '%d minute', '%d minutes', intval( $time_left / 60 ), 'rcp-rest' ), intval( $time_left / 60 ) );
else
$expiration = sprintf( _n( '%d second', '%d seconds', $time_left, 'rcp-rest' ), intval( $time_left / 60 ) );
if ( $expired )
$expiration = sprintf( __( '%s ago', 'rcp-rest' ), $expiration );
}
return $expiration;
}
private function has_license_keys() {
require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
$keys = Ithemes_Updater_Keys::get();
$legacy_keys = Ithemes_Updater_Keys::get_legacy();
if ( empty( $keys ) && empty( $legacy_keys ) ) {
return false;
}
return true;
}
}
new Ithemes_Updater_Settings_Page();

View File

@@ -0,0 +1,490 @@
<?php
/*
Central management of options storage and registered packages.
Written by Chris Jean for iThemes.com
Version 1.3.0
Version History
1.0.0 - 2013-09-19 - Chris Jean
Split off from the old Ithemes_Updater_Init class.
1.0.1 - 2013-09-20 - Chris Jean
Fixed bug where the old ithemes-updater-object global was being referenced.
1.1.0 - 2013-10-04 - Chris Jean
Enhancement: Added handler for GET query variable: ithemes-updater-force-minor-update.
Bug Fix: Changed URL regex for applying the CA patch to only apply to links for api.ithemes.com and not the S3 links.
Bug Fix: A check to ensure that the $GLOBALS['ithemes_updater_path'] variable is set properly.
Misc: Updated file reference for ca/cacert.crt to ca/roots.crt.
1.2.0 - 2013-10-23 - Chris Jean
Enhancement: Added the quick_releases setting.
Enhancement: Added an explicit flush when the ithemes-updater-force-minor-update query variable is used
Misc: Removed the show_on_sites setting as it is no longer needed.
1.3.0 - 2014-10-23 - Chris Jean
Improved flushing system.
Reduced cache timeout durations.
Added timeout multiplier.
Removed CA patch code as it's now handled in the server code.
Updated code to meet WordPress coding standards.
*/
class Ithemes_Updater_Settings {
private $option_name = 'ithemes-updater-cache';
private $packages = array();
private $new_packages = array();
private $options = false;
private $options_modified = false;
private $do_flush = false;
private $initialized = false;
private $plugins_cleaned = false;
private $themes_cleaned = false;
private $db_failure = false;
private $default_options = array(
'timeout-multiplier' => 1,
'expiration' => 0,
'timestamp' => 0,
'packages' => array(),
'update_plugins' => array(),
'update_plugins_no_update' => array(),
'update_themes' => array(),
'update_themes_no_update' => array(),
'use_ca_patch' => false,
'use_ssl' => true,
'quick_releases' => false,
);
public function __construct() {
$GLOBALS['ithemes-updater-settings'] = $this;
add_action( 'init', array( $this, 'init' ) );
add_action( 'shutdown', array( $this, 'shutdown' ), -10 );
}
public function init() {
if ( $this->initialized ) {
return;
}
$this->initialized = true;
if ( ! isset( $GLOBALS['ithemes_updater_path'] ) ) {
$GLOBALS['ithemes_updater_path'] = dirname( __FILE__ );
}
$this->load();
do_action( 'ithemes_updater_register', $this );
$this->new_packages = array_diff( array_keys( $this->packages ), $this->options['packages'] );
if ( isset( $_GET['ithemes-updater-force-quick-release-update'] ) && ! isset( $_GET['ithemes-updater-force-minor-update'] ) ) {
$_GET['ithemes-updater-force-minor-update'] = $_GET['ithemes-updater-force-quick-release-update'];
}
$flushed = false;
if ( isset( $_GET['ithemes-updater-force-minor-update'] ) && current_user_can( 'manage_options' ) ) {
if ( $_GET['ithemes-updater-force-minor-update'] ) {
$this->options['force_minor_version_update'] = time() + 3600;
$this->update_options( $this->options );
$this->flush( 'forced minor version update' );
$flushed = true;
} else {
unset( $this->options['force_minor_version_update'] );
$this->update_options( $this->options );
$this->flush( 'unset forced minor version update' );
$flushed = true;
}
} else if ( isset( $this->options['force_minor_version_update'] ) && ( $this->options['force_minor_version_update'] < time() ) ) {
unset( $this->options['force_minor_version_update'] );
$this->update_options( $this->options );
}
if ( ! $flushed ) {
if ( ! empty( $_GET['ithemes-updater-force-refresh'] ) && current_user_can( 'manage_options' ) ) {
$this->flush( 'forced' );
} else if ( empty( $this->options['expiration'] ) || ( $this->options['expiration'] <= time() ) ) {
$this->flush( 'expired' );
} else if ( $this->is_expired( $this->options['timestamp'] ) ) {
$this->flush( 'got stale' );
} else if ( ! empty( $this->new_packages ) ) {
$this->flush( 'new packages' );
}
}
}
public function load() {
if ( false !== $this->options ) {
return;
}
require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
$this->options = Ithemes_Updater_Functions::get_site_option( $this->option_name );
if ( false === $this->options ) {
$this->db_failure = true;
}
if ( ! is_array( $this->options ) ) {
$this->options = array();
}
$this->options = array_merge( $this->default_options, $this->options );
if ( 0 == $this->options['timestamp'] ) {
$this->update();
}
$this->update_site_url_history();
}
public function shutdown() {
$this->flush();
if ( $this->options_modified && false === $this->db_failure ) {
update_site_option( $this->option_name, $this->options );
}
}
public function queue_flush() {
$this->do_flush = true;
}
public function flush( $reason = '' ) {
if ( empty( $reason ) && ! $this->do_flush ) {
return;
}
$this->do_flush = false;
$this->update();
}
public function update() {
$this->init();
require_once( $GLOBALS['ithemes_updater_path'] . '/updates.php' );
Ithemes_Updater_Updates::run_update();
}
public function get_options() {
$this->init();
return $this->options;
}
public function get_option( $var ) {
$this->init();
if ( isset( $this->options[$var] ) ) {
return $this->options[$var];
}
return null;
}
public function update_options( $updates ) {
$this->init();
$this->options = array_merge( $this->options, $updates );
$this->options_modified = true;
}
public function update_packages() {
$this->update_options( array( 'packages' => array_keys( $this->packages ) ) );
}
public function get_packages() {
return $this->packages;
}
public function get_new_packages() {
return $this->new_packages;
}
public function filter_update_plugins( $update_plugins ) {
if ( ! is_object( $update_plugins ) ) {
return $update_plugins;
}
if ( ! isset( $update_plugins->response ) || ! is_array( $update_plugins->response ) ) {
$update_plugins->response = array();
}
if ( ! isset( $update_plugins->no_update ) || ! is_array( $update_plugins->no_update ) ) {
$update_plugins->no_update = array();
}
$this->flush();
if ( ! is_array( $this->options ) || ! isset( $this->options['update_plugins'] ) ) {
$this->load();
}
if ( isset( $this->options['update_plugins'] ) && is_array( $this->options['update_plugins'] ) ) {
if ( ! $this->plugins_cleaned ) {
@include_once( ABSPATH . '/wp-admin/includes/plugin.php' );
if ( is_callable( 'get_plugin_data' ) ) {
foreach ( $this->options['update_plugins'] as $plugin => $update_data ) {
if ( ! is_file( WP_PLUGIN_DIR . "/$plugin" ) ) {
continue;
}
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . "/$plugin", false, false );
if ( $plugin_data['Version'] == $update_data->new_version ) {
unset( $this->options['update_plugins'][$plugin] );
$update_data_array = (array) $update_data;
$update_data_array['icons'] = array();
$update_data_array['banners'] = array();
$update_data_array['banners_rtl'] = array();
$update_data_array['tested'] = '';
$update_data_array['requires_php'] = '';
$update_data_array['compatibility'] = new stdClass();
$this->options['update_plugins_no_update'][$plugin] = (object) $update_data_array;
$this->plugins_cleaned = true;
}
}
}
if ( $this->plugins_cleaned ) {
$this->options_modified = true;
}
$this->plugins_cleaned = true;
}
$update_plugins->response = array_merge( $update_plugins->response, $this->options['update_plugins'] );
$update_plugins->no_update = array_merge( $update_plugins->no_update, $this->options['update_plugins_no_update'] );
}
return $update_plugins;
}
public function filter_update_themes( $update_themes ) {
if ( ! is_object( $update_themes ) ) {
return $update_themes;
}
if ( ! isset( $update_themes->response ) || ! is_array( $update_themes->response ) ) {
$update_themes->response = array();
}
if ( ! isset( $update_themes->no_update ) || ! is_array( $update_themes->no_update ) ) {
$update_themes->no_update = array();
}
$this->flush();
if ( ! is_array( $this->options ) || ! isset( $this->options['update_themes'] ) ) {
$this->load();
}
if ( isset( $this->options['update_themes'] ) && is_array( $this->options['update_themes'] ) ) {
if ( ! $this->themes_cleaned ) {
foreach ( $this->options['update_themes'] as $theme => $update_data ) {
$theme_data = wp_get_theme( $theme );
if ( $theme_data->get( 'Version' ) === $update_data['new_version'] ) {
unset( $this->options['update_themes'][$theme] );
$update_data['requires'] = '';
$update_data['requires_php'] = '';
$this->options['update_themes_no_update'][$theme] = $update_data;
$this->themes_cleaned = true;
}
}
if ( $this->themes_cleaned ) {
$this->options_modified = true;
}
$this->themes_cleaned = true;
}
$update_themes->response = array_merge( $update_themes->response, $this->options['update_themes'] );
$update_themes->no_update = array_merge( $update_themes->no_update, $this->options['update_themes_no_update'] );
}
return $update_themes;
}
public function register( $slug, $file ) {
$this->packages[$slug][] = $file;
}
private function is_expired( $timestamp ) {
$multiplier = $this->get_option( 'timeout-multiplier' );
if ( $multiplier < 1 ) {
$multiplier = 1;
} else if ( $multiplier > 10 ) {
$multiplier = 10;
}
if ( current_user_can( 'update_themes' ) || current_user_can( 'update_plugins' ) ) {
if ( ! empty( $_POST['action'] ) && ( 'heartbeat' == $_POST['action'] ) ) {
$timeout = 43200;
} else {
$page = empty( $_GET['page'] ) ? $GLOBALS['pagenow'] : $_GET['page'];
switch ( $page ) {
case 'update.php' :
case 'update-core.php' :
case 'ithemes-licensing' :
$timeout = 60;
break;
case 'plugins.php' :
case 'themes.php' :
$timeout = 600;
break;
default :
$timeout = 3600;
}
}
} else {
$timeout = 7200;
}
$timeout *= $multiplier;
if ( $timestamp <= ( time() - $timeout ) ) {
return true;
}
return false;
}
/*
public function get_hostname_history() {
$this->get_canonical_hostname();
return $this->options['hostname_details']['history'];
}
public function get_canonical_hostname() {
if ( ! is_array( $this->options ) ) {
$this->load();
}
$hostname = $this->get_hostname();
if ( ! isset( $this->options['hostname_details'] ) || ! is_array( $this->options['hostname_details'] ) ) {
$this->options['hostname_details'] = array();
$this->options_modified = true;
}
if ( empty( $this->options['hostname_details']['canonical'] ) ) {
$this->options['hostname_details']['canonical'] = $hostname;
$this->options_modified = true;
}
if ( empty( $this->options['hostname_details']['history'] ) || ! is_array( $this->options['hostname_details']['history'] ) || ( time() - max( $this->options['hostname_details']['history'] ) > 600 ) ) {
$this->options['hostname_details']['history'][$hostname] = time();
$this->options_modified = true;
}
return $this->options['hostname_details']['canonical'];
}
public function update_canonical_hostname( $hostname ) {
$this->options['hostname_details']['canonical'] = $this->get_hostname( $hostname );
$this->options_modified = true;
}
*/
public function update_site_url_history() {
$site_url = $this->get_site_url();
if ( ! isset( $this->options['site_url_history'] ) || ! is_array( $this->options['site_url_history'] ) ) {
$this->options['site_url_history'] = array();
$this->options_modified = true;
}
if ( empty( $this->options['site_url_history'] ) || ! is_array( $this->options['site_url_history'] ) || ( time() - max( $this->options['site_url_history'] ) > 600 ) ) {
$this->options['site_url_history'][$site_url] = time();
$this->options_modified = true;
}
}
public function get_site_url( $url = false ) {
if ( empty( $url ) ) {
$url = network_home_url();
}
$url = strtolower( preg_replace( '|/$|', '', $url ) );
if ( is_ssl() ) {
$url = preg_replace( '|^https?:|', 'https:', $url );
} else {
$url = preg_replace( '|^https?:|', 'http:', $url );
}
return $url;
}
public function is_request_on_licensed_site_url() {
return $this->get_licensed_site_url() === $this->get_site_url();
}
public function get_licensed_site_url_from_server() {
$response = Ithemes_Updater_API::get_licensed_site_url();
if ( ! is_wp_error( $response ) && is_array( $response ) && ! empty( $response['site_url'] ) ) {
return $this->get_site_url( "http://{$response['site_url']}" );
}
return '';
}
public function set_licensed_site_url( $url ) {
$url = $this->get_site_url( $url );
$url = preg_replace( '|^https?://|', '', $url );
$this->options['site_url'] = $url;
$this->options_modified = true;
}
public function get_licensed_site_url() {
if ( ! is_array( $this->options ) ) {
$this->load();
}
if ( empty( $this->options['site_url'] ) ) {
return false;
} else {
return $this->get_site_url( "http://{$this->options['site_url']}" );
}
}
public function is_licensed_site_url_confirmed() {
if ( false === $this->get_licensed_site_url() ) {
return false;
} else {
return true;
}
}
}
new Ithemes_Updater_Settings();

View File

@@ -0,0 +1,191 @@
<?php
/*
Provides a simple interface for connecting iThemes' packages with the updater API.
Written by Chris Jean for iThemes.com
Version 1.4.1
Version History
1.0.0 - 2013-04-11 - Chris Jean
Release ready
1.0.1 - 2013-09-19 - Chris Jean
Changed the logic in process_server_response to skip updatable packages that have the 'upgrade' data set to a true value.
Updated requires to not use dirname().
Updated ithemes-updater-object to ithemes-updater-settings.
1.1.0 - 2013-10-02 - Chris Jean
Updated 'url' data for themes to point to the plugin-install.php file in order to show changelog notes as plugins have.
1.2.0 - 2013-10-04 - Chris Jean
Added logic to handle skipped updates when force_minor_version_update is set.
1.2.1 - 2013-10-04 - Chris Jean
Added a fix to prevent the code from executing if it is loaded by an older updater version. This can happen when updating a theme or plugin.
1.3.0 - 2013-10-23 - Chris Jean
Enhancement: Added support for quick_releases setting to force an update to a quick release.
1.4.0 - 2014-11-13 - Chris Jean
Improved cache flush handling.
Removed server-cache setting change handler.
Added timeout-multiplier setting change handler.
1.4.1 - 2015-04-23 - Chris Jean
Added "plugin" entry for plugins in order to handle changes in WordPress 4.2.
Added "theme" entry for themes in order to handle changes in WordPress 4.2.
Added support for both "autoupdate" and "upgrade_notice" fields to be supplied from the server.
*/
class Ithemes_Updater_Updates {
public static function run_update() {
// Prevent the code from running if the code was loaded by an older updater version.
if ( ! isset( $GLOBALS['ithemes_updater_path'] ) ) {
return;
}
require_once( $GLOBALS['ithemes_updater_path'] . '/api.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
$keys = Ithemes_Updater_Keys::get();
$legacy_keys = Ithemes_Updater_Keys::get_legacy();
if ( empty( $keys ) && empty( $legacy_keys ) ) {
return;
}
Ithemes_Updater_API::get_package_details( false );
}
public static function process_server_response( $response, $cached = false ) {
if ( empty( $response['packages'] ) ) {
return;
}
require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
$keys = array();
foreach ( $response['packages'] as $package => $data ) {
if ( isset( $data['key'] ) ) {
$keys[$package] = $data['key'];
} else if ( isset( $data['status'] ) && ( 'inactive' == $data['status'] ) ) {
$keys[$package] = '';
}
}
Ithemes_Updater_Keys::set( $keys );
$details = Ithemes_Updater_Packages::get_full_details( $response );
$updates = array(
'update_themes' => array(),
'update_themes_no_update' => array(),
'update_plugins' => array(),
'update_plugins_no_update' => array(),
'expiration' => $details['expiration'],
);
if ( ! $cached ) {
$updates['timestamp'] = time();
}
if ( isset( $response['timeout_multiplier'] ) ) {
$updates['timeout-multiplier'] = $response['timeout_multiplier'];
}
if ( ! isset( $updates['timeout-multiplier'] ) || ( $updates['timeout-multiplier'] < 1 ) ) {
$updates['timeout-mulitplier'] = 1;
} else if ( $updates['timeout-multiplier'] > 10 ) {
$updates['timeout-mulitplier'] = 10;
}
$use_ssl = $GLOBALS['ithemes-updater-settings']->get_option( 'use_ssl' );
foreach ( $details['packages'] as $path => $data ) {
if ( empty( $data['package-url'] ) ) {
continue;
}
$force_minor_version_update = $GLOBALS['ithemes-updater-settings']->get_option( 'force_minor_version_update' );
$quick_releases = $GLOBALS['ithemes-updater-settings']->get_option( 'quick_releases' );
$update_available = true;
if ( version_compare( $data['installed'], $data['available'], '>=' ) ) {
$update_available = false;
} else if ( ( isset( $data['upgrade'] ) && ! $data['upgrade'] ) && ! $force_minor_version_update && ! $quick_releases ) {
$update_available = false;
}
if ( ! $use_ssl ) {
$data['package-url'] = preg_replace( '/^https/', 'http', $data['package-url'] );
}
if ( 'plugin' == $data['type'] ) {
$update = array(
'id' => 0,
'slug' => dirname( $path ),
'plugin' => $path,
'new_version' => $data['available'],
'url' => $data['info-url'],
'package' => $data['package-url'],
);
if ( $update_available ) {
if ( isset( $data['autoupdate'] ) ) {
$update['autoupdate'] = $data['autoupdate'];
}
if ( isset( $data['upgrade_notice'] ) ) {
$update['upgrade_notice'] = $data['upgrade_notice'];
}
} else {
$update['icons'] = array();
$update['banners'] = array();
$update['banners_rtl'] = array();
$update['tested'] = '';
$update['requires_php'] = '';
$update['compatibility'] = new stdClass();
}
$update = (object) $update;
}
else {
$update = array(
'theme' => $path,
'new_version' => $data['available'],
'url' => self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . dirname( $path ) . '&section=changelog&TB_iframe=true&width=600&height=800' ),
'package' => $data['package-url'],
);
if ( $update_available ) {
if ( isset( $data['autoupdate'] ) ) {
$update['autoupdate'] = $data['autoupdate'];
}
if ( isset( $data['upgrade_notice'] ) ) {
$update['upgrade_notice'] = $data['upgrade_notice'];
}
} else {
$update['requires'] = '';
$update['requires_php'] = '';
}
$path = dirname( $path );
}
if ( $update_available ) {
$updates["update_{$data['type']}s"][$path] = $update;
} else {
$updates["update_{$data['type']}s_no_update"][$path] = $update;
}
}
$GLOBALS['ithemes-updater-settings']->update_options( $updates );
}
}

View File

@@ -0,0 +1,339 @@
<?php
/**
* Manage licensing of iThemes plugins and themes.
*/
final class Ithemes_Updater_WP_CLI_Ithemes_Licensing extends WP_CLI_Command {
/**
* Show iThemes plugins and themes on the site and the licensing status for each.
*
* ## OPTIONS
*
* [<product>]
* : Only show the status for the supplied product.
*
* [--verbose]
* : Show increased detail about each product.
*
* [--status=<status>]
* : Limit the list to products with a specific licensing status.
* ---
* default: all
* options:
* - all
* - active
* - inactive
*
* [--format=<format>]
* : Output formatting
* ---
* default: table
* options:
* - table
* - json
* - csv
* - yaml
* - count
*
* @param array $args
* @param array $assoc_args
*/
public function show( $args, $assoc_args ) {
$this->verify_updater_is_present();
require_once( $GLOBALS['ithemes_updater_path'] . '/api.php' );
if ( ! empty( $args ) ) {
list( $product ) = $args;
} else {
$product = null;
}
$default_args = array(
'verbose' => false,
'status' => 'all',
'format' => 'table',
);
$assoc_args = wp_parse_args( $assoc_args, $default_args );
$package_details = Ithemes_Updater_API::get_package_details();
if ( is_wp_error( $package_details ) ) {
WP_CLI::error( sprintf( 'Unable to retrieve product details: %1$s (%2$s)', $package_details->get_error_message(), $package_details->get_error_code() ) );
return;
}
ksort( $package_details['packages'] );
$packages = array();
foreach ( $package_details['packages'] as $name => $details ) {
if ( ! is_null( $product ) && $name !== $product ) {
continue;
}
if ( ! isset( $details['status'] ) ) {
$details['status'] = 'inactive';
}
if ( 'all' !== $assoc_args['status'] && $details['status'] !== $assoc_args['status'] ) {
continue;
}
$package = array(
'name' => $name,
'status' => isset( $details['status'] ) ? $details['status'] : 'inactive',
);
if ( $assoc_args['verbose'] ) {
$package = array_merge( $package, $details );
}
$packages[] = $package;
}
if ( ! empty( $packages ) ) {
if ( $assoc_args['verbose'] ) {
$columns = array(
'name',
'status',
'used',
'total',
'ver',
'user',
'sub_expire',
'release_timestamp',
'upgrade',
'link_expire',
'link',
'key',
'error',
);
} else {
$columns = array(
'name',
'status',
);
}
foreach ( $packages as &$package ) {
foreach ( $columns as $column ) {
if ( ! isset( $package[$column] ) ) {
$package[$column] = '';
}
}
}
WP_CLI\Utils\format_items( $assoc_args['format'], $packages, $columns );
} else if ( $assoc_args['verbose'] ) {
WP_CLI::error( 'No iThemes products were found matching the current criteria.' );
}
}
/**
* Activate licensing for one or more products
*
* ## OPTIONS
*
* Specificy the iThemes account username and password using the environment variables ITHEMES_USER and ITHEMES_PASS
*
* [<product>...]
* : Product to activate licensing for.
*
* [--ithemes-user=<user>]
* : iThemes member username. This value can also be supplied by an ITHEMES_USER environment variable.
*
* [--ithemes-pass=<pass>]
* : iThemes member password. This value can also be supplied by an ITHEMES_PASS environment variable.
*
* [--all]
* : Activate licensing for all currently installed, inactive products.
*
* ## EXAMPLES
*
* # Activate licensing for the ithemes-security-pro plugin.
* $ wp ithemes-licensing activate ithemes-security-pro --ithemes-user=example --ithemes-pass=example
*
* # Activate licensing for all installed iThemes products using environment variables for member details.
* $ ITHEMES_USER=example ITHEMES_PASS=example wp ithemes-licensing activate --all
*
* @param array $args
* @param array $assoc_args
*/
public function activate( $args, $assoc_args ) {
$this->handle_request( 'activate', $args, $assoc_args );
}
/**
* Deactivate licensing for one or more products
*
* ## OPTIONS
*
* Specificy the iThemes account username and password using the environment variables ITHEMES_USER and ITHEMES_PASS
*
* [<product>...]
* : Product to deactivate licensing for.
*
* [--ithemes-user=<user>]
* : iThemes member username. This value can also be supplied by an ITHEMES_USER environment variable.
*
* [--ithemes-pass=<pass>]
* : iThemes member password. This value can also be supplied by an ITHEMES_PASS environment variable.
*
* [--all]
* : Deactivate licensing for all currently installed, active products.
*
* ## EXAMPLES
*
* # Deactivate licensing for the ithemes-security-pro plugin.
* $ wp ithemes-licensing deactivate ithemes-security-pro --ithemes-user=example --ithemes-pass=example
*
* # Deactivate licensing for all installed iThemes products using environment variables for member details.
* $ ITHEMES_USER=example ITHEMES_PASS=example wp ithemes-licensing deactivate --all
*
* @param array $args
* @param array $assoc_args
*/
public function deactivate( $args, $assoc_args ) {
$this->handle_request( 'deactivate', $args, $assoc_args );
}
private function handle_request( $verb, $args, $assoc_args ) {
$this->verify_updater_is_present();
require_once( $GLOBALS['ithemes_updater_path'] . '/api.php' );
require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
$products = $args;
$default_args = array(
'all' => false,
);
$assoc_args = wp_parse_args( $assoc_args, $default_args );
$user = getenv( 'ITHEMES_USER' );
$pass = getenv( 'ITHEMES_PASS' );
if ( isset( $assoc_args['ithemes-user'] ) ) {
$user = $assoc_args['ithemes-user'];
}
if ( isset( $assoc_args['ithemes-pass'] ) ) {
$pass = $assoc_args['ithemes-pass'];
}
if ( empty( $user ) ) {
WP_CLI::error( 'You must supply the iThemes member username.' );
return;
}
if ( empty( $pass ) ) {
WP_CLI::error( 'You must supply the iThemes member password.' );
return;
}
if ( empty( $products ) && ! $assoc_args['all'] ) {
WP_CLI::error( "You must supply one or more products or use the --all flag." );
return;
} else if ( ! empty( $products ) && $assoc_args['all'] ) {
WP_CLI::error( 'You must supply one or more products or use the --all flag, but not both.' );
return;
}
$package_details = Ithemes_Updater_API::get_package_details();
if ( $assoc_args['all'] ) {
if ( is_wp_error( $package_details ) ) {
WP_CLI::error( sprintf( 'Unable to retrieve product details: %1$s (%2$s)', $package_details->get_error_message(), $package_details->get_error_code() ) );
return;
}
$products = array();
foreach ( $package_details['packages'] as $name => $details ) {
if ( 'activate' === $verb xor ( isset( $details['status'] ) && 'active' === $details['status'] ) ) {
$products[] = $name;
}
}
if ( empty( $products ) ) {
if ( 'activate' === $verb ) {
WP_CLI::success( 'No products with inactive licensing were found.' );
} else {
WP_CLI::success( 'No products with active licensing were found.' );
}
return;
}
} else {
foreach ( $products as $index => $product ) {
if ( ! isset( $package_details['packages'][$product] ) ) {
WP_CLI::error( "$product is not a valid iThemes product. Licensing for it cannot be {$verb}d." );
unset( $products[$index] );
}
}
if ( empty( $products ) ) {
return;
}
}
if ( 'activate' === $verb ) {
$response = Ithemes_Updater_API::activate_package( $user, $pass, $products );
} else {
$response = Ithemes_Updater_API::deactivate_package( $user, $pass, $products );
}
if ( is_wp_error( $response ) ) {
WP_CLI::error( Ithemes_Updater_API::get_error_explanation( $response ) );
return;
}
if ( empty( $response['packages'] ) ) {
if ( 1 === count( $products ) ) {
WP_CLI::error( "An unknown server error occurred. Please try to $verb your product license again at another time." );
} else {
WP_CLI::error( "An unknown server error occurred. Please try to $verb your product licenses again at another time." );
}
return;
}
uksort( $response['packages'], 'strnatcasecmp' );
foreach ( $response['packages'] as $package => $data ) {
if ( preg_match( '/ \|\|\| \d+$/', $package ) ) {
continue;
}
if ( 'activate' === $verb ) {
if ( ! empty( $data['key'] ) ) {
WP_CLI::success( "Activated the product license for $package." );
} else if ( ! empty( $data['status'] ) && ( 'expired' === $data['status'] ) ) {
WP_CLI::warning( "Unable to activate the product license for $package. Your product subscription has expired." );
} else {
WP_CLI::error( "Unable to activate the product license for $package. {$data['error']['message']}" );
}
} else {
if ( isset( $data['status'] ) && ( 'inactive' == $data['status'] ) ) {
WP_CLI::success( "Deactivated the product license for $package." );
} else if ( isset( $data['error'] ) && isset( $data['error']['message'] ) ) {
WP_CLI::error( "Unable to deactivate the product license for $package. {$data['error']['message']}" );
} else {
WP_CLI::error( "Unable to deactivate the product license for $package. Unknown server error." );
}
}
}
}
private function verify_updater_is_present() {
if ( empty( $GLOBALS['ithemes_updater_path'] ) ) {
if ( defined( 'ITHEMES_UPDATER_DISABLE' ) && ITHEMES_UPDATER_DISABLE ) {
WP_CLI::error( 'The iThemes updater library is disabled on this site due to the ITHEMES_UPDATER_DISABLE define being set to a truthy value. Licensing for this site cannot be managed.' );
} else {
WP_CLI::error( 'The $GLOBALS[\'ithemes_updater_path\'] variable is empty or not set. This indicates that the updater was not loaded although the cause for this is not known.' );
}
exit;
}
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* Plugin Name: Restrict Content Pro - REST API
* Plugin URI: http://restrictcontentpro.com/addons/rest-api
* Description: Adds a REST API to Restrict Content Pro
* Author: Sandhills Development, LLC
* Author URI: https://sandhillsdev.com
* Version: 1.2.2
* Text Domain: rcp-rest
* Domain Path: languages
* iThemes Package: rcp-rest-api
*/
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
final class RCP_REST_API {
/**
* @var RCP_REST_API The one true RCP_REST_API
* @since 1.0
*/
private static $instance;
/**
* @var $path The plugin directory path
* @since 1.0
*/
public static $path;
/**
* @var $routes The API routes
* @since 1.0
*/
public static $routes;
/**
* Main RCP_REST_API Instance.
*
* Insures that only one instance of RCP_REST_API exists in memory at any one
* time. Also prevents needing to define globals all over the place.
*
* @since 1.0
* @static
* @return RCP_REST_API The one true RCP_REST_API
*/
public static function instance() {
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof RCP_REST_API ) ) {
self::$path = plugin_dir_path( __FILE__ );
self::$instance = new RCP_REST_API;
self::$instance->text_domain();
self::$instance->updater();
self::$instance->includes();
self::$routes = new RCP_REST_API_Routes;
}
return self::$instance;
}
/**
* Throw error on object clone.
*
* The whole idea of the singleton design pattern is that there is a single
* object therefore, we don't want the object to be cloned.
*
* @since 1.0
* @access public
* @return void
*/
public function __clone() {
// Cloning instances of the class is forbidden.
_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'rcp-rest' ), '1.0' );
}
/**
* Disable unserializing of the class.
*
* @since 1.0
* @access public
* @return void
*/
public function __wakeup() {
// Unserializing instances of the class is forbidden.
_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'rcp-rest' ), '1.0' );
}
/**
* Load our textdomain
*
* @since 1.0
* @access public
* @return void
*/
public function text_domain() {
// Set filter for plugin's languages directory
$lang_dir = dirname( plugin_basename( __FILE__ ) ) . '/languages/';
$lang_dir = apply_filters( 'rcp_rest_languages_directory', $lang_dir );
// Traditional WordPress plugin locale filter
$locale = apply_filters( 'plugin_locale', get_locale(), 'rcp-rest' );
$mofile = sprintf( '%1$s-%2$s.mo', 'rcp-rest', $locale );
// Setup paths to current locale file
$mofile_local = $lang_dir . $mofile;
$mofile_global = WP_LANG_DIR . '/rcp/' . $mofile;
if ( file_exists( $mofile_global ) ) {
// Look in global /wp-content/languages/rcp folder
load_textdomain( 'rcp-rest', $mofile_global );
} elseif ( file_exists( $mofile_local ) ) {
// Look in local /wp-content/plugins/restrict-content-pro/languages/ folder
load_textdomain( 'rcp-rest', $mofile_local );
} else {
// Load the default language files
load_plugin_textdomain( 'rcp-rest', false, $lang_dir );
}
}
/**
* Load our plugin updater
*
* @since 1.0
* @access public
* @return void
*/
public function updater() {
if( is_admin() && class_exists( 'RCP_Add_On_Updater' ) ) {
$updater = new RCP_Add_On_Updater( 389, __FILE__, '1.2.2' );
}
}
/**
* Load our files
*
* @since 1.0
* @access public
* @return void
*/
public function includes() {
require_once self::$path . 'includes/class-routes.php';
require_once self::$path . 'includes/class-level.php';
require_once self::$path . 'includes/class-member.php';
require_once self::$path . 'includes/class-payment.php';
}
}
/**
* Load the REST API after other plugins are loaded
*
* @since 1.0
* @access public
* @return RCP_REST_API
*/
function rcp_rest_api() {
if( ! function_exists( 'rcp_is_active' ) ) {
return false;
}
return RCP_REST_API::instance();
}
add_action( 'plugins_loaded', 'rcp_rest_api' );
if ( ! function_exists( 'ithemes_repository_name_updater_register' ) ) {
function ithemes_repository_name_updater_register( $updater ) {
$updater->register( 'rcp-rest-api', __FILE__ );
}
add_action( 'ithemes_updater_register', 'ithemes_repository_name_updater_register' );
require( __DIR__ . '/lib/updater/load.php' );
}