|
|
<?php
|
|
|
/**
|
|
|
* Plugin update class
|
|
|
*
|
|
|
* @since 1.0
|
|
|
* @package RankMathPro
|
|
|
* @subpackage RankMathPro\Admin
|
|
|
* @author Rank Math <support@rankmath.com>
|
|
|
*/
|
|
|
|
|
|
namespace RankMathPro\Plugin_Update;
|
|
|
|
|
|
use RankMath\KB;
|
|
|
use RankMath\Helper;
|
|
|
use RankMath\Traits\Hooker;
|
|
|
use MyThemeShop\Helpers\Param;
|
|
|
use RankMath\Admin\Admin_Helper;
|
|
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
|
|
/**
|
|
|
* Plugin_Update class
|
|
|
*/
|
|
|
class Plugin_Update {
|
|
|
|
|
|
use Hooker;
|
|
|
|
|
|
/**
|
|
|
* Placeholder for opening tag inserted with JS.
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
const NOTICE_START_MARKER = '[[';
|
|
|
|
|
|
/**
|
|
|
* Placeholder for closing tag inserted with JS.
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
const NOTICE_END_MARKER = ']]';
|
|
|
|
|
|
/**
|
|
|
* Plugin slug.
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
private $slug = 'seo-by-rank-math-pro';
|
|
|
|
|
|
/**
|
|
|
* Rank Math API URL.
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
private $api_url = 'https://rankmath.com/wp-json/rankmath/v1';
|
|
|
|
|
|
/**
|
|
|
* Keep a log of external requests made in this thread so we can avoid
|
|
|
* running them multiple times.
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
private $requested = [];
|
|
|
|
|
|
/**
|
|
|
* The Constructor.
|
|
|
*
|
|
|
* @return void
|
|
|
*/
|
|
|
public function __construct() {
|
|
|
$this->action( 'admin_enqueue_scripts', 'enqueue' );
|
|
|
$this->action( 'admin_notices', 'admin_license_notice', 20 );
|
|
|
$this->action( 'in_plugin_update_message-seo-by-rank-math-pro/rank-math-pro.php', 'beta_update_message', 20, 2 );
|
|
|
$this->action( 'in_plugin_update_message-' . plugin_basename( RANK_MATH_PRO_FILE ), 'in_plugin_update_message', 30, 2 );
|
|
|
$this->action( 'add_option_rank_math_connect_data', 'check_and_inject' );
|
|
|
$this->action( 'update_option_rank_math_connect_data', 'check_and_inject' );
|
|
|
$this->action( 'delete_option_rank_math_connect_data', 'check_and_inject' );
|
|
|
$this->action( 'rank_math/settings/toggle_auto_update', 'toggle_auto_update', 10, 1 );
|
|
|
$this->action( 'update_site_option_auto_update_plugins', 'connect_auto_update_toggles', 20, 4 );
|
|
|
|
|
|
$this->filter( 'plugin_action_links_' . plugin_basename( RANK_MATH_PRO_FILE ), 'plugin_action_links', 50 );
|
|
|
$this->filter( 'pre_set_site_transient_update_plugins', 'maybe_inject_update', 20, 1 );
|
|
|
$this->filter( 'site_transient_update_plugins', 'maybe_disable_update', 90, 1 );
|
|
|
$this->filter( 'pre_set_site_transient_update_plugins', 'maybe_add_upgrade_notice', 120, 1 );
|
|
|
$this->filter( 'plugins_api', 'filter_info', 10, 3 );
|
|
|
$this->filter( 'admin_print_footer_scripts-plugin-install.php', 'iframe_footer_scripts', 10, 3 );
|
|
|
|
|
|
$this->filter( 'auto_update_plugin', 'auto_update_plugin', 20, 2 );
|
|
|
$this->filter( 'plugin_auto_update_setting_html', 'plugin_auto_update_setting_html', 10, 3 );
|
|
|
|
|
|
$this->filter( 'rank_math/admin/should_send_update_notification', 'should_send_update_notification', 10, 2 );
|
|
|
$this->filter( 'rank_math/admin/update_notification_products', 'update_notification_products', 10, 2 );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Enqueue styles and scripts.
|
|
|
*
|
|
|
* @param string $hook Page hook prefix.
|
|
|
*
|
|
|
* @return void
|
|
|
*/
|
|
|
public function enqueue( $hook ) {
|
|
|
if ( 'update-core.php' !== $hook ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
Helper::add_json( 'canUpdatePro', $this->can_update() );
|
|
|
Helper::add_json( 'betaOptinEnabled', Helper::get_settings( 'general.beta_optin' ) );
|
|
|
wp_enqueue_script( 'rank-math-pro-updates', RANK_MATH_PRO_URL . 'assets/admin/js/updates.js', [], RANK_MATH_PRO_VERSION, true );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns false if Rank Math Pro update object exists but its 'package'
|
|
|
* item is empty, which means that the user cannot update. Returns true in
|
|
|
* all other cases – even if update is not available ATM.
|
|
|
*
|
|
|
* @param mixed $transient Update object to check or null to load transient.
|
|
|
* @return boolean
|
|
|
*/
|
|
|
public function can_update( $transient = null ) {
|
|
|
if ( is_null( $transient ) ) {
|
|
|
$transient = get_site_transient( 'update_plugins' );
|
|
|
}
|
|
|
|
|
|
if ( ! is_object( $transient ) ) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if ( ! isset( $transient->response ) || ! isset( $transient->response['seo-by-rank-math-pro/rank-math-pro.php'] ) ) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return ( ! empty( $transient->response['seo-by-rank-math-pro/rank-math-pro.php']->package ) );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Add connect/activation notice.
|
|
|
*
|
|
|
* @return void
|
|
|
*/
|
|
|
public function admin_license_notice() {
|
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if ( $this->is_block_editor_page() ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if ( Helper::is_site_connected() || rank_math()->registration->invalid ) {
|
|
|
return;
|
|
|
}
|
|
|
?>
|
|
|
<div class="notice notice-success rank-math-notice">
|
|
|
<p>
|
|
|
<?php
|
|
|
esc_html_e( 'Rank Math PRO is installed but it is not connected to your account, so you are missing out on important SEO features.', 'rank-math-pro' );
|
|
|
echo '<br>';
|
|
|
// translators: 1: opening HTML anchor tag, 2: closing HTML anchor tags.
|
|
|
echo wp_kses_post( sprintf( __( '%1$sConnect now%2$s. It only takes 20 seconds!', 'rank-math-pro' ), '<a href="' . esc_url( Admin_Helper::get_activate_url() ) . '">', '</a>' ) );
|
|
|
?>
|
|
|
</p>
|
|
|
</div>
|
|
|
<?php
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check if we are on Block Editor page.
|
|
|
*
|
|
|
* @return bool
|
|
|
*/
|
|
|
private function is_block_editor_page() {
|
|
|
$current_screen = get_current_screen();
|
|
|
|
|
|
if ( $current_screen instanceof \WP_Screen && method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() ) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if ( function_exists( 'is_gutenberg_page' ) && is_gutenberg_page() ) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Add Connect/Activate action link
|
|
|
*
|
|
|
* @param array $links Action links.
|
|
|
* @return array
|
|
|
*/
|
|
|
public function plugin_action_links( $links ) {
|
|
|
if ( ! Helper::is_site_connected() ) {
|
|
|
$links['activate_license'] = sprintf( '<a href="%s" class="rank-math-pro-activate-link" style="color:green">%s</a>', esc_url( Admin_Helper::get_activate_url( network_admin_url( 'plugins.php' ) ) ), __( 'Enable updates', 'rank-math-pro' ) );
|
|
|
}
|
|
|
|
|
|
return $links;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* If user requested check with force-check parameter.
|
|
|
*
|
|
|
* @return bool
|
|
|
*/
|
|
|
public function is_check_requested() {
|
|
|
return (bool) Param::get( 'force-check' );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check for updates & inject to update_plugins transient.
|
|
|
*
|
|
|
* @return void
|
|
|
*/
|
|
|
public function check_and_inject() {
|
|
|
$this->inject_update( $this->fetch_latest_version( true ) );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Inject update fetched from the rankmath.com API or pushed to this site via the REST API.
|
|
|
*
|
|
|
* @param object $transient Origial transient.
|
|
|
* @return mixed
|
|
|
*/
|
|
|
public function maybe_inject_update( $transient ) {
|
|
|
$force_check = $this->is_check_requested();
|
|
|
return $this->inject_update( $this->fetch_latest_version( $force_check ), $transient );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Remove package download URL if needed.
|
|
|
*
|
|
|
* @param object $transient Original transient.
|
|
|
* @return mixed
|
|
|
*/
|
|
|
public function maybe_disable_update( $transient ) {
|
|
|
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
|
|
return $transient;
|
|
|
}
|
|
|
|
|
|
// If we're in the process of updating RM Free then don't disable RM Pro update.
|
|
|
if (
|
|
|
( Param::get( 'action' ) === 'update-selected' && strpos( Param::get( 'plugins', '' ), 'seo-by-rank-math/rank-math.php' ) !== false ) ||
|
|
|
$this->do_filter( 'updates/remove_restrictions', false )
|
|
|
) {
|
|
|
return $transient;
|
|
|
}
|
|
|
|
|
|
if ( isset( $transient->response['seo-by-rank-math/rank-math.php'] )
|
|
|
&& isset( $transient->response['seo-by-rank-math-pro/rank-math-pro.php'] )
|
|
|
&& ! empty( $transient->response['seo-by-rank-math-pro/rank-math-pro.php']->package )
|
|
|
) {
|
|
|
unset( $transient->response['seo-by-rank-math-pro/rank-math-pro.php']->package );
|
|
|
$transient->response['seo-by-rank-math-pro/rank-math-pro.php']->unavailability_reason = 'update_free';
|
|
|
}
|
|
|
|
|
|
return $transient;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Add upgrade notice if needed, which is displayed on the Updates page (wp-admin/update-core.php)
|
|
|
*
|
|
|
* @param object $transient Original transient.
|
|
|
* @return mixed
|
|
|
*/
|
|
|
public function maybe_add_upgrade_notice( $transient ) {
|
|
|
if ( ! $this->can_update( $transient ) ) {
|
|
|
$before = self::NOTICE_START_MARKER;
|
|
|
$before .= __( 'Automatic updates are not available.', 'rank-math-pro' );
|
|
|
$before .= ' ';
|
|
|
$after = self::NOTICE_END_MARKER;
|
|
|
|
|
|
$message = $this->get_update_message( $transient->response['seo-by-rank-math-pro/rank-math-pro.php']->unavailability_reason );
|
|
|
$message = $before . $message . $after;
|
|
|
|
|
|
$transient->response['seo-by-rank-math-pro/rank-math-pro.php']->upgrade_notice = $message;
|
|
|
}
|
|
|
|
|
|
return $transient;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Inject our update in the update_plugins transient.
|
|
|
*
|
|
|
* @param mixed $update New update object or array, or false to clear current update.
|
|
|
* @param mixed $transient Original updates transient.
|
|
|
* @return mixed
|
|
|
*/
|
|
|
public function inject_update( $update, $transient = null ) {
|
|
|
$save = false;
|
|
|
if ( is_null( $transient ) ) {
|
|
|
$transient = get_site_transient( 'update_plugins' );
|
|
|
$save = true;
|
|
|
}
|
|
|
|
|
|
$plugin = plugin_basename( RANK_MATH_PRO_FILE );
|
|
|
if ( false !== $update ) {
|
|
|
$obj = $this->get_default_update_data();
|
|
|
$obj = (object) array_merge( (array) $obj, (array) $update );
|
|
|
|
|
|
$obj = $this->maybe_apply_beta( $obj );
|
|
|
|
|
|
// If a newer version is already present in the update_plugins transient then don't inject.
|
|
|
if ( $this->has_newer_version( $transient, $obj->new_version ) ) {
|
|
|
return $transient;
|
|
|
}
|
|
|
|
|
|
// Default transient data.
|
|
|
if ( empty( $transient ) ) {
|
|
|
$transient = new \stdClass();
|
|
|
|
|
|
$transient->last_checked = time();
|
|
|
$transient->checked = [ $plugin => RANK_MATH_PRO_VERSION ];
|
|
|
$transient->response = [];
|
|
|
}
|
|
|
|
|
|
// Inject if new data has URL and is a newer version than the one currently in use.
|
|
|
if ( version_compare( $obj->new_version, RANK_MATH_PRO_VERSION, '>' ) ) {
|
|
|
$transient->response[ $plugin ] = $obj;
|
|
|
if ( $save ) {
|
|
|
set_site_transient( 'update_plugins', $transient );
|
|
|
}
|
|
|
} else {
|
|
|
// No update is available.
|
|
|
$item = (object) [
|
|
|
'id' => 'seo-by-rank-math-pro/rank-math-pro.php',
|
|
|
'slug' => 'seo-by-rank-math-pro',
|
|
|
'plugin' => 'seo-by-rank-math-pro/rank-math-pro.php',
|
|
|
'new_version' => RANK_MATH_PRO_VERSION,
|
|
|
'url' => '',
|
|
|
'package' => '',
|
|
|
'icons' => [],
|
|
|
'banners' => [],
|
|
|
'banners_rtl' => [],
|
|
|
'tested' => '',
|
|
|
'requires_php' => '',
|
|
|
'compatibility' => new \stdClass(),
|
|
|
];
|
|
|
|
|
|
if ( empty( $transient->no_update ) ) {
|
|
|
$transient->no_update = [];
|
|
|
}
|
|
|
|
|
|
$transient->no_update[ $plugin ] = $item;
|
|
|
}
|
|
|
} elseif ( isset( $transient->response[ $plugin ] ) ) {
|
|
|
unset( $transient->response[ $plugin ] );
|
|
|
}
|
|
|
|
|
|
return $transient;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Replace `new_version` & `package` properties with beta if needed.
|
|
|
*
|
|
|
* @param object $update_object Plugin update data object.
|
|
|
* @return object
|
|
|
*/
|
|
|
public function maybe_apply_beta( $update_object ) {
|
|
|
if ( ! Helper::get_settings( 'general.beta_optin' ) ) {
|
|
|
return $update_object;
|
|
|
}
|
|
|
|
|
|
if (
|
|
|
empty( $update_object->new_version )
|
|
|
|| empty( $update_object->beta_version )
|
|
|
|| empty( $update_object->package )
|
|
|
|| empty( $update_object->beta_package )
|
|
|
) {
|
|
|
return $update_object;
|
|
|
}
|
|
|
|
|
|
if ( version_compare( $update_object->new_version, $update_object->beta_version, '>' ) ) {
|
|
|
return $update_object;
|
|
|
}
|
|
|
|
|
|
$update_object->is_beta = true;
|
|
|
|
|
|
// Store stable version data in case it's needed later.
|
|
|
$update_object->stable_version = $update_object->new_version;
|
|
|
$update_object->stable_package = $update_object->package;
|
|
|
|
|
|
// Override stable version data with beta.
|
|
|
$update_object->new_version = $update_object->beta_version;
|
|
|
$update_object->package = $update_object->beta_package;
|
|
|
|
|
|
// Add notice that's shown on the Updates page.
|
|
|
$update_object->upgrade_notice = self::NOTICE_START_MARKER . ' ' . __( 'This update will install a beta version of Rank Math SEO PRO.', 'rank-math-pro' ) . ' ' . self::NOTICE_END_MARKER;
|
|
|
|
|
|
return $update_object;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Show beta update message on the Plugins screen.
|
|
|
*
|
|
|
* @param array $plugin_data An array of plugin metadata.
|
|
|
* @param object $response An array of metadata about the available plugin update.
|
|
|
*/
|
|
|
public function beta_update_message( $plugin_data, $response ) {
|
|
|
if ( empty( $plugin_data['is_beta'] ) ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
printf(
|
|
|
'</p><p class="rank-math-beta-update-notice">%s',
|
|
|
esc_html__( 'This update will install a beta version of Rank Math SEO PRO.', 'rank-math-pro' )
|
|
|
);
|
|
|
|
|
|
$this->action( 'admin_footer', 'print_beta_notice_css' );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Print CSS related to the beta notice on the Plugins screen.
|
|
|
*
|
|
|
* @return void
|
|
|
*/
|
|
|
public function print_beta_notice_css() {
|
|
|
?>
|
|
|
<style>
|
|
|
.update-message .rank-math-beta-update-notice {
|
|
|
font-weight: bold;
|
|
|
margin-top: 20px;
|
|
|
}
|
|
|
.update-message p.rank-math-beta-update-notice:before {
|
|
|
content: "\f534";
|
|
|
}
|
|
|
</style>
|
|
|
<?php
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check if the transient already contains newer version of the plugin.
|
|
|
*
|
|
|
* @param object $transient Site transient: 'update_plugins'.
|
|
|
* @param string $new_version New version we check against, e.g. '1.2'.
|
|
|
* @return boolean
|
|
|
*/
|
|
|
public function has_newer_version( $transient, $new_version ) {
|
|
|
$plugin = plugin_basename( RANK_MATH_PRO_FILE );
|
|
|
|
|
|
return isset( $transient->response[ $plugin ] )
|
|
|
&& is_object( $transient->response[ $plugin ] )
|
|
|
&& isset( $transient->response[ $plugin ]->new_version )
|
|
|
&& version_compare( $transient->response[ $plugin ]->new_version, $new_version, '>' );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Filter plugin information.
|
|
|
*
|
|
|
* @param false|object|array $result The result object or array. Default false.
|
|
|
* @param string $action The type of information being requested from the Plugin Installation API.
|
|
|
* @param object $args Plugin API arguments.
|
|
|
* @return false|object false or Response object.
|
|
|
*/
|
|
|
public function filter_info( $result, $action, $args ) {
|
|
|
if ( ! isset( $args->slug ) || ! ( $this->slug === $args->slug && 'plugin_information' === $action ) ) {
|
|
|
return $result;
|
|
|
}
|
|
|
|
|
|
$information = $this->get_plugin_info();
|
|
|
if ( $this->has_beta_update( $information ) ) {
|
|
|
$information->sections['changelog'] = $information->sections['beta_changelog'];
|
|
|
}
|
|
|
unset( $information->sections['beta_changelog'] );
|
|
|
|
|
|
return $information;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Add JS in plugin-info iframe, to disable the Update button if necessary.
|
|
|
*
|
|
|
* @return void
|
|
|
*/
|
|
|
public function iframe_footer_scripts() {
|
|
|
if ( Param::get( 'plugin' ) !== 'seo-by-rank-math-pro' ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
$transient = get_site_transient( 'update_plugins' );
|
|
|
$response = isset( $transient->response['seo-by-rank-math-pro/rank-math-pro.php'] ) ? $transient->response['seo-by-rank-math-pro/rank-math-pro.php'] : new \stdClass();
|
|
|
if ( empty( $response->package ) && isset( $response->unavailability_reason ) ) {
|
|
|
$message = $this->get_update_message( $response->unavailability_reason );
|
|
|
?>
|
|
|
<script type="text/javascript">jQuery( function() {
|
|
|
var $button = jQuery( '#plugin_update_from_iframe' );
|
|
|
if ( $button.data( 'plugin' ) !== 'seo-by-rank-math-pro/rank-math-pro.php' ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
$button.css( 'pointer-events', 'none' ).addClass( 'disabled' ).text( '<?php echo esc_js( __( 'Cannot Update', 'rank-math-pro' ) ); ?>' );
|
|
|
jQuery( '#section-holder' ).prepend( '<div class="notice notice-error notice-alt"><p><strong><?php echo esc_js( $message ); ?></strong></p></div>' );
|
|
|
} );</script>
|
|
|
<?php
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check if plugin update data & info object contain a valid beta update.
|
|
|
*
|
|
|
* @param object $plugin_info
|
|
|
* @return boolean
|
|
|
*/
|
|
|
private function has_beta_update( $plugin_info ) {
|
|
|
$beta_optin_enabled = Helper::get_settings( 'general.beta_optin' );
|
|
|
$plugin = plugin_basename( RANK_MATH_PRO_FILE );
|
|
|
$transient = get_site_transient( 'update_plugins' );
|
|
|
|
|
|
return (
|
|
|
$beta_optin_enabled
|
|
|
&& ! empty( $transient->response[ $plugin ]->beta_version )
|
|
|
&& ! empty( $plugin_info->sections['beta_changelog'] )
|
|
|
&& version_compare( $transient->response[ $plugin ]->beta_version, ! empty( $transient->response[ $plugin ]->stable_version ) ? $transient->response[ $plugin ]->stable_version : $transient->response[ $plugin ]->new_version, '>=' )
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check if version check endpoint's response contains new beta verison.
|
|
|
*
|
|
|
* @param array $data Latest versions.
|
|
|
* @return boolean
|
|
|
*/
|
|
|
private function new_beta_version_available( $data ) {
|
|
|
return (
|
|
|
Helper::get_settings( 'general.beta_optin' )
|
|
|
&& version_compare( $data['beta_version'], $data['new_version'], '>' )
|
|
|
&& version_compare( $data['beta_version'], RANK_MATH_PRO_VERSION, '>' )
|
|
|
);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Merge default plugin data with fetched data.
|
|
|
*
|
|
|
* @param bool $force_check Disregard cached data & always re-fetch.
|
|
|
* @param string $locale Requested locale. Optional. Default: site locale.
|
|
|
*
|
|
|
* @return object|bool If there is an update, returns the license information.
|
|
|
* Otherwise returns false.
|
|
|
*/
|
|
|
private function get_plugin_info( $force_check = false, $locale = '' ) {
|
|
|
$information = $this->get_default_plugin_info();
|
|
|
$fetched = $this->fetch_plugin_info( $force_check, $locale );
|
|
|
if ( is_object( $fetched ) ) {
|
|
|
$information = (object) array_merge( (array) $information, (array) $fetched );
|
|
|
}
|
|
|
|
|
|
return $information;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Get default plugin info.
|
|
|
*
|
|
|
* @return object
|
|
|
*/
|
|
|
private function get_default_plugin_info() {
|
|
|
$description = '<p><strong>' . __( 'Rank Math SEO PRO For WordPress', 'rank-math-pro' ) . '</strong><br />';
|
|
|
$description .= '★★★★★</p>';
|
|
|
$description .= '<p><strong>' . __( 'SEO is the most consistent source of traffic for any website', 'rank-math-pro' ) . '.</strong> ';
|
|
|
// Translators: placeholders are the anchor tag opening and closing.
|
|
|
$description .= sprintf( __( 'We created %1$sRank Math, a WordPress SEO plugin%2$s, to help every website owner get access to the SEO tools they need to improve their SEO and attract more traffic to their website.', 'rank-math-pro' ), '<a href="' . KB::get( 'logo', 'PRO Update Popup Description Tab' ) . '" rel="nofollow ugc"><strong>', '</strong></a>' ) . '</p>';
|
|
|
|
|
|
$plugin_info = [
|
|
|
'external' => true,
|
|
|
'name' => 'Rank Math SEO PRO',
|
|
|
'slug' => $this->slug,
|
|
|
'author' => '<a href="' . KB::get( 'seo-suite', 'PRO Update Popup Author Link' ) . '">Rank Math</a>',
|
|
|
'homepage' => KB::get( 'seo-suite', 'PRO Update Popup Homepage Link' ),
|
|
|
'banners' => [
|
|
|
'low' => 'https://ps.w.org/seo-by-rank-math/assets/banner-772x250.png',
|
|
|
'high' => 'https://ps.w.org/seo-by-rank-math/assets/banner-1544x500.png',
|
|
|
],
|
|
|
'sections' => [
|
|
|
'description' => $description,
|
|
|
],
|
|
|
'version' => RANK_MATH_PRO_VERSION,
|
|
|
];
|
|
|
|
|
|
return (object) $plugin_info;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Get default plugin info if we can't get anything from the API.
|
|
|
*
|
|
|
* @return object
|
|
|
*/
|
|
|
private function get_default_update_data() {
|
|
|
$plugin = plugin_basename( RANK_MATH_PRO_FILE );
|
|
|
|
|
|
$update = [
|
|
|
'slug' => $this->slug,
|
|
|
'plugin' => $plugin,
|
|
|
'url' => KB::get( 'seo-suite', 'PRO Update Popup Update Home Link' ),
|
|
|
'icons' => [
|
|
|
'svg' => 'https://ps.w.org/seo-by-rank-math/assets/icon.svg?rev=2348086',
|
|
|
'1x' => 'https://ps.w.org/seo-by-rank-math/assets/icon-128x128.png',
|
|
|
'2x' => 'https://ps.w.org/seo-by-rank-math/assets/icon-256x256.png',
|
|
|
],
|
|
|
'new_version' => '',
|
|
|
'package' => '',
|
|
|
];
|
|
|
|
|
|
return (object) $update;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Checks the license manager to see if there is an update available for this product.
|
|
|
*
|
|
|
* @param bool $force_check Disregard cached data & always re-fetch.
|
|
|
* @return object|bool If there is an update, returns the license information.
|
|
|
* Otherwise returns false.
|
|
|
*/
|
|
|
public function fetch_latest_version( $force_check = false ) {
|
|
|
|
|
|
$stored_versions = get_site_transient( 'rank_math_pro_versions' );
|
|
|
if ( empty( $stored_versions ) || $force_check ) {
|
|
|
// Check the latest versions.
|
|
|
$versions_response = wp_remote_get(
|
|
|
$this->api_url . '/versionCheck/',
|
|
|
[
|
|
|
'timeout' => defined( 'DOING_CRON' ) && DOING_CRON ? 30 : 10,
|
|
|
'body' => [
|
|
|
'product_slug' => $this->slug,
|
|
|
],
|
|
|
]
|
|
|
);
|
|
|
|
|
|
if ( is_wp_error( $versions_response ) ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
$versions_response_body = wp_remote_retrieve_body( $versions_response );
|
|
|
$versions_result = json_decode( $versions_response_body, true );
|
|
|
if ( ! is_array( $versions_result ) || ! isset( $versions_result['new_version'] ) ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
$stored_versions = $versions_result;
|
|
|
|
|
|
set_site_transient( 'rank_math_pro_versions', $versions_result, 3600 * 3 );
|
|
|
update_site_option( 'rank_math_pro_google_updates', $versions_result['g_updates'] );
|
|
|
}
|
|
|
|
|
|
$stored = get_site_transient( 'rank_math_pro_updates' );
|
|
|
if (
|
|
|
! $force_check
|
|
|
&& ! empty( $stored )
|
|
|
&& version_compare( $stored_versions['new_version'], RANK_MATH_PRO_VERSION, '<=' )
|
|
|
&& ! $this->new_beta_version_available( $stored_versions )
|
|
|
) {
|
|
|
return $stored;
|
|
|
}
|
|
|
|
|
|
if ( ! empty( $this->requested['version'] ) ) {
|
|
|
return ( false === $stored ? [] : $stored );
|
|
|
}
|
|
|
|
|
|
$params = [
|
|
|
'site_url' => is_multisite() ? network_site_url() : home_url(),
|
|
|
'product_slug' => $this->slug,
|
|
|
'new_api' => 2,
|
|
|
'v' => RANK_MATH_PRO_VERSION,
|
|
|
];
|
|
|
|
|
|
$this->maybe_add_auth_params( $params );
|
|
|
|
|
|
if ( ! isset( $params['username'] ) || Admin_Helper::is_plan_expired() ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
$response = wp_remote_post(
|
|
|
add_query_arg( 'v', RANK_MATH_PRO_VERSION, $this->api_url . '/updateCheck2/' ),
|
|
|
[
|
|
|
'timeout' => defined( 'DOING_CRON' ) && DOING_CRON ? 30 : 10,
|
|
|
'body' => $params,
|
|
|
]
|
|
|
);
|
|
|
|
|
|
$this->requested['version'] = true;
|
|
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
$response_body = wp_remote_retrieve_body( $response );
|
|
|
$result = json_decode( $response_body, true );
|
|
|
if ( ! is_array( $result ) || ! isset( $result['new_version'] ) ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
set_site_transient( 'rank_math_pro_updates', $result, 3600 * 12 );
|
|
|
|
|
|
return $result;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Checks the license manager to see if there is an update available for this product.
|
|
|
*
|
|
|
* @param bool $force_check Disregard cached data & always re-fetch.
|
|
|
* @param string $locale Requested locale. Optional. Default: site locale.
|
|
|
* @return object|bool If there is an update, returns the license information.
|
|
|
* Otherwise returns false.
|
|
|
*/
|
|
|
public function fetch_plugin_info( $force_check = false, $locale = '' ) {
|
|
|
if ( ! $locale ) {
|
|
|
$locale = get_locale();
|
|
|
}
|
|
|
|
|
|
$stored = get_site_transient( 'rank_math_pro_info_' . $locale );
|
|
|
if ( ! $force_check && ! empty( $stored ) ) {
|
|
|
return $stored;
|
|
|
}
|
|
|
|
|
|
if ( ! empty( $this->requested['info'] ) ) {
|
|
|
return ( false === $stored ? (object) [] : $stored );
|
|
|
}
|
|
|
|
|
|
$params = [
|
|
|
'product_slug' => $this->slug,
|
|
|
'locale' => $locale,
|
|
|
'site_url' => is_multisite() ? network_site_url() : home_url(),
|
|
|
];
|
|
|
|
|
|
$this->maybe_add_auth_params( $params );
|
|
|
|
|
|
// Send the request.
|
|
|
$response = wp_remote_post(
|
|
|
$this->api_url . '/pluginInfo/',
|
|
|
[
|
|
|
'timeout' => defined( 'DOING_CRON' ) && DOING_CRON ? 30 : 10,
|
|
|
'body' => $params,
|
|
|
]
|
|
|
);
|
|
|
|
|
|
$this->requested['info'] = true;
|
|
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
$response_body = wp_remote_retrieve_body( $response );
|
|
|
|
|
|
// We do assoc=true and then cast to object to keep sub-items as array.
|
|
|
$result = (object) json_decode( $response_body, true );
|
|
|
|
|
|
if ( ! is_object( $result ) ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
set_site_transient( 'rank_math_pro_info_' . $locale, $result, 3600 * 3 );
|
|
|
return $result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Add username & api key if the site is connected.
|
|
|
*
|
|
|
* @param array $params Params passed by reference.
|
|
|
* @return void
|
|
|
*/
|
|
|
private function maybe_add_auth_params( &$params ) {
|
|
|
$registered = Admin_Helper::get_registration_data();
|
|
|
if ( $registered && isset( $registered['username'] ) && isset( $registered['api_key'] ) ) {
|
|
|
$params['username'] = $registered['username'];
|
|
|
$params['api_key'] = $registered['api_key'];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Add additional text to notice if download is not available and account is connected.
|
|
|
*
|
|
|
* @param array $plugin_data An array of plugin metadata.
|
|
|
* @param object $response An array of metadata about the available plugin update.
|
|
|
* @return void
|
|
|
*/
|
|
|
public function in_plugin_update_message( $plugin_data, $response ) {
|
|
|
if ( current_user_can( 'update_plugins' ) ) {
|
|
|
if ( empty( $response->package ) && isset( $response->unavailability_reason ) ) {
|
|
|
$message = $this->get_update_message( $response->unavailability_reason );
|
|
|
echo ' <strong>' . wp_kses_post( $message ) . '</strong>';
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Get unavailability reason message.
|
|
|
*
|
|
|
* @param string $reason Unavailability reason ID, like 'not_connected'.
|
|
|
* @param mixed $default Default text to return when specified ID has no message attached to it.
|
|
|
* @return string
|
|
|
*/
|
|
|
public function get_update_message( $reason = '', $default = null ) {
|
|
|
if ( is_null( $default ) ) {
|
|
|
$default = '';
|
|
|
}
|
|
|
|
|
|
$unavailability_reasons = [
|
|
|
'update_free' => __( 'Please update the free version before updating Rank Math SEO PRO.', 'rank-math-pro' ),
|
|
|
'not_subscribed' => sprintf(
|
|
|
/* translators: 1: Plugin name, 2: Pricing Link's opening HTML anchor tag, 3: Pricing Link's closing HTML anchor tag. */
|
|
|
__( 'It seems that you don\'t have an active subscription for %1$s. Please see %2$sdetails and pricing%3$s.', 'rank-math-pro' ),
|
|
|
'Rank Math SEO PRO',
|
|
|
'<a href="' . KB::get( 'pro', 'PRO Update Popup Upgrade Notice' ) . '">',
|
|
|
'</a>'
|
|
|
),
|
|
|
'not_connected' => sprintf(
|
|
|
/* translators: 1: Link's opening HTML anchor tag, 2: Link's closing HTML anchor tag. */
|
|
|
__( 'Please %1$s connect Rank Math SEO PRO %2$s for automatic updates.', 'rank-math-pro' ),
|
|
|
'<a href="' . Helper::get_connect_url() . '">',
|
|
|
'</a>'
|
|
|
),
|
|
|
];
|
|
|
|
|
|
$unavailability_reasons = $this->do_filter( 'updates/unavailability_reasons', $unavailability_reasons );
|
|
|
|
|
|
if ( isset( $unavailability_reasons[ $reason ] ) ) {
|
|
|
return $unavailability_reasons[ $reason ];
|
|
|
}
|
|
|
|
|
|
return $default;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Toggle auto updates option.
|
|
|
* Hooked to run when the option is changed in the free version.
|
|
|
*
|
|
|
* @param string $toggle New status.
|
|
|
* @return void
|
|
|
*/
|
|
|
public function toggle_auto_update( $toggle ) {
|
|
|
$auto_updates = (array) get_site_option( 'auto_update_plugins', [] );
|
|
|
if ( ! empty( $toggle ) && 'off' !== $toggle ) {
|
|
|
$auto_updates[] = 'seo-by-rank-math-pro/rank-math-pro.php';
|
|
|
update_site_option( 'auto_update_plugins', array_unique( $auto_updates ) );
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
update_site_option( 'auto_update_plugins', array_diff( $auto_updates, [ 'seo-by-rank-math-pro/rank-math-pro.php' ] ) );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Don't auto-update if it's a beta version.
|
|
|
*
|
|
|
* @param bool $update Whether to update the plugin or not.
|
|
|
* @param array $item The update plugin object.
|
|
|
*
|
|
|
* @return bool
|
|
|
*/
|
|
|
public function auto_update_plugin( $update, $item ) {
|
|
|
// Show auto-updates control on Plugins page.
|
|
|
if ( did_action( 'load-plugins.php' ) ) {
|
|
|
return $update;
|
|
|
}
|
|
|
|
|
|
if ( $this->is_rm_pro_update( $item ) && $this->is_beta_update( $item ) ) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return $update;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check if updatable object is RM.
|
|
|
*
|
|
|
* @param object $item Updatable object.
|
|
|
* @return boolean
|
|
|
*/
|
|
|
public function is_rm_pro_update( $item ) {
|
|
|
return isset( $item->slug ) &&
|
|
|
'seo-by-rank-math-pro' === $item->slug &&
|
|
|
isset( $item->new_version );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check if given version is beta.
|
|
|
*
|
|
|
* @param object $item Update data.
|
|
|
* @return boolean
|
|
|
*/
|
|
|
public function is_beta_update( $item ) {
|
|
|
return ( is_object( $item ) && isset( $item->new_version ) && false !== stripos( $item->new_version, 'beta' ) );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Hide "update scheduled in X hours" message if update is a beta version because we don't auto-update those.
|
|
|
*
|
|
|
* @param string $html HTML string.
|
|
|
* @param string $plugin_file Plugin file relative to the plugin directory.
|
|
|
* @param array $plugin_data Plugin update data.
|
|
|
* @return string
|
|
|
*/
|
|
|
public function plugin_auto_update_setting_html( $html, $plugin_file, $plugin_data ) {
|
|
|
if ( 'seo-by-rank-math-pro/rank-math-pro.php' !== $plugin_file ) {
|
|
|
return $html;
|
|
|
}
|
|
|
|
|
|
if ( ! empty( $plugin_data['is_beta'] ) ) {
|
|
|
$html = str_replace( 'class="auto-update-time"', 'class="auto-update-time hidden"', $html );
|
|
|
}
|
|
|
|
|
|
return $html;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Set should_send to true if Pro update is available, to send the notification email.
|
|
|
* Notification feature is only available if auto-updates are disabled.
|
|
|
*
|
|
|
* @param boolean $should_send Original should_send value.
|
|
|
* @param mixed $transient update_plugins site ransient value.
|
|
|
* @return boolean
|
|
|
*/
|
|
|
public function should_send_update_notification( $should_send, $transient ) {
|
|
|
if ( $this->get_auto_update_setting() ) {
|
|
|
return $should_send;
|
|
|
}
|
|
|
|
|
|
if ( ! $this->is_update_available( $transient ) ) {
|
|
|
return $should_send;
|
|
|
}
|
|
|
|
|
|
$new_version = $transient->response['seo-by-rank-math-pro/rank-math-pro.php']->new_version;
|
|
|
|
|
|
// Now let's check if we've already sent this email.
|
|
|
$sent = get_option( 'rank_math_update_notifications_sent', [ 'pro' => [ 'new_version' => '1.0' ] ] );
|
|
|
if ( ! isset( $sent['pro'] ) ) {
|
|
|
$sent['pro'] = [ 'new_version' => '1.0' ];
|
|
|
}
|
|
|
|
|
|
if ( version_compare( $sent['pro']['new_version'], $new_version, '>=' ) ) {
|
|
|
return $should_send;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Add Pro to notification product list if an update is available.
|
|
|
*
|
|
|
* @param array $products Products data array.
|
|
|
* @param mixed $transient Transient value.
|
|
|
* @return array
|
|
|
*/
|
|
|
public function update_notification_products( $products, $transient ) {
|
|
|
if ( $this->get_auto_update_setting() ) {
|
|
|
return $products;
|
|
|
}
|
|
|
|
|
|
if ( ! $this->is_update_available( $transient ) ) {
|
|
|
return $products;
|
|
|
}
|
|
|
|
|
|
$products['pro'] = [
|
|
|
'name' => __( 'Rank Math PRO', 'rank-math-pro' ),
|
|
|
'old_version' => RANK_MATH_PRO_VERSION,
|
|
|
'new_version' => $transient->response['seo-by-rank-math-pro/rank-math-pro.php']->new_version,
|
|
|
'changelog' => KB::get( 'changelog', 'PRO Update Popup Chagelog Link' ),
|
|
|
];
|
|
|
|
|
|
return $products;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check if update is available for the PRO version.
|
|
|
*
|
|
|
* @param mixed $transient The update_plugins transient value.
|
|
|
* @return boolean
|
|
|
*/
|
|
|
public function is_update_available( $transient ) {
|
|
|
if ( ! is_object( $transient )
|
|
|
|| empty( $transient->response )
|
|
|
|| empty( $transient->response['seo-by-rank-math-pro/rank-math-pro.php'] )
|
|
|
|| empty( $transient->response['seo-by-rank-math-pro/rank-math-pro.php']->new_version )
|
|
|
) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Get Auto update setting status.
|
|
|
*
|
|
|
* @return bool
|
|
|
*/
|
|
|
public function get_auto_update_setting() {
|
|
|
return in_array( 'seo-by-rank-math-pro/rank-math-pro.php', (array) get_site_option( 'auto_update_plugins', [] ), true );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Connect auto-update toggles: if we enable it for the Pro, then Free should be enabled too,
|
|
|
* and if we disable it for Free then it should be disabled for the Pro too.
|
|
|
*
|
|
|
* @param string $option Option name.
|
|
|
* @param mixed $value Option value.
|
|
|
* @param mixed $old_value Previous option value before the change.
|
|
|
* @param int $network_id Network ID.
|
|
|
* @return void
|
|
|
*/
|
|
|
public function connect_auto_update_toggles( $option, $value, $old_value, $network_id ) {
|
|
|
$this->remove_action( 'update_site_option_auto_update_plugins', 'connect_auto_update_toggles', 20 );
|
|
|
if ( ! is_array( $value ) ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
$free_file = 'seo-by-rank-math/rank-math.php';
|
|
|
$pro_file = 'seo-by-rank-math-pro/rank-math-pro.php';
|
|
|
|
|
|
// If we just enabled it for Rank Math SEO Pro.
|
|
|
if ( in_array( $pro_file, $value, true ) && ! in_array( $pro_file, $old_value, true ) && ! in_array( $free_file, $value, true ) ) {
|
|
|
$value[] = $free_file;
|
|
|
update_site_option( $option, $value );
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// If we just disabled it for Rank Math SEO Free.
|
|
|
if ( ! in_array( $free_file, $value, true ) && in_array( $free_file, $old_value, true ) && in_array( $pro_file, $value, true ) ) {
|
|
|
$value = array_diff( $value, [ $pro_file ] );
|
|
|
update_site_option( $option, $value );
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
}
|