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,352 @@
<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-dashboard
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden!
}
/**
* Class TD_TTW_Connection
*
* This is a twin of TPM_Connection from thrive product manager
* Since we can't rely on TPM existence on client site we have to implement connection logic here
* We will use the same db data from TPM, if any
*
* @property int ttw_id
* @property string ttw_salt
* @property string ttw_email
* @property string status
* @property string ttw_expiration datetime until the current connection is known by TTW; ttw_salt has to be refreshed after this date;
* @static new TD_TTW_Connection get_instance
*/
class TD_TTW_Connection {
use TD_Magic_Methods;
use TD_Singleton;
use TD_TTW_Utils;
const CONNECTED = 'connected';
const NAME = 'tpm_connection';
const SIGNATURE = 's6!xv(Q7Zp234L_snodt]CvG2meROk0Gurc49KiyJzz6kSjqAyqpUL&9+P4s';
protected $_errors = array();
protected $_messages = array();
protected $_expected_data
= array(
'ttw_id',
'ttw_email',
'ttw_salt',
'ttw_expiration',
);
private function __construct() {
$this->_data = get_option( static::NAME, array() );
}
public function is_connected() {
return static::CONNECTED === $this->status;
}
/**
* Disconnect ttw account
*/
public function disconnect() {
delete_option( static::NAME );
thrive_delete_transient( TD_TTW_User_Licenses::NAME );
thrive_delete_transient( 'td_ttw_connection_error' );
}
public function get_login_url() {
return add_query_arg(
array(
'callback_url' => urlencode( base64_encode( $this->get_callback_url() ) ),
'td_site' => base64_encode( get_site_url() ),
),
static::get_ttw_url() . '/connect-account/'
);
}
/**
* URL where user is redirected back after he logs in TTW
*
* @return string
*/
protected function get_callback_url() {
$url = admin_url( 'admin.php?page=tve_dash_ttw_account' );
return add_query_arg(
array(
'td_token' => base64_encode( $this->get_token() ),
),
$url
);
}
/**
* Get signature token, if none create one
*
* @return mixed|string
*/
public function get_token() {
$token = get_option( 'tpm_token', null );
if ( ! empty( $token ) ) {
return $this->decrypt( $token );
}
$rand_nr = mt_rand( 1, 11 );
$rand_chars = '^!#)_@%*^@(yR&dsYh';
$rand_string = substr( str_shuffle( $rand_chars ), 0, $rand_nr );
$token = $rand_string . strrev( base_convert( bin2hex( hash( 'sha512', uniqid( mt_rand() . microtime( true ) * 10000, true ), true ) ), 16, 36 ) );
$to_length = ceil( strlen( $token ) / 2 );
$token = $rand_nr . substr( $token, mt_rand( 1, 9 ), $to_length );
add_option( 'tpm_token', $this->encrypt( $token ) );
return $token;
}
/**
* Encrypt a given string
*
* @param string $str
*
* @return string
*/
public function encrypt( $str ) {
$str .= '-' . static::SIGNATURE;
$str = base64_encode( $str );
return $str;
}
/**
* Decrypt a given string
*
* @param string $str
*
* @return mixed|string
*/
public function decrypt( $str ) {
$str = base64_decode( $str );
$str = explode( '-', $str );
return $str[0];
}
/**
* If environment is on a staging server
*
* @return bool
*/
public static function is_debug_mode() {
return ( defined( 'TD_TTW_DEBUG' ) && TD_TTW_DEBUG ) || ! empty( $_REQUEST['td_debug'] );
}
/**
* @return string
*/
public static function get_ttw_url() {
if ( defined( 'TTW_URL' ) ) {
return trim( TTW_URL, '/' );
}
if ( static::is_debug_mode() ) {
return get_option( 'tpm_ttw_url', 'https://staging.thrivethemes.com' );
}
return 'https://thrivethemes.com';
}
public function get_email() {
return $this->ttw_email;
}
public function get_disconnect_url() {
$url = admin_url( 'admin.php?page=tve_dash_ttw_account' );
$url = add_query_arg( array( 'td_disconnect' => 1 ), $url );
return $url;
}
/**
* Render ttw connection screen
*
* @param false $return
*
* @return false|string
*/
public function render( $return = false ) {
ob_start();
include $this->path( 'templates/header.phtml' );
if ( count( $this->_errors ) ) {
include $this->path( 'templates/connection/error.phtml' );
} else {
include $this->path( 'templates/connection/form.phtml' );
}
include $this->path( 'templates/debugger.phtml' );
$html = ob_get_clean();
if ( true === $return ) {
return $html;
}
echo $html; // phpcs:ignore
}
protected function _is_valid_token( $token ) {
$tpm_token = get_option( 'tpm_token', null );
return $this->decrypt( $tpm_token ) === $token;
}
/**
* Check if data is as expected
*
* @param $data array
*
* @return bool
*/
protected function _is_valid_data( $data ) {
if ( ! is_array( $data ) ) {
return false;
}
$keys = array_intersect( array_keys( $data ), $this->_expected_data );
return $keys === $this->_expected_data;
}
/**
* Add a new message in list to be displayed
*
* @param string $str
* @param string $status
*/
public function push_message( $str, $status ) {
$str = __( $str, 'thrive-dash' );
$this->_messages[] = array(
'message' => $str,
'status' => $status,
);
update_option( 'tpm_connection_messages', $this->_messages );
}
/**
* Process the request
* Validate it and sve the connection into DB
*
* @return bool
*/
public function process_request() {
if ( ! empty( $_REQUEST['td_token'] ) && ! $this->_is_valid_token( base64_decode( sanitize_text_field( $_REQUEST['td_token'] ) ) ) ) {
$this->_errors[] = __( 'Invalid token', 'thrive-dash' );
return false;
}
$data = $this->_read_data();
if ( ! $this->_is_valid_data( $data ) ) {
$this->_errors[] = __( 'Invalid data', 'thrive-dash' );
return false;
}
return $this->_save_connection( $data );
}
/**
* @param $data
*
* @return bool
*/
protected function _save_connection( $data ) {
$data['status'] = static::CONNECTED;
$this->_data = $data;
update_option( static::NAME, $data );
/* always delete the stored license details transient when a new connection is made */
thrive_delete_transient( TD_TTW_User_Licenses::NAME );
return true;
}
/**
* Reads expected data from request
*
* @return array
*/
protected function _read_data() {
$data = array();
$no_decode = array(
'ttw_salt',
);
foreach ( $this->_expected_data as $key ) {
//this has to be in clear; not encoded
if ( in_array( $key, $no_decode, false ) ) {
$data[ $key ] = ! empty( $_REQUEST[ $key ] ) ? sanitize_text_field( $_REQUEST[ $key ] ) : '';
continue;
}
if ( ! empty( $_REQUEST[ $key ] ) ) {
$data[ $key ] = base64_decode( urldecode( sanitize_text_field( $_REQUEST[ $key ] ) ) );
}
}
return $data;
}
public function get_connection_data() {
return [
'user_id' => $this->ttw_id,
'ttw_auth' => $this->ttw_salt,
'email' => $this->ttw_email,
'referrer' => base64_encode( get_site_url() ),
];
}
}

View File

@@ -0,0 +1,224 @@
<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-dashboard
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden
}
/**
* @property int id
* @property int status
* @property string name
* @property string state
* @property string expiration
* @property string refund_date
* @property array tags
* @property boolean can_update
* @property int grace_period_in_days
* @property boolean in_grace_period
* @property boolean complementary
*
* Representation of a single user license
* Class TD_TTW_License
*/
class TD_TTW_License {
use TD_Magic_Methods;
const MEMBERSHIP_TAG = 'all';
const REFUNDED_STATUS = 3;
private $_expected_fields = [
'id',
'status',
'name',
'state',
'tags',
'expiration',
'refund_date',
'can_update',
'mm_product_id',
'grace_period_in_days',
'in_grace_period',
'complementary',
];
public function __construct( $data ) {
foreach ( $this->_expected_fields as $field ) {
if ( isset( $data[ $field ] ) ) {
$this->_data[ $field ] = $data[ $field ];
}
}
}
/**
* Check if the license is active
*
* @return bool
*/
public function is_active() {
return in_array(
(int) $this->status,
array(
1, // active
9, // pending cancellation
),
true
) || $this->complementary === true;
}
/**
* Check if the license is expired
*
* @return bool
*/
public function is_expired() {
try {
return new DateTime( 'now' ) > $this->get_expiration_date();
} catch ( Exception $e ) {
return true;
}
}
/**
* @return DateTime
* @throws Exception
*/
public function get_expiration_date() {
return new DateTime( $this->expiration );
}
/**
* @return DateTime
* @throws Exception
*/
public function get_grace_period_date() {
return $this->get_expiration_date()->add( new DateInterval( 'P' . (int) $this->grace_period_in_days . 'D' ) );
}
/**
* Checks if a license is expired and expiration date + grace period in days in the future
*
* @return bool
*/
public function is_in_grace_period() {
if ( $this->is_active() ) {
return false;
}
try {
$date = $this->get_expiration_date();
$date->add( new DateInterval( 'P' . (int) $this->grace_period_in_days . 'D' ) );
return new DateTime( 'now' ) < $date;
} catch ( Exception $e ) {
return false;
}
}
/**
* @return bool
* @throws Exception
*/
public function is_out_of_grace_period() {
return $this->is_expired() && ! $this->is_in_grace_period();
}
/**
* @return string
*/
public function get_name() {
return $this->name;
}
/**
* @return string
*/
public function get_expiration() {
return $this->expiration;
}
/**
* Check if the user has access to updates on this license
*
* @return bool
*/
public function can_update() {
return true === $this->can_update;
}
/**
* @return bool
*/
public function is_membership() {
return in_array( self::MEMBERSHIP_TAG, $this->tags, true );
}
/**
* @return DateInterval
* @throws Exception
*/
public function get_remaining_grace_period() {
try {
return ( new DateTime( 'now' ) )->diff( $this->get_grace_period_date() );
} catch ( Exception $e ) {
return new DateInterval( 'P0D' );
}
}
/**
* @return string
*/
public function get_product_name() {
if ( $this->is_membership() ) {
return 'membership';
}
return implode( ',', $this->tags );
}
public function get_state() {
return $this->state;
}
public function is_refunded() {
return self::REFUNDED_STATUS === (int) $this->status;
}
public function get_refunded_date() {
return $this->refund_date;
}
/**
* Checks if tags list contains the $tag
*
* @param $tag
*
* @return bool
*/
public function has_tag( $tag ) {
return in_array( $tag, $this->tags, true );
}
/**
* License data
*
* @return array|mixed
*/
public function get_data() {
return $this->_data;
}
}

View File

@@ -0,0 +1,168 @@
<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-dashboard
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden
}
/**
* Handles update related messages across wp-admin
*
* Class TD_TTW_Messages_Manager
*/
class TD_TTW_Messages_Manager {
use TD_Singleton;
use TD_TTW_Utils;
private function __construct() {
/** @var TD_TTW_User_Licenses $licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
if ( $licenses->get_membership() && ! $licenses->get_membership()->can_update() ) {
//add_action( 'admin_notices', array( __CLASS__, 'inactive_membership' ) );
}
}
/**
* Render a message from templates/messages/ directory
* First param should be template name
* Second whether or not to echo/return the output
* Third an array with needed vars in template
*
* @return false|string
*/
public static function render() {
$args = func_get_args();
$template = ! empty( $args[0] ) ? $args[0] : null;
if ( empty( $template ) ) {
return false;
}
$action = ! empty( $args[1] ) && 1 === (int) $args[1] ? 'return' : 'echo';
$vars = ! empty( $args[2] ) && is_array( $args[2] ) ? $args[2] : array();
/**
* Prepare variables names for template file
* $key => var name
* $value => var value
*/
foreach ( $vars as $key => $value ) {
$$key = $value;
}
ob_start();
include self::path( 'templates/messages/' . $template . '.phtml' );
$html = ob_get_clean();
if ( 'return' === $action ) {
return $html;
}
echo $html; //phpcs:ignore
}
/**
* Show license related notices in wp dash
*/
public static function inactive_membership() {
/** @var TD_TTW_User_Licenses $licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
$membership = $licenses->get_membership();
if ( ! $membership ) {
return;
}
if ( TD_TTW_Connection::get_instance()->is_connected() ) {
$tpl = 'expired-connected';
} else {
$tpl = 'expired-disconnected';
}
self::render(
$tpl,
false,
array(
'membership_name' => $membership->get_name(),
)
);
}
/**
* Get plugin update message
*
* @param stdClass $state
* @param array $plugin_data
*
* @return string|null
* - `` empty string means: no custom message is returned so let the UpdateChecker do its logic
* - `null` means that no license was fond for the plugin and no update should be provided by the UpdateChecker
*/
public static function get_update_message( $state, $plugin_data ) {
$message = '';
$template = null;
$template_data = array(
'state' => $state,
'plugin_data' => $plugin_data,
'recheck_url' => TD_TTW_User_Licenses::get_instance()->get_recheck_url(),
);
$plugin_tag = TVE_Dash_Product_LicenseManager::get_product_tag( $plugin_data['TextDomain'] );
if ( TVE_Dash_Product_LicenseManager::TPM_TAG === $plugin_tag ) {
return $message;
}
$is_connected = TD_TTW_Connection::get_instance()->is_connected();
if ( false === $is_connected ) {
$template = 'plugin/disconnected';
} else {
/** @var TD_TTW_User_Licenses $licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
$membership = $licenses->get_membership();
$license = $licenses->get_license( $plugin_tag );
if ( ( $membership && $membership->can_update() ) || ( $license && $license->can_update() ) ) {
return $message;
}
if ( $membership && false === $membership->can_update() ) {
$template = 'plugin/membership-expired';
} elseif ( null === $license && null === $membership ) {
$template = 'plugin/no-license-found';
} elseif ( $license && false === $license->can_update() ) {
$template = 'plugin/license-expired';
}
}
$error = thrive_get_transient( 'td_ttw_connection_error' );
if ( ! empty( $error ) ) {
$template = 'error';
$template_data['error_message'] = $error;
}
if ( $template ) {
$message = static::render(
$template,
true,
$template_data
);
}
return $message;
}
}
TD_TTW_Messages_Manager::get_instance();

View File

@@ -0,0 +1,132 @@
<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-dashboard
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden!
}
/**
* Class TD_TTW_Proxy_Request
* Decorator for TD_TTW_Request
*/
class TD_TTW_Proxy_Request {
const URL = 'https://service-api.thrivethemes.com';
const API_PASS = '!!@#ThriveIsTheBest123$$@#';
const API_KEY = '@(#$*%)^SDFKNgjsdi870234521SADBNC#';
protected $secret_key = '@#$()%*%$^&*(#@$%@#$%93827456MASDFJIK3245';
/** @var TD_TTW_Request */
protected $request;
/**
* TD_TTW_Proxy_Request constructor.
*
* @param TD_TTW_Request $request
*/
public function __construct( TD_TTW_Request $request ) {
$this->request = $request;
}
/**
* Execute the request
*
* @param string $route
*
* @return array|WP_Error
*/
public function execute( $route ) {
// Allow bypassing proxy server
if ( defined( 'TPM_BYPASS_PROXY' ) && TPM_BYPASS_PROXY ) {
return $this->request->execute();
}
$params = array(
'body' => $this->request->get_body(),
'headers' => $this->request->get_headers(),
'url' => $this->request->get_url(),
'pw' => self::API_PASS,
);
$headers = array(
'X-Thrive-Authenticate' => $this->_build_auth_string( $params ),
);
$args = array(
'headers' => $headers,
'body' => $params,
'timeout' => 30,
'sslverify' => false,
);
$url = add_query_arg(
array(
'p' => $this->_calc_hash( $params ),
),
trim( $this->_get_url(), '/' ) . '/' . ltrim( $route, '/' )
);
$response = wp_remote_post( $url, $args );
if ( is_wp_error( $response ) ) {
$args['sslverify'] = true;
$response = wp_remote_post( $url, $args );
return $response;
}
return $response;
}
/**
* @return string
*/
protected function _get_url() {
if ( defined( 'TPM_DEBUG' ) && TPM_DEBUG === true && defined( 'TVE_CLOUD_URL' ) ) {
return TVE_CLOUD_URL;
}
return self::URL;
}
/**
* @param array $params
*
* @return string
*/
protected function _calc_hash( $params ) {
return md5( $this->secret_key . serialize( $params ) . $this->secret_key );
}
/**
* Create an auth string fro the request
*
* @param null $data
*
* @return string
*/
protected function _build_auth_string( $data = null ) {
$string = '';
foreach ( $data as $field => $value ) {
if ( is_array( $value ) ) {
$value = serialize( $value );
}
$string .= $field . '=' . $value;
$string .= '|' . self::API_KEY . '|';
}
return md5( $string );
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-dashboard
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden!
}
class TD_TTW_Request {
protected $url;
protected $args
= array(
'headers' => array(
'Content-Type' => 'application/json',
),
'timeout' => 20,
);
protected $params = array();
protected $route;
/**
* TD_TTW_Request constructor.
*
* @param string $route
* @param array $params
*/
public function __construct( $route, $params ) {
$this->route = $route;
$this->params = $params;
$this->url = TD_TTW_Connection::get_ttw_url();
}
/**
* Execute the request
*
* @return array|WP_Error
*/
public function execute() {
$this->args['body'] = $this->get_body();
return wp_remote_post( $this->get_url(), $this->args );
}
/**
* @return false|string
*/
public function get_body() {
return json_encode( $this->params );
}
/**
* @return array
*/
public function get_params() {
return $this->params;
}
/**
* @param string $name
* @param string $value
*/
public function set_header( $name, $value ) {
$this->args['headers'][ $name ] = $value;
}
/**
* @return mixed
*/
public function get_headers() {
return $this->args['headers'];
}
/**
* @return string
*/
public function get_url() {
return trim( $this->url, '/' ) . '/' . trim( $this->route, '/' );
}
}

View File

@@ -0,0 +1,454 @@
<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-dashboard
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden
}
class TD_TTW_Update_Manager {
use TD_Singleton;
use TD_TTW_Utils;
const NAME = 'tve_dash_ttw_account';
const SUITE_URL = 'https://thrivethemes.com/suite/';
const TTB_DOMAIN = 'thrive-theme';
/**
* @var array
*/
protected $_errors = array();
/**
* TD_TTW_Update_Manager constructor.
*/
private function __construct() {
$this->init();
}
public function init() {
$this->_includes();
$this->_actions();
}
/**
* Handler for tve_dash_ttw_account section
*/
public function tve_dash_ttw_account() {
if ( ! TD_TTW_Connection::get_instance()->is_connected() ) {
TD_TTW_Connection::get_instance()->render();
} else {
TD_TTW_User_Licenses::get_instance()->render();
}
}
/**
* Loads needed files
*/
private function _includes() {
require_once TVE_DASH_PATH . '/inc/ttw-account/classes/class-td-ttw-user-licenses.php';
require_once TVE_DASH_PATH . '/inc/ttw-account/classes/class-td-ttw-license.php';
require_once TVE_DASH_PATH . '/inc/ttw-account/classes/class-td-ttw-request.php';
require_once TVE_DASH_PATH . '/inc/ttw-account/classes/class-td-ttw-proxy-request.php';
require_once TVE_DASH_PATH . '/inc/ttw-account/classes/class-td-ttw-messages-manager.php';
}
/**
* Add needed action for ttw section
*/
private function _actions() {
add_action( 'admin_menu', array( $this, 'register_section' ), 10 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), PHP_INT_MAX );
add_action( 'current_screen', array( $this, 'try_process_connection' ) );
add_action( 'current_screen', array( $this, 'try_set_url' ) );
add_action( 'current_screen', array( $this, 'try_logout' ) );
add_action( 'admin_init', array( $this, 'ensure_license_details' ) );
add_filter( 'auto_update_plugin', array( $this, 'auto_update_plugin' ), 10, 2 );
add_filter( 'auto_update_theme', array( $this, 'auto_update_theme' ), 10, 2 );
add_filter( 'wp_prepare_themes_for_js', array( $this, 'wp_prepare_themes_for_js' ) );
add_filter( 'site_transient_update_themes', array( $this, 'hide_theme_updates' ), 10, 2 );
}
/**
* @param stdClass $transient
*
* @return stdClass
*/
public function hide_theme_updates( $transient ) {
if ( static::is_wp_core_update_screen() && false === static::has_access_to_updates( TD_TTW_User_Licenses::TTB_TAG ) ) {
unset( $transient->response[ self::TTB_DOMAIN ] );
}
return $transient;
}
/**
* Checks if there is a membership which can_update
* or check if there is a license with $tag which can_update
*
* On false - another logic for reason message has to be applied
*
* @param string $tag
*
* @return bool
*/
public static function has_access_to_updates( $tag ) {
$is_connected = TD_TTW_Connection::get_instance()->is_connected();
/** @var TD_TTW_User_Licenses $licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
$membership = $licenses->get_membership();
$has_valid_membership = $membership && true === $membership->can_update();
$ttb_license = $licenses->get_license( $tag );
$has_valid_license = $ttb_license && true === $ttb_license->can_update();
return $is_connected && ( $has_valid_membership || $has_valid_license );
}
/**
* @param array $themes
*
* @return array
*/
public function wp_prepare_themes_for_js( $themes ) {
$is_ttb_installed = isset( $themes[ self::TTB_DOMAIN ] );
$is_ttb_installed = $is_ttb_installed && is_array( $themes[ self::TTB_DOMAIN ] );
//ttb is installed and doesn't have access to updates
//then display update message - why it doesn't have access to updates
if ( true === $is_ttb_installed && false === static::has_access_to_updates( TD_TTW_User_Licenses::TTB_TAG ) ) {
$themes[ self::TTB_DOMAIN ]['hasPackage'] = 0;
$themes[ self::TTB_DOMAIN ]['update'] = $this->_get_theme_update_message( $themes[ self::TTB_DOMAIN ] );
}
return $themes;
}
/**
* @param array $data
*
* @return false|string|null
*/
private function _get_theme_update_message( $data ) {
if ( ! is_array( $data ) || empty( $data ) || ! current_user_can( 'update_themes' ) || is_multisite() ) {
return null;
}
$themes_update = get_site_transient( 'update_themes' );
if ( ! isset( $themes_update->response[ self::TTB_DOMAIN ] ) ) {
return null;
}
$themes_update = $themes_update->response[ self::TTB_DOMAIN ];
$details_url = add_query_arg(
array(
'TB_iframe' => 'true',
'width' => 1024,
'height' => 800,
),
$themes_update['url']
);
$template = 'theme/update';
$template_data = array(
'name' => $data['name'],
'version' => $themes_update['new_version'],
'details_url' => $details_url,
'recheck_url' => add_query_arg(
array(
'theme' => 'thrive-theme',
),
TD_TTW_User_Licenses::get_instance()->get_recheck_url( 'themes.php' )
),
);
$membership = static::get_membership();
/** @var TD_TTW_User_Licenses $licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
$theme_license = $licenses->get_license( TD_TTW_User_Licenses::TTB_TAG );
if ( false === TD_TTW_Connection::get_instance()->is_connected() ) {
$template = 'theme/disconnected';
} elseif ( $membership && false === $membership->is_active() ) {
$template = 'theme/membership-expired';
} elseif ( $theme_license && false === $theme_license->can_update() ) {
$template = 'theme/license-expired';
} elseif ( ! $membership && ! $theme_license ) {
$template = 'theme/no-license-found';
}
$error = thrive_get_transient( 'td_ttw_connection_error' );
if ( ! empty( $error ) ) {
$template = 'error';
$template_data['error_message'] = $error;
}
return TD_TTW_Messages_Manager::render(
$template,
true,
$template_data
);
}
/**
* @return TD_TTW_License|null
*/
public static function get_membership() {
return TD_TTW_User_Licenses::get_instance()->get_membership();
}
/**
* @return bool
*/
public static function allow_membership_updates() {
/** @var TD_TTW_Connection $connection */
$connection = TD_TTW_Connection::get_instance();
if ( ! $connection->is_connected() ) {
return false;
}
/** @var TD_TTW_User_Licenses $licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
return $licenses->get_membership() && $licenses->get_membership()->can_update();
}
/**
* Handle auto update plugin action
*
* @param bool $update
* @param object $item
*
* @return bool
*/
public function auto_update_plugin( $update, $item ) {
$doing_cron = apply_filters( 'wp_doing_cron', defined( 'DOING_CRON' ) && DOING_CRON );
$auto_update = doing_action( 'wp_maybe_auto_update' );
if ( ( ! $doing_cron && ! $auto_update ) || ! isset( $item->plugin ) ) {
return $update;
}
$file = wp_normalize_path( WP_PLUGIN_DIR . '/' . $item->plugin );
if ( ! is_file( $file ) ) {
return $update;
}
$plugin_data = get_plugin_data( $file );
if ( isset( $plugin_data['PluginURI'] ) && false !== strpos( $plugin_data['PluginURI'], 'thrivethemes.com' ) && ! self::allow_membership_updates() ) {
/* stop auto update only if the user doesn't have membership updates */
$update = false;
}
return $update;
}
/**
* Handle auto update theme action
*
* @param bool $update
* @param stdClass $item
*
* @return bool
*/
public function auto_update_theme( $update, $item ) {
$doing_cron = apply_filters( 'wp_doing_cron', defined( 'DOING_CRON' ) && DOING_CRON );
$auto_update = doing_action( 'wp_maybe_auto_update' );
$stop = ! $update || ( ! $doing_cron && ! $auto_update );
if ( ! $stop && isset( $item->theme ) && self::TTB_DOMAIN === $item->theme && ! self::allow_membership_updates() ) {
/* stop auto update if the user doesn't have membership updates */
$update = false;
}
return $update;
}
/**
* Ensure license details
*/
public function ensure_license_details() {
/** @var $connection TD_TTW_Connection */
$connection = TD_TTW_Connection::get_instance();
/** @var $licenses TD_TTW_User_Licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
if ( $connection->is_connected() && empty( $licenses->get() ) ) {
$licenses->get_licenses_details();
}
}
/**
* Check if current screen is wp bulk updates screen
*
* @return bool
*/
public static function is_wp_core_update_screen() {
global $current_screen;
return isset( $current_screen->id ) && 'update-core' === $current_screen->id;
}
/**
* Check if the updates should be available in WP Updates screen
*
* @return bool
*/
public static function can_see_updates() {
return false === static::is_wp_core_update_screen();
}
/**
* Register ttw section
*/
public function register_section() {
if ( empty( $_REQUEST['page'] ) || self::NAME !== $_REQUEST['page'] ) {
return;
}
add_submenu_page(
'',
'',
'',
'manage_options',
self::NAME,
array( $this, 'tve_dash_ttw_account' )
);
}
/**
* Process ttw connection
*/
public function try_process_connection() {
if ( ! $this->is_known_page() ) {
return;
}
/** @var $connection TD_TTW_Connection */
$connection = TD_TTW_Connection::get_instance();
if ( ! empty( $_REQUEST['td_token'] ) ) {
$processed = $connection->process_request();
if ( true === $processed ) {
/** @var $licenses TD_TTW_User_Licenses */
$licenses = TD_TTW_User_Licenses::get_instance();
$licenses->get_licenses_details(); //get licenses details
if ( $licenses->has_membership() && $licenses->is_membership_active() ) {
$connection->push_message( 'Your account has been successfully connected.', 'success' );
}
wp_redirect( $this->get_admin_url() );
die();
}
}
}
/**
* Log out ttw account
*/
public function try_logout() {
if ( ! $this->is_known_page() ) {
return;
}
if ( ! empty( $_REQUEST['td_disconnect'] ) ) {
/** @var TD_TTW_Connection $connection */
$connection = TD_TTW_Connection::get_instance();
$params = array(
'website' => get_site_url(),
);
$request = new TD_TTW_Request( '/api/v1/public/disconnect/' . $connection->ttw_id, $params );
$request->set_header( 'Authorization', $connection->ttw_salt );
$proxy_request = new TD_TTW_Proxy_Request( $request );
$proxy_request->execute( '/tpm/proxy' );
$connection->disconnect();
wp_redirect( admin_url( 'admin.php?page=' . TD_TTW_Update_Manager::NAME ) );
die;
}
}
public function try_set_url() {
if ( ! current_user_can( 'manage_options' ) || ! TD_TTW_Connection::is_debug_mode() || ! $this->is_known_page() ) {
return;
}
if ( ! empty( $_REQUEST['url'] ) && ! empty( $_REQUEST['td_action'] ) && sanitize_text_field( $_REQUEST['td_action'] ) === 'set_url' ) {
update_option( 'tpm_ttw_url', sanitize_url( $_REQUEST['url'] ) );
wp_redirect( $this->get_admin_url() );
die;
}
}
/**
* @return string|void
*/
public function get_admin_url() {
return admin_url( 'admin.php?page=' . self::NAME );
}
/**
* Enqueue scripts
*/
public function enqueue_scripts() {
if ( ! $this->is_known_page() ) {
return;
}
wp_enqueue_style( 'td-ttw-style', $this->url( 'css/admin.css' ), array(), uniqid() );
}
/**
* Check if the screen is ttw account screen
*
* @return bool
*/
public function is_known_page() {
return isset( $_REQUEST['page'] ) && self::NAME === $_REQUEST['page'];
}
}
TD_TTW_Update_Manager::get_instance();

View File

@@ -0,0 +1,555 @@
<?php
/**
* Thrive Themes - https://thrivethemes.com
*
* @package thrive-dashboard
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Silence is golden
}
/**
* Class TD_TTW_User_Licenses
* @static TD_TTW_User_Licenses get_instance
* @property string status
*/
class TD_TTW_User_Licenses {
use TD_Magic_Methods;
use TD_Singleton;
use TD_TTW_Utils;
const NAME = 'td_ttw_licenses_details';
const RECHECK_KEY = 'td_recheck_license';
const TTB_TAG = 'ttb';
const CACHE_LIFE_TIME = 28800; //8 hours
const CACHE_LIFE_TIME_SHORT = 28800; //30 minutes should be but for the moment we keep it 8 hours
private $_licenses_instances = array();
/**
* @var TD_TTW_License[]
*/
private $_active_licenses = array();
/**
* @var TD_TTW_License[]
*/
private $_in_grace_period_licenses = array();
/**
* @var TD_TTW_License[]
*/
private $_all_license_instances = array();
/**
* @var array|mixed - transient value before deleting the transient
*/
private $_tr_licenses;
private function __construct() {
$tr_licenses = array();
add_filter( 'option__thrive_tr_' . self::NAME, function ( $option_value ) use ( &$tr_licenses ) {
$tr_licenses = $option_value['value'];
return $option_value;
} );
$transient = thrive_get_transient( self::NAME );
$this->_tr_licenses = $tr_licenses;
$this->_data = $transient === false ? array() : $transient;
$this->_init_licenses_instances();
if ( ! empty( $_REQUEST[ self::RECHECK_KEY ] ) ) {
$this->recheck_license();
wp_redirect( $_SERVER['HTTP_REFERER'] );
die;
}
}
private function _init_licenses_instances() {
$this->_all_license_instances = array();
foreach ( (array) $this->_data as $item ) {
$license = new TD_TTW_License( $item );
$this->_all_license_instances[] = $license;
if ( $license->is_active() ) {
$this->_push( $license, 'active' );
} else if ( $license->is_in_grace_period() ) {
$this->_push( $license, 'in_grace_period' );
} else {
$this->_push( $license, 'expired' );
}
if ( ! empty( $item['tags'] ) && is_array( $item['tags'] ) ) {
foreach ( $item['tags'] as $tag ) {
/**
* There might be a cases where user has purchased the same license multiple times; e.g. Suit with tag: all
* TTW serves them all but those which can_update are first in the list
* So that, the last ones in the list which cannot_update do not overwrite those which can_update()
*/
if ( empty( $this->_licenses_instances[ $tag ] ) ) {
$this->_licenses_instances[ $tag ] = new TD_TTW_License( $item );
}
}
}
}
//membership license should be first in the list
usort( $this->_all_license_instances, static function ( $a, $b ) {
if ( $a->is_membership() && $b->is_membership() ) {
return 0;
}
return $a->is_membership() ? - 1 : 1;
} );
}
/**
* Push the license into a list
*
* @param TD_TTW_License $license
* @param string $list - expired, active, in_grace_period
*
* @return void
*/
private function _push( TD_TTW_License $license, string $list ) {
$allowed_lists = array( 'expired', 'active', 'in_grace_period' );
if ( ! in_array( $list, $allowed_lists, true ) ) {
$list = 'expired';
}
$arr = $this->{'_' . $list . '_licenses'};
foreach ( $license->tags as $tag ) {
$arr[ $tag ] = $license;
}
$this->{'_' . $list . '_licenses'} = $arr;
}
/**
* Check if the membership license is active
*
* @return bool
*/
public function is_membership_active() {
return $this->get_membership() && $this->get_membership()->is_active();
}
/**
* Get available licenses
*
* @return TD_TTW_License[]
*/
public function get() {
return $this->_licenses_instances;
}
/**
* Returns all licenses
*
* @return TD_TTW_License[]
*/
public function get_all(): array {
return $this->_all_license_instances;
}
/**
* Get all licenses that are expired or in grace period
*
* @return array
*/
public function get_inactive(): array {
return array_filter( $this->_all_license_instances, static function ( $license ) {
/** @var $license TD_TTW_License */
return $license->is_expired() || $license->is_in_grace_period();
} );
}
/**
* Check if a license exists by tag
*
* @param $tag
*
* @return bool
*/
public function has_license( $tag ): bool {
return isset( $this->_licenses_instances[ $tag ] );
}
/**
* Check if there is any membership license
*
* @return bool
*/
public function has_membership(): bool {
return $this->has_license( TD_TTW_License::MEMBERSHIP_TAG );
}
/**
* Returns a license which has 'all' in tags list
*
* @return TD_TTW_License|null
*/
public function get_membership() {
return $this->get_license( TD_TTW_License::MEMBERSHIP_TAG );
}
/**
* Checks if active licenses array has a [all] tag license
* @return TD_TTW_License|null
*/
public function get_active_membership_license() {
if ( ! empty( $this->_active_licenses['all'] ) && $this->_active_licenses['all'] instanceof TD_TTW_License ) {
return $this->_active_licenses['all'];
}
return null;
}
/**
* Checks if in grace period licenses array has a [all] tag license
* @return TD_TTW_License|null
*/
public function get_in_grace_period_membership() {
if ( ! empty( $this->_in_grace_period_licenses['all'] ) && $this->_in_grace_period_licenses['all'] instanceof TD_TTW_License ) {
return $this->_in_grace_period_licenses['all'];
}
return null;
}
/**
* Get license instance based on a tag
*
* @param string $tag
*
* @return TD_TTW_License|null
*/
public function get_license( $tag ) {
$license = null;
if ( isset( $this->_licenses_instances[ $tag ] ) ) {
$license = $this->_licenses_instances[ $tag ];
}
return $license;
}
/**
* Get license details
*
* @return array
*/
public function get_licenses_details() {
if ( ! TD_TTW_Connection::get_instance()->is_connected() ) {
return array();
}
$licenses_details = $this->_get_connection_licenses( TD_TTW_Connection::get_instance() );
$this->_data = $licenses_details;
$this->_init_licenses_instances();
return $licenses_details;
}
/**
* Recheck license details
*/
public function recheck_license() {
thrive_delete_transient( self::NAME );
remove_query_arg( self::RECHECK_KEY );
$this->get_licenses_details();
if ( $this->has_membership() && $this->is_membership_active() ) {
add_action( 'admin_notices', array( $this, 'success_notice' ) );
} else {
add_action( 'admin_notices', array( $this, 'fail_notice' ) );
}
}
public function success_notice() {
TD_TTW_Messages_Manager::render( 'success-notice' );
}
public function fail_notice() {
TD_TTW_Messages_Manager::render( 'expired-notice' );
}
/**
* Get recheck license url
*
* @return string
*/
public function get_recheck_url( $file = 'plugins.php' ) {
if ( isset( $_REQUEST['page'] ) && sanitize_text_field( $_REQUEST['page'] ) === TD_TTW_Update_Manager::NAME ) {
$url = ! empty( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( $_SERVER['REQUEST_URI'] ) : '';
} else {
$url = admin_url( $file );
}
return add_query_arg(
array(
TD_TTW_User_Licenses::RECHECK_KEY => 1,
),
$url
);
}
/**
* Render licenses screen
*
* @param false $return
*
* @return false|string
*/
public function render( $return = false ) {
ob_start();
include $this->path( 'templates/header.phtml' );
include $this->path( 'templates/licences/list.phtml' );
include $this->path( 'templates/debugger.phtml' );
$html = ob_get_clean();
if ( true === $return ) {
return $html;
}
echo $html; //phpcs:ignore
}
/**
* Based on current connection a request is made to TTW for assigned licenses
*
* @param TD_TTW_Connection $connection
*
* @return array
*/
protected function _get_connection_licenses( TD_TTW_Connection $connection ) {
if ( ! $connection->is_connected() ) {
return array();
}
$licenses = thrive_get_transient( self::NAME );
/* some sanity checks : there are cases when this is an array containing a single empty array. this IF identifies and corrects that case */
if ( is_array( $licenses ) && ! empty( $licenses ) && empty( array_filter( $licenses ) ) ) {
// force a re-fetch
$licenses = false;
}
if ( false !== $licenses ) {
return $licenses;
}
$params = array(
'user_id' => $connection->ttw_id,
'user_site_url' => get_site_url(),
);
$route = '/api/v1/public/get_licenses_details';
$request = new TD_TTW_Request( $route, $params );
$request->set_header( 'Authorization', $connection->ttw_salt );
$proxy_request = new TD_TTW_Proxy_Request( $request );
$response = $proxy_request->execute( '/tpm/proxy' );
$body = wp_remote_retrieve_body( $response );
$body = json_decode( $body, true );
$response_status_code = wp_remote_retrieve_response_code( $response );
if ( 200 !== $response_status_code ) {
$error_message = isset( $body['message'] ) ? $body['message'] : 'It looks like there has been an error while fetching your ThriveThemes license details.';
thrive_set_transient( 'td_ttw_connection_error', $error_message, self::CACHE_LIFE_TIME );
}
$cache_time = self::CACHE_LIFE_TIME;
/**
* 200, //success
* 400, //bad request
* 401, //unauthorized
* 403, //forbidden rate limiter
*/
if ( $response_status_code >= 403 && ! empty( $this->_tr_licenses ) ) {
$cache_time = self::CACHE_LIFE_TIME_SHORT;
$body = array(
'success' => true,
'data' => $this->_tr_licenses,
);
}
if ( ! is_array( $body ) || empty( $body['success'] ) ) {
thrive_set_transient( self::NAME, array(), $cache_time );
return array();
}
$licenses_details = $body['data'];
thrive_set_transient( self::NAME, $licenses_details, $cache_time );
thrive_delete_transient( 'td_ttw_connection_error' );
return $licenses_details;
}
/**
* Check if there is any TTB license that allows updates - memberships are not included here
*
* @return bool
*/
public function can_update_ttb() {
return $this->get_license( self::TTB_TAG ) && $this->get_license( self::TTB_TAG )->can_update();
}
public function get_active_license( $tag ) {
$license = false;
foreach ( $this->_active_licenses as $active_license ) {
if ( $active_license->has_tag( $tag ) ) {
$license = $active_license;
break;
}
}
return $license;
}
/**
* Checks is there is a license that allows user to user the product
* - firstly it looks for a membership active license
* - secondly it looks for a specific plugin active license
*
* @param string $tag plugin tag
*
* @return bool - plugin has/has not active license (will check membership tag also)
*/
public function has_active_license( string $tag ) {
$has = false;
$licenses = thrive_get_transient( self::NAME );
if ( empty( $licenses ) && ! is_array( $licenses ) ) {
return true;
}
$active_membership = $this->get_active_membership_license();
if ( $active_membership ) {
$has = true;
}
if ( ! $has ) {
foreach ( $this->_active_licenses as $license ) {
if ( $license->has_tag( $tag ) ) {
$has = true;
break;
}
}
}
return $has;
}
/**
* Check if a plugin tag has a license which is in grace period
*
* @param string $tag //plugin representation for which we check license
*
* @return bool - plugin is/is not in grace period (will check membership tag also)
*/
public function is_in_grace_period( string $tag ) {
$is = false;
if ( ! $this->has_active_license( $tag ) ) {
$in_grace_period_membership = $this->get_in_grace_period_membership();
if ( $in_grace_period_membership ) {
return true;
}
foreach ( $this->_in_grace_period_licenses as $license ) {
if ( $license->has_tag( $tag ) && $license->is_in_grace_period() ) {
$is = true;
break;
}
}
}
return $is;
}
public function show_gp_lightbox( string $tag ) {
$transient = 'tve_license_warning_lightbox_' . $tag;
return empty( get_transient( $transient ) );
}
/**
* Check if a plugin tag has a license which is in grace period
* and calculate the number of days left in grace period
*
* @param string $tag
*
* @return int - number of days left in grace period
* -1 if there is no license in grace period
*/
public function get_grace_period_left( string $tag ) {
if ( ! $this->is_in_grace_period( $tag ) ) {
return 0;
}
try {
$membership = $this->get_in_grace_period_membership();
$single = ! empty( $this->_in_grace_period_licenses[ $tag ] ) ? $this->_in_grace_period_licenses[ $tag ] : null;
$membership_days = 0;
$single_days = 0;
if ( $membership ) {
$membership_days = (int) $membership->get_remaining_grace_period()->format( '%a' ) + 1;
}
if ( $single ) {
$single_days = (int) $single->get_remaining_grace_period()->format( '%a' ) + 1;
}
$days = max( $membership_days, $single_days );
} catch ( Exception $e ) {
$days = 0;
}
return $days;
}
}