Commit realizado el 12:13:52 08-04-2024

This commit is contained in:
Pagina Web Monito
2024-04-08 12:13:55 -04:00
commit 0c33094de9
7815 changed files with 1365694 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,61 @@
<?php
/**
* Divi admin integration.
*
* @since TODO
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Divi;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Divi class.
*/
class Divi_Admin {
use Hooker;
/**
* Class constructor.
*/
public function __construct() {
$this->init();
}
/**
* Intialize Divi admin.
*/
public function init() {
$screen = get_current_screen();
if ( 'toplevel_page_et_divi_options' === $screen->id ) {
$this->action( 'admin_enqueue_scripts', 'enqueue_divi_admin_scripts' );
}
}
/**
* Enqueue scripts for Divi admin options screen.
*/
public function enqueue_divi_admin_scripts() {
wp_enqueue_script(
'rank-math-divi-admin',
rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/js/divi-admin.js',
[
'jquery',
'react',
'react-dom',
'wp-components',
'wp-element',
'wp-i18n',
'wp-polyfill',
],
rank_math()->version,
true
);
}
}

View File

@@ -0,0 +1,355 @@
<?php
/**
* Divi integration.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Divi;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Helpers\Editor;
use RankMath\Helpers\Str;
use RankMath\Schema\DB as Schema_DB;
use RankMath\Schema\Admin as Schema_Admin;
use RankMath\Traits\Hooker;
use RankMath\Admin\Metabox\Screen;
use WP_Dependencies;
defined( 'ABSPATH' ) || exit;
/**
* Divi class.
*/
class Divi {
use Hooker;
/**
* Screen object.
*
* @var Screen
*/
private $screen;
/**
* Class constructor.
*/
public function __construct() {
$this->action( 'wp', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! $this->can_add_seo_tab() ) {
return;
}
$this->screen = new Screen();
$this->screen->load_screen( 'post' );
$this->action( 'template_redirect', 'set_window_lodash', 0 );
$this->action( 'wp_enqueue_scripts', 'register_rankmath_react' );
$this->action( 'wp_enqueue_scripts', 'add_json_data', 0 );
$this->action( 'wp_footer', 'footer_enqueue_scripts', 11 );
remove_action( 'wp_footer', [ rank_math()->json, 'output' ], 0 );
add_action( 'wp_footer', [ rank_math()->json, 'output' ], 11 );
$this->filter( 'script_loader_tag', 'add_et_tag', 10, 3 );
}
/**
* Set the global lodash variable.
*
* Lodash's `noConflict` would prevent UnderscoreJS from taking over the underscore (_)
* global variable. Because Underscore.js will later also be assigned to the underscore (_)
* global this function should run as early as possible.
*/
public function set_window_lodash() {
wp_register_script( 'rm-set-window-lodash', '', [ 'lodash' ], rank_math()->version, false );
wp_enqueue_script( 'rm-set-window-lodash' );
wp_add_inline_script(
'rm-set-window-lodash',
join(
"\r\n ",
[
'window.isLodash = function() {',
"if ( typeof window._ !== 'function' || typeof window._.forEach !== 'function' ) {",
'return false;',
'}',
'var isLodash = true;',
'window._.forEach(',
"[ 'cloneDeep', 'at', 'add', 'ary', 'attempt' ],",
'function( fn ) {',
"if ( isLodash && typeof window._[ fn ] !== 'function' ) {",
'isLodash = false;',
'}',
'}',
');',
'return isLodash;',
'}',
'if ( window.isLodash() ) { window.lodash = window._.noConflict(); }',
]
)
);
}
/**
* Register RankMath React and ReactDOM.
*
* Registers the native WP version of react with a custom handle for use in the
* RankMath module. Divi builder dequeues and deregisters native WP react scripts
* and replaces them with their own copy of React. Their copy might not be of the
* same version as the one RankMath requires.
*/
public function register_rankmath_react() {
$path = site_url( '/wp-includes/js/dist/vendor/' );
$suffix = wp_scripts_get_suffix();
wp_register_script( 'rm-react', "{$path}react{$suffix}.js", [ 'wp-polyfill', 'react' ], '16.13.1', true );
wp_register_script( 'rm-react-dom', "{$path}react-dom{$suffix}.js", [ 'rm-react', 'react-dom' ], '16.13.1', true );
}
/**
* Add JSON data.
*/
public function add_json_data() {
if ( Helper::has_cap( 'onpage_snippet' ) ) {
// Schema.
$schemas = $this->get_schema_data( get_the_ID() );
Helper::add_json( 'schemas', $schemas );
Helper::add_json( 'customSchemaImage', esc_url( rank_math()->plugin_url() . 'includes/modules/schema/assets/img/custom-schema-builder.jpg' ) );
// Trends.
$trends_upgrade_link = KB::get( 'pro', 'Divi General Tab Trends' );
Helper::add_json( 'trendsUpgradeLink', esc_url_raw( $trends_upgrade_link ) );
Helper::add_json( 'trendsPreviewImage', esc_url( rank_math()->plugin_url() . 'assets/admin/img/trends-preview.jpg' ) );
}
Helper::add_json(
'api',
[
'root' => esc_url_raw( get_rest_url() ),
'nonce' => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ),
]
);
Helper::add_json(
'keywordsApi',
[
'url' => 'https://api.rankmath.com/ltkw/v1/',
]
);
Helper::add_json( 'links', KB::get_links() );
Helper::add_json(
'validationl10n',
[
'regexErrorDefault' => __( 'Please use the correct format.', 'rank-math' ),
'requiredErrorDefault' => __( 'This field is required.', 'rank-math' ),
'emailErrorDefault' => __( 'Please enter a valid email address.', 'rank-math' ),
'urlErrorDefault' => __( 'Please enter a valid URL.', 'rank-math' ),
]
);
Helper::add_json( 'capitalizeTitle', Helper::get_settings( 'titles.capitalize_titles' ) );
Helper::add_json( 'blogName', get_bloginfo( 'name' ) );
if ( is_admin_bar_showing() && Helper::has_cap( 'admin_bar' ) ) {
Helper::add_json( 'objectID', get_the_ID() );
Helper::add_json( 'objectType', 'post' );
}
}
/**
* Enqueue scripts.
*/
public function footer_enqueue_scripts() {
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts before plugin assets.
*/
$this->do_action( 'admin/before_editor_scripts' );
$divi_deps = [
'jquery',
'lodash',
'rm-react',
'rm-react-dom',
'rm-set-window-lodash',
'et-dynamic-asset-helpers',
'wp-api-fetch',
'wp-block-editor',
'wp-components',
'wp-compose',
'wp-core-data',
'wp-data',
'wp-element',
'wp-hooks',
'wp-media-utils',
'rank-math-analyzer',
'rank-math-app',
];
if ( is_admin_bar_showing() && Helper::has_cap( 'admin_bar' ) ) {
wp_enqueue_style( 'rank-math', rank_math()->assets() . 'css/rank-math.css', null, rank_math()->version );
wp_enqueue_script( 'rank-math', rank_math()->assets() . 'js/rank-math.js', [ 'jquery' ], rank_math()->version, true );
}
wp_enqueue_style( 'rank-math-common', rank_math()->plugin_url() . 'assets/admin/css/common.css', null, rank_math()->version );
wp_enqueue_style( 'wp-components' );
wp_enqueue_style( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/css/divi.css', [], rank_math()->version );
wp_register_script( 'rank-math-analyzer', rank_math()->plugin_url() . 'assets/admin/js/analyzer.js', null, rank_math()->version, true );
wp_enqueue_script( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/js/divi.js', $divi_deps, rank_math()->version, true );
wp_enqueue_script( 'rank-math-divi-iframe', rank_math()->plugin_url() . 'includes/3rdparty/divi/assets/js/divi-iframe.js', [ 'jquery', 'lodash' ], rank_math()->version, true );
if ( Helper::is_module_active( 'rich-snippet' ) ) {
wp_enqueue_style( 'rank-math-schema', rank_math()->plugin_url() . 'includes/modules/schema/assets/css/schema.css', [ 'wp-components' ], rank_math()->version );
wp_enqueue_script( 'rank-math-schema', rank_math()->plugin_url() . 'includes/modules/schema/assets/js/schema-gutenberg.js', [ 'rank-math-editor' ], rank_math()->version, true );
wp_set_script_translations( 'rank-math-schema', 'rank-math', rank_math()->plugin_dir() . 'languages/' );
}
rank_math()->variables->setup();
rank_math()->variables->setup_json();
$this->screen->localize();
$this->print_react_containers();
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts after plugin assets.
*/
$this->do_action( 'admin/editor_scripts' );
}
/**
* Add et attributes to script tags.
*
* @param string $tag The <script> tag for the enqueued script.
* @param string $handle The script's registered handle.
* @param string $src The script's source URL.
*
* @return string
*/
public function add_et_tag( $tag, $handle, $src ) {
$script_handles = [
'rm-react',
'rm-react-dom',
'lodash',
'moment',
'rank-math',
'rank-math-analyzer',
'rank-math-schema',
'rank-math-editor',
'rank-math-content-ai',
'rank-math-app',
// Scripts required by pro version.
'wp-plugins',
'jquery-ui-autocomplete',
'rank-math-pro-editor',
'rank-math-schema-pro',
'rank-math-pro-schema-filters',
'rank-math-pro-news',
];
$exclude_handles = [
'wp-util',
'wp-backbone',
'wp-plupload',
'wp-mediaelement',
'wp-color-picker',
'wp-color-picker-alpha',
'wp-embed',
'wp-hooks',
];
if ( in_array( $handle, $exclude_handles, true ) ) {
return $tag;
}
if ( Str::starts_with( 'wp-', $handle ) || in_array( $handle, $script_handles, true ) ) {
// These tags load in parent window only, not in Divi iframe.
return '<script type="text/javascript" src="' . $src . '" class="et_fb_ignore_iframe"></script>' . "\n"; // phpcs:ignore
}
return $tag;
}
/**
* Print React containers onto the screen.
*/
public function print_react_containers() {
echo '<div id="rank-math-rm-app-root" class="et_fb_ignore_iframe"></div>';
echo '<div id="rank-math-rm-settings-bar-root" class="et_fb_ignore_iframe"></div>';
}
/**
* Can add SEO in Divi Page Builder.
*
* @return bool
*/
private function can_add_seo_tab() {
if (
! Helper::is_divi_frontend_editor() ||
! defined( 'ET_BUILDER_PRODUCT_VERSION' ) ||
! version_compare( '4.9.2', ET_BUILDER_PRODUCT_VERSION, 'le' )
) {
return false;
}
/**
* Filter to show/hide SEO Tab in Divi Editor.
*/
if ( ! $this->do_filter( 'divi/add_seo_tab', true ) ) {
return false;
}
$post_type = get_post_type();
if ( $post_type && ! Helper::get_settings( 'titles.pt_' . $post_type . '_add_meta_box' ) ) {
return false;
}
return Editor::can_add_editor();
}
/**
* Get Schema Data.
*
* @param int $post_id Post ID.
*
* @return array $schemas Schema Data.
*/
private function get_schema_data( $post_id ) {
$schemas = Schema_DB::get_schemas( $post_id );
if ( ! empty( $schemas ) || metadata_exists( 'post', $post_id, 'rank_math_rich_snippet' ) ) {
return $schemas;
}
$post_type = get_post_type( $post_id );
$default_type = ucfirst( Helper::get_default_schema_type( $post_id ) );
if ( ! $default_type ) {
return [];
}
$schemas['new-9999'] = [
'@type' => $default_type,
'metadata' => [
'title' => Helper::sanitize_schema_title( $default_type ),
'type' => 'template',
'shortcode' => uniqid( 's-' ),
'isPrimary' => true,
],
];
return $schemas;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,213 @@
<?php
/**
* Elementor integration.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Elementor;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Editor;
defined( 'ABSPATH' ) || exit;
/**
* Elementor class.
*/
class Elementor {
use Hooker;
/**
* Class constructor.
*/
public function __construct() {
$this->action( 'init', 'init' );
$this->filter( 'rank_math/frontend/robots', 'robots' );
$this->filter( 'rank_math/frontend/disable_integration', 'disable_frontend_integration' );
}
/**
* Intialize.
*/
public function init() {
if ( ! $this->can_add_seo_tab() ) {
return;
}
$this->action( 'elementor/editor/before_enqueue_scripts', 'enqueue' );
add_action( 'elementor/editor/footer', [ rank_math()->json, 'output' ], 0 );
$this->action( 'elementor/editor/footer', 'start_capturing', 0 );
$this->action( 'elementor/editor/footer', 'end_capturing', 999 );
$this->filter( 'rank_math/sitemap/content_before_parse_html_images', 'apply_builder_in_content', 10, 2 );
}
/**
* Disable frontend integration on Elementor Maintenance page.
*
* @since 1.0.91
*
* @param boolean $value Whether to run the frontend integration.
*/
public function disable_frontend_integration( $value ) {
$mode = get_option( 'elementor_maintenance_mode_mode' );
if ( ! in_array( $mode, [ 'maintenance', 'coming_soon' ], true ) ) {
return $value;
}
if ( ! get_option( 'elementor_maintenance_mode_template_id' ) ) {
return $value;
}
$exclude_mode = get_option( 'elementor_maintenance_mode_exclude_mode', [] );
if ( 'logged_in' === $exclude_mode && is_user_logged_in() ) {
return $value;
}
if ( 'custom' !== $exclude_mode ) {
return true;
}
$exclude_roles = get_option( 'elementor_maintenance_mode_exclude_roles', [] );
$user = wp_get_current_user();
$user_roles = $user->roles;
if ( is_multisite() && is_super_admin() ) {
$user_roles[] = 'super_admin';
}
$compare_roles = array_intersect( $user_roles, $exclude_roles );
return ! empty( $compare_roles ) ? $value : true;
}
/**
* Start capturing buffer.
*/
public function start_capturing() {
ob_start();
}
/**
* End capturing buffer and add button.
*/
public function end_capturing() {
$output = \ob_get_clean();
$search = '/(<(div|button) class="elementor-component-tab elementor-panel-navigation-tab" data-tab="global">.*<\/(div|button)>)/m';
$replace = '${1}<${2} class="elementor-component-tab elementor-panel-navigation-tab" data-tab="rank-math">SEO</${2}>';
echo \preg_replace(
$search,
$replace,
$output
);
}
/**
* Enqueue scripts.
*/
public function enqueue() {
$deps = [
'wp-core-data',
'wp-components',
'wp-block-editor',
'wp-element',
'wp-data',
'wp-api-fetch',
'wp-media-utils',
'site-health',
'rank-math-analyzer',
'backbone-marionette',
'elementor-common-modules',
'rank-math-app',
];
$mode = \Elementor\Core\Settings\Manager::get_settings_managers( 'editorPreferences' )->get_model()->get_settings( 'ui_theme' );
wp_deregister_style( 'rank-math-editor' );
wp_enqueue_style( 'wp-components' );
wp_enqueue_style( 'site-health' );
wp_enqueue_style( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/elementor/assets/css/elementor.css', [ 'rank-math-common' ], rank_math()->version );
$media_query = '';
$dark_styles = $this->do_filter(
'elementor/dark_styles',
[
'rank-math-elementor-dark' => rank_math()->plugin_url() . 'includes/3rdparty/elementor/assets/css/elementor-dark.css',
]
);
if ( 'light' !== $mode ) {
$media_query = 'auto' === $mode ? '(prefers-color-scheme: dark)' : 'all';
foreach ( $dark_styles as $handle => $src ) {
wp_enqueue_style( $handle, $src, [], rank_math()->version, $media_query );
}
}
Helper::add_json( 'elementorDarkMode', $dark_styles );
wp_enqueue_script( 'rank-math-editor', rank_math()->plugin_url() . 'includes/3rdparty/elementor/assets/js/elementor.js', $deps, rank_math()->version, true );
rank_math()->variables->setup();
rank_math()->variables->setup_json();
}
/**
* Filters the post content before it is parsed for Sitmeap images..
* Used to apply the Elementor page editor on the post content.
*
* @since 1.0.38
*
* @param string $content The post content.
* @param int $post_id The post ID.
*
* @return string The post content.
*/
public function apply_builder_in_content( $content, $post_id ) {
if ( \Elementor\Plugin::$instance->db->is_built_with_elementor( $post_id ) ) {
return \Elementor\Plugin::$instance->frontend->get_builder_content( $post_id );
}
return $content;
}
/**
* Add SEO tab in Elementor Page Builder.
*
* @return bool
*/
private function can_add_seo_tab() {
/**
* Filter to show/hide SEO Tab in the Elementor Editor.
*/
if ( ! $this->do_filter( 'elementor/add_seo_tab', true ) ) {
return false;
}
$post_type = isset( $_GET['post'] ) ? get_post_type( $_GET['post'] ) : '';
if ( $post_type && ! Helper::get_settings( 'titles.pt_' . $post_type . '_add_meta_box' ) ) {
return false;
}
return Editor::can_add_editor();
}
/**
* Change robots for Elementor Templates pages
*
* @param array $robots Array of robots to sanitize.
*
* @return array Modified robots.
*/
public function robots( $robots ) {
if ( is_singular( 'elementor_library' ) ) {
$robots['index'] = 'noindex';
$robots['follow'] = 'nofollow';
}
return $robots;
}
}

View File

@@ -0,0 +1,487 @@
<?php
/**
* Admin bar menu.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath;
use RankMath\Paper\Paper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Meta;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Arr;
use RankMath\Helpers\Url;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Bar_Menu class.
*/
class Admin_Bar_Menu {
use Hooker, Ajax, Meta;
/**
* The unique identifier used for the menu.
*
* @var string
*/
const MENU_IDENTIFIER = 'rank-math';
/**
* Hold menu items.
*
* @var array
*/
private $items = [];
/**
* Constructor method.
*/
public function __construct() {
$this->ajax( 'mark_page_as', 'mark_page_as' );
$this->action( 'admin_bar_menu', 'add_menu', 100 );
}
/**
* AJAX function to mark page as Pillar Content/Noindex/Nofollow.
*/
public function mark_page_as() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
$what = Param::post( 'what', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
$object_id = Param::post( 'objectID', 0, FILTER_VALIDATE_INT );
$object_type = Param::post( 'objectType', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( ! $what || ! $object_id || ! $object_type ) {
return 0;
}
if ( 'pillar_content' === $what ) {
$current = $this->get_meta( $object_type, $object_id, 'rank_math_pillar_content' );
$updated = 'on' === $current ? 'off' : 'on';
$this->update_meta( $object_type, $object_id, 'rank_math_pillar_content', $updated );
die( '1' );
}
if ( 'noindex' === $what || 'nofollow' === $what ) {
$robots = (array) $this->get_meta( $object_type, $object_id, 'rank_math_robots' );
$robots = array_filter( $robots );
Arr::add_delete_value( $robots, $what );
$robots = $this->normalize_robots( $what, array_unique( $robots ) );
$this->update_meta( $object_type, $object_id, 'rank_math_robots', $robots );
if ( 'noindex' === $what ) {
$this->do_action( 'sitemap/invalidate_object_type', $object_type, $object_id );
}
die( '1' );
}
die();
}
/**
* Add SEO item to admin bar with context-specific submenu items.
*
* @param WP_Admin_Bar $wp_admin_bar Admin bar instance to add the menu to.
*/
public function add_menu( $wp_admin_bar ) {
if ( ! $this->can_add_menu() ) {
return;
}
$this->add_root_menu();
if ( Helper::has_cap( 'titles' ) ) {
$this->add_page_menu();
}
if ( $this->is_front() ) {
$this->add_seo_tools();
}
if ( $this->can_add_mark_menu() ) {
$this->add_mark_page_menu();
}
/**
* Add item to rank math admin bar node.
*
* @param Admin_Bar_Menu $this Class instance.
*/
$this->do_action( 'admin_bar/items', $this );
$this->add_order();
uasort( $this->items, [ $this, 'sort_by_priority' ] );
array_walk( $this->items, [ $wp_admin_bar, 'add_node' ] );
}
/**
* Normalize robots.
*
* @param string $what Current admin menu process.
* @param array $robots Array to normalize.
*
* @return array
*/
private function normalize_robots( $what, $robots ) {
if ( 'noindex' !== $what ) {
return $robots;
}
if ( ! in_array( 'noindex', $robots, true ) ) {
$robots[] = ! in_array( 'index', $robots, true ) ? 'index' : '';
return $robots;
}
if ( false !== ( $key = array_search( 'index', $robots ) ) ) { // @codingStandardsIgnoreLine
unset( $robots[ $key ] );
}
return $robots;
}
/**
* Keep original order when uasort() deals with equal "priority" values.
*/
private function add_order() {
$order = 0;
foreach ( $this->items as &$item ) {
$item['order'] = $order++;
}
}
/**
* Add root menu.
*/
private function add_root_menu() {
$first_menu = get_transient( 'rank_math_first_submenu_id' );
$first_menu = $first_menu && 'rank-math' !== $first_menu ? str_replace( 'rank-math-', '', $first_menu ) : '';
$this->items['main'] = [
'id' => self::MENU_IDENTIFIER,
'title' => '<span class="rank-math-icon">' . $this->get_icon() . '</span><span class="rank-math-text">' . esc_html__( 'Rank Math SEO', 'rank-math' ) . '</span>',
'href' => Helper::get_admin_url( $first_menu ),
'meta' => [ 'title' => esc_html__( 'Rank Math Dashboard', 'rank-math' ) ],
'priority' => 10,
];
if ( current_user_can( 'manage_options' ) ) {
$this->add_sub_menu(
'dashboard',
[
'title' => esc_html__( 'Dashboard', 'rank-math' ),
'href' => $this->items['main']['href'],
'meta' => [ 'title' => esc_html__( 'Dashboard', 'rank-math' ) ],
'priority' => 20,
]
);
}
}
/**
* Add page menu.
*/
private function add_page_menu() {
$hash = [
'add_home_menu' => is_front_page(),
'add_post_type_menu' => is_singular( Helper::get_accessible_post_types() ) || is_home(),
'add_date_menu' => is_date(),
'add_taxonomy_menu' => is_archive() && ! is_post_type_archive() && ! is_author(),
'add_search_menu' => is_search(),
];
foreach ( $hash as $func => $can_run ) {
if ( true === $can_run ) {
$this->$func();
break;
}
}
}
/**
* Add homepage menu
*/
private function add_home_menu() {
$this->add_sub_menu(
'home',
[
'title' => esc_html__( 'Homepage SEO', 'rank-math' ),
'href' => Helper::get_admin_url( 'options-titles#setting-panel-homepage' ),
'meta' => [ 'title' => esc_html__( 'Edit Homepage SEO Settings', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add post_type menu
*/
private function add_post_type_menu() {
$post_type = get_post_type();
if ( ! $post_type ) {
return;
}
$name = get_post_type_object( $post_type )->labels->name;
if ( is_home() ) {
$post_type = 'page';
$name = esc_html__( 'Pages', 'rank-math' );
}
$this->add_sub_menu(
'posttype',
[
/* translators: Post Type Singular Name */
'title' => sprintf( esc_html__( 'SEO Settings for %s', 'rank-math' ), $name ),
'href' => Helper::get_admin_url( 'options-titles#setting-panel-post-type-' . $post_type ),
'meta' => [ 'title' => esc_html__( 'Edit default SEO settings for this post type', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add taxonomy menu
*/
private function add_taxonomy_menu() {
$term = get_queried_object();
if ( empty( $term ) || ! ( $term instanceof \WP_Term ) ) {
return;
}
$labels = get_taxonomy_labels( get_taxonomy( $term->taxonomy ) );
$this->add_sub_menu(
'tax',
[
/* translators: Taxonomy Singular Name */
'title' => sprintf( esc_html__( 'SEO Settings for %s', 'rank-math' ), $labels->name ),
'href' => Helper::get_admin_url( 'options-titles#setting-panel-taxonomy-' . $term->taxonomy ),
'meta' => [ 'title' => esc_html__( 'Edit SEO settings for this archive page', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add date archive menu
*/
private function add_date_menu() {
$this->add_sub_menu(
'date',
[
'title' => esc_html__( 'SEO Settings for Date Archives', 'rank-math' ),
'href' => Helper::get_admin_url( 'options-titles#setting-panel-global' ),
'meta' => [ 'title' => esc_html__( 'Edit SEO settings for this archive page', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add search result menu
*/
private function add_search_menu() {
$this->add_sub_menu(
'search',
[
'title' => esc_html__( 'SEO Settings for Search Page', 'rank-math' ),
'href' => Helper::get_admin_url( 'options-titles#setting-panel-global' ),
'meta' => [ 'title' => esc_html__( 'Edit SEO settings for the search results page', 'rank-math' ) ],
'priority' => 35,
]
);
}
/**
* Add mark page menu.
*/
private function add_mark_page_menu() {
$this->add_sub_menu(
'mark-me',
[
'title' => esc_html__( 'Mark this page', 'rank-math' ),
'href' => '#',
'priority' => 100,
]
);
$is_pillar_content = '';
$dashicon_format = '<span class="dashicons dashicons-%s rm-mark-page-icon"></span>';
if ( is_singular( Helper::get_accessible_post_types() ) ) {
if ( get_post_meta( get_the_ID(), 'rank_math_pillar_content', true ) === 'on' ) {
$is_pillar_content = sprintf( $dashicon_format, 'yes' );
}
$this->add_sub_menu(
'pillar-content',
[
'title' => $is_pillar_content . esc_html__( 'As Pillar Content', 'rank-math' ),
'href' => '#pillar_content',
'meta' => [ 'class' => 'mark-page-as' ],
],
'mark-me'
);
}
if ( Paper::get() ) {
$robots = Paper::get()->get_robots();
$noindex_check = in_array( 'noindex', $robots, true ) ? sprintf( $dashicon_format, 'yes' ) : '';
$this->add_sub_menu(
'no-index',
[
'title' => $noindex_check . esc_html__( 'As NoIndex', 'rank-math' ),
'href' => '#noindex',
'meta' => [ 'class' => 'mark-page-as' ],
],
'mark-me'
);
$nofollow_check = in_array( 'nofollow', $robots, true ) ? sprintf( $dashicon_format, 'yes' ) : '';
$this->add_sub_menu(
'no-follow',
[
'title' => $nofollow_check . esc_html__( 'As NoFollow', 'rank-math' ),
'href' => '#nofollow',
'meta' => [ 'class' => 'mark-page-as' ],
],
'mark-me'
);
}
}
/**
* Third party SEO Tools, like the Google Structured Data Testing Tool.
*/
private function add_seo_tools() {
$this->add_sub_menu(
'third-party',
[
'title' => esc_html__( 'External Tools', 'rank-math' ),
'href' => '#',
'priority' => 200,
]
);
$url = rawurlencode( Url::get_current_url() );
$items = [
'google-pagespeed' => [
'title' => esc_html__( 'Google PageSpeed', 'rank-math' ),
'href' => 'https://developers.google.com/speed/pagespeed/insights/?url=' . $url,
'meta' => [ 'title' => esc_html__( 'Google PageSpeed Insights', 'rank-math' ) ],
],
'google-richresults-mobile' => [
'title' => esc_html__( 'Google Rich Results (Mobile)', 'rank-math' ),
'href' => 'https://search.google.com/test/rich-results?url=' . $url . '&user_agent=1',
'meta' => [ 'title' => esc_html__( 'Google Rich Results Test - Googlebot Smartphone', 'rank-math' ) ],
],
'google-richresults-desktop' => [
'title' => esc_html__( 'Google Rich Results (Desktop)', 'rank-math' ),
'href' => 'https://search.google.com/test/rich-results?url=' . $url . '&user_agent=2',
'meta' => [ 'title' => esc_html__( 'Google Rich Results Test - Googlebot Desktop', 'rank-math' ) ],
],
'google-cache' => [
'title' => esc_html__( 'Google Cache', 'rank-math' ),
'href' => 'https://webcache.googleusercontent.com/search?q=cache:' . $url,
'meta' => [ 'title' => esc_html__( 'See Google\'s cached version of your site', 'rank-math' ) ],
],
'fb-debugger' => [
'title' => esc_html__( 'Facebook Debugger', 'rank-math' ),
'href' => 'https://developers.facebook.com/tools/debug/sharing/?q=' . $url,
'meta' => [ 'title' => esc_html__( 'Facebook Sharing Debugger', 'rank-math' ) ],
],
];
foreach ( $items as $id => $args ) {
$args['meta']['target'] = '_blank';
$this->add_sub_menu( $id, $args, 'third-party' );
}
}
/**
* Add sub menu item
*
* @param string $id Unique ID for the node.
* @param array $args Arguments for adding a node.
* @param string $parent Node parent.
*/
public function add_sub_menu( $id, $args, $parent = '' ) {
$args['priority'] = isset( $args['priority'] ) ? $args['priority'] : 999;
$args['id'] = 'rank-math-' . $id;
$args['parent'] = '' !== $parent ? 'rank-math-' . $parent : self::MENU_IDENTIFIER;
$this->items[ $id ] = $args;
}
/**
* Can current user has capability for admin menu.
*
* @return bool
*/
private function can_add_menu() {
return Helper::has_cap( 'admin_bar' );
}
/**
* Can add mark me menu.
*
* @return bool
*/
private function can_add_mark_menu() {
return $this->is_front() && Helper::has_cap( 'onpage_general' );
}
/**
* Is frontend.
*
* @return bool
*/
private function is_front() {
return ! is_admin() && ! is_preview();
}
/**
* Sort admin bar items callback.
*
* @param array $item1 Item A to compare.
* @param array $item2 Item B to compare.
*
* @return integer
*/
private function sort_by_priority( $item1, $item2 ) {
if ( $item1['priority'] === $item2['priority'] ) {
return $item1['order'] < $item2['order'] ? -1 : 1;
}
return $item1['priority'] < $item2['priority'] ? -1 : 1;
}
/**
* Get Rank Math icon.
*
* @param integer $width Width of the icon.
*
* @return string
*/
private function get_icon( $width = 20 ) {
return '<svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="' . $width . '"><g><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"/><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"/></g></svg>';
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Breadcrumbs for the Rank Math pages
*
* @since 1.0.44
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin Header class.
*
* @codeCoverageIgnore
*/
class Admin_Breadcrumbs {
/**
* Display Header.
*/
public function display() {
?>
<div class="rank-math-breadcrumbs-wrap">
<div class="rank-math-breadcrumbs">
<span><?php echo esc_html__( 'Dashboard', 'rank-math' ); ?></span>
<span class="divider">/</span>
<span class="active"><?php echo esc_html( $this->get_page_title() ); ?></span>
</div>
</div>
<?php
}
/**
* Get Current Admin Page Title.
*/
private function get_page_title() {
$base = __( 'Modules', 'rank-math' );
if ( is_network_admin() ) {
$base = __( 'Help', 'rank-math' );
}
$default = 'rank-math' === Param::get( 'page' ) ? $base : get_admin_page_title();
return str_replace( '_', ' ', Param::get( 'view', $default, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK ) );
}
}

View File

@@ -0,0 +1,135 @@
<?php
/**
* The nav tabs on the Dashboard page.
*
* @since 1.0.40
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin Dashboard Nav class.
*
* @codeCoverageIgnore
*/
class Admin_Dashboard_Nav {
/**
* Display dashboard tabs.
*/
public function display() {
$nav_links = $this->get_nav_links();
if ( empty( $nav_links ) ) {
return;
}
?>
<div class="rank-math-tab-nav" role="tablist" aria-orientation="horizontal">
<?php
foreach ( $nav_links as $id => $link ) {
$this->nav_link( $link );
}
?>
</div>
<?php
}
/**
* Get URL for dashboard nav links.
*
* @param array $link Link data.
* @return string Link URL.
*/
public function get_link_url( $link ) {
return is_network_admin() ?
Security::add_query_arg(
[
'page' => 'rank-math',
'view' => $link['id'],
],
network_admin_url( 'admin.php' )
) :
Helper::get_admin_url( $link['url'], $link['args'] );
}
/**
* Output dashboard nav link.
*
* @param array $link Link data.
* @return void
*/
public function nav_link( $link ) {
if ( isset( $link['cap'] ) && ! current_user_can( $link['cap'] ) ) {
return;
}
$default_tab = is_network_admin() ? 'help' : 'modules';
?>
<a
class="rank-math-tab<?php echo Param::get( 'view', $default_tab ) === sanitize_html_class( $link['id'] ) ? ' is-active' : ''; ?>"
href="<?php echo esc_url( $this->get_link_url( $link ) ); ?>"
title="<?php echo esc_attr( $link['title'] ); ?>">
<?php echo esc_html( $link['title'] ); ?>
</a>
<?php
}
/**
* Get dashbaord navigation links
*
* @return array
*/
private function get_nav_links() {
$links = [
'modules' => [
'id' => 'modules',
'url' => '',
'args' => 'view=modules',
'cap' => 'manage_options',
'title' => esc_html__( 'Modules', 'rank-math' ),
],
'help' => [
'id' => 'help',
'url' => '',
'args' => 'view=help',
'cap' => 'manage_options',
'title' => esc_html__( 'Help', 'rank-math' ),
],
'wizard' => [
'id' => 'wizard',
'url' => 'wizard',
'args' => '',
'cap' => 'manage_options',
'title' => esc_html__( 'Setup Wizard', 'rank-math' ),
],
];
if ( Helper::is_advanced_mode() ) {
$links['import-export'] = [
'id' => 'import-export',
'url' => 'status',
'args' => 'view=import_export',
'cap' => 'install_plugins',
'title' => esc_html__( 'Import &amp; Export', 'rank-math' ),
];
}
if ( Helper::is_plugin_active_for_network() ) {
unset( $links['help'] );
}
if ( is_network_admin() ) {
$links = [];
}
return apply_filters( 'rank_math/admin/dashboard_nav_links', $links );
}
}

View File

@@ -0,0 +1,151 @@
<?php
/**
* Header for the Rank Math pages
*
* @since 1.0.44
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\KB;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin Header class.
*
* @codeCoverageIgnore
*/
class Admin_Header {
/**
* Hold current screen ID.
*
* @var Current screen ID.
*/
private $screen_id = '';
/**
* Display Header.
*/
public function display() {
$logo_url = '<a href="' . esc_url( Helper::get_admin_url() ) . '"><i class="rm-icon rm-icon-rank-math"></i></a>';
$this->screen_id = $this->get_current_screen();
?>
<div class="rank-math-header">
<div class="rank-math-logo">
<?php echo $logo_url; // phpcs:ignore ?>
</div>
<h1 class="rank-math-logo-text">
Rank Math SEO
<?php do_action( 'rank_math/pro_badge' ); ?>
</h1>
<?php $this->get_search_options(); ?>
<?php $this->get_mode_selector(); ?>
<?php do_action( 'rank_math/before_help_link' ); ?>
<a href="<?php echo esc_url( $this->get_help_link() ); ?>" title="<?php esc_attr_e( 'Rank Math Knowledge Base', 'rank-math' ); ?>" target="_blank" class="button rank-math-help"><i class="dashicons dashicons-editor-help"></i></a>
</div>
<?php
// Breadcrumbs.
rank_math()->admin->display_admin_breadcrumbs();
}
/**
* Get Search Options.
*/
private function get_search_options() {
if (
! in_array(
$this->screen_id,
[
'rank-math_page_rank-math-options-general',
'rank-math_page_rank-math-options-titles',
'rank-math_page_rank-math-options-sitemap',
],
true
)
) {
return;
}
?>
<div class="rank-math-search-options">
<div class="search-field">
<i class="rm-icon rm-icon-search"></i>
<input type="text" value="" placeholder="<?php esc_attr_e( 'Search Options', 'rank-math' ); ?>">
<em class="clear-search dashicons dashicons-no-alt"></em>
</div>
</div>
<?php
}
/**
* Get Mode Selector.
*/
private function get_mode_selector() {
if (
! in_array(
$this->screen_id,
[
'toplevel_page_rank-math',
'rank-math_page_rank-math-status',
],
true
)
) {
return;
}
$is_advanced_mode = Helper::is_advanced_mode();
?>
<div class="rank-math-mode-selector">
<a href="#" class="<?php echo ! $is_advanced_mode ? 'active' : ''; ?>" data-mode="easy"><?php esc_attr_e( 'Easy Mode', 'rank-math' ); ?></a>
<a href="#" class="<?php echo $is_advanced_mode ? 'active' : ''; ?>" data-mode="advanced"><?php esc_attr_e( 'Advanced Mode', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Get Current Screen ID.
*/
private function get_help_link() {
$links = [
'import-export-settings' => 'import_export' === Param::get( 'view' ),
'version-control' => 'version_control' === Param::get( 'view' ) || 'rank-math-status' === Param::get( 'page' ),
'general-settings' => 'rank-math-options-general' === Param::get( 'page' ),
'titles-meta' => 'rank-math-options-titles' === Param::get( 'page' ),
'sitemap-general' => 'rank-math-options-sitemap' === Param::get( 'page' ),
'role-manager' => 'rank-math-role-manager' === Param::get( 'page' ),
'seo-analysis' => 'rank-math-seo-analysis' === Param::get( 'page' ),
'content-ai-restore-credits' => 'rank-math-content-ai-page' === Param::get( 'page' ),
];
$link = KB::get( 'knowledgebase', 'RM Header KB Icon' );
foreach ( $links as $key => $value ) {
if ( $value ) {
$link = KB::get( $key, 'Admin Bar ' . ucwords( str_replace( '-', ' ', $key ) ) );
break;
}
}
return $link;
}
/**
* Get Current Screen ID.
*/
private function get_current_screen() {
$screen = get_current_screen();
if ( empty( $screen ) ) {
return '';
}
return $screen->id;
}
}

View File

@@ -0,0 +1,468 @@
<?php
/**
* Admin helper Functions.
*
* This file contains functions needed on the admin screens.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Data_Encryption;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Helper class.
*/
class Admin_Helper {
/**
* Get .htaccess related data.
*
* @return array
*/
public static function get_htaccess_data() {
if ( ! Helper::is_filesystem_direct() ) {
return [
'content' => '',
'writable' => false,
];
}
$wp_filesystem = Helper::get_filesystem();
if ( empty( $wp_filesystem ) ) {
return;
}
$htaccess_file = get_home_path() . '.htaccess';
return ! $wp_filesystem->exists( $htaccess_file ) ? false : [
'content' => $wp_filesystem->get_contents( $htaccess_file ),
'writable' => $wp_filesystem->is_writable( $htaccess_file ),
];
}
/**
* Get tooltip HTML.
*
* @param string $message Message to show in tooltip.
*
* @return string
*/
public static function get_tooltip( $message ) {
return '<span class="rank-math-tooltip"><em class="dashicons-before dashicons-editor-help"></em><span>' . $message . '</span></span>';
}
/**
* Get admin view file.
*
* @param string $view View filename.
*
* @return string Complete path to view
*/
public static function get_view( $view ) {
$view = sanitize_key( $view );
$view = rank_math()->admin_dir() . "views/{$view}.php";
if ( ! file_exists( $view ) ) {
Helper::redirect( Helper::get_admin_url() );
exit;
}
return $view;
}
/**
* Get taxonomies as choices.
*
* @param array $args (Optional) Arguments passed to filter list.
*
* @return array|bool
*/
public static function get_taxonomies_options( $args = [] ) {
global $wp_taxonomies;
$args = wp_parse_args( $args, [ 'public' => true ] );
$taxonomies = wp_filter_object_list( $wp_taxonomies, $args, 'and', 'label' );
return empty( $taxonomies ) ? false : [ 'off' => esc_html__( 'None', 'rank-math' ) ] + $taxonomies;
}
/**
* Registration data get/update.
*
* @param array|bool|null $data Array of data to save.
*
* @return array
*/
public static function get_registration_data( $data = null ) {
$row = 'rank_math_connect_data';
$keys = [
'username',
'email',
'api_key',
'plan',
];
// Setter.
if ( ! is_null( $data ) ) {
if ( false === $data ) {
update_option( 'rank_math_registration_skip', 1 );
return delete_option( $row );
}
foreach ( $keys as $key ) {
if ( isset( $data[ $key ] ) ) {
$data[ $key ] = Data_Encryption::encrypt( $data[ $key ] );
}
}
Helper::remove_notification( 'rank-math-site-url-mismatch' );
update_option( 'rank_math_registration_skip', 1 );
$connected = update_option( $row, $data );
do_action( 'rank_math/connect/account_connected', $data );
return $connected;
}
// Getter.
$options = Helper::is_plugin_active_for_network() ? get_blog_option( get_main_site_id(), $row, false ) : get_option( $row, false );
if ( empty( $options ) ) {
return false;
}
foreach ( $keys as $key ) {
if ( isset( $options[ $key ] ) ) {
$options[ $key ] = Data_Encryption::decrypt( $options[ $key ] );
}
}
if ( ! self::is_valid_registration( $options ) ) {
// Delete invalid registration data.
delete_option( $row );
// Ask the user to reconnect.
Helper::add_notification(
__( 'Unable to validate Rank Math SEO registration data.', 'rank-math' ) .
' <a href="' . esc_url( self::get_activate_url() ) . '">' . __( 'Please try reconnecting.', 'rank-math' ) . '</a> ' .
sprintf(
/* translators: KB Link */
__( 'If the issue persists, please try the solution described in our Knowledge Base article: %s', 'rank-math' ),
'<a href="' . KB::get( 'unable-to-encrypt', 'Registration Data' ) . '" target="_blank">' . __( '[3. Unable to Encrypt]', 'rank-math' ) . '</a>'
),
[ 'type' => 'error' ]
);
return false;
}
/**
* Filter whether we need to check for URL mismatch or not.
*/
$do_url_check = apply_filters( 'rank_math/registration/do_url_check', ! get_option( 'rank_math_siteurl_mismatch_notice_dismissed' ) );
if ( $do_url_check && isset( $options['site_url'] ) && Helper::get_home_url() !== $options['site_url'] ) {
$message = esc_html__( 'Seems like your site URL has changed since you connected to Rank Math.', 'rank-math' ) . ' <a href="' . self::get_activate_url() . '">' . esc_html__( 'Click here to reconnect.', 'rank-math' ) . '</a>';
Helper::add_notification(
$message,
[
'type' => 'warning',
'id' => 'rank-math-site-url-mismatch',
]
);
}
/**
* Ensure the site_url is returned if it is absent, as it is required for the Content AI.
*/
if ( empty( $options['site_url'] ) ) {
$options['site_url'] = Helper::get_home_url();
}
return $options;
}
/**
* Check if registration data is valid.
*
* @param array $data Registration data.
*
* @return bool
*/
public static function is_valid_registration( $data ) {
if ( empty( $data['username'] ) || empty( $data['email'] ) || empty( $data['api_key'] ) || empty( $data['plan'] ) ) {
return false;
}
if ( ! filter_var( $data['email'], FILTER_VALIDATE_EMAIL ) ) {
return false;
}
if ( strlen( $data['plan'] ) > 32 ) { // This can happen when the decryption fails for some reason.
return false;
}
return true;
}
/**
* Get user plan.
*/
public static function get_user_plan() {
$data = self::get_registration_data();
return $data['plan'];
}
/**
* Is user plan expired.
*
* @return boolean
*/
public static function is_plan_expired() {
$data = self::get_registration_data();
if ( ! isset( $data['plan'] ) ) {
return true;
}
return 'free' === $data['plan'];
}
/**
* Remove registration data and disconnect from RankMath.com.
*/
public static function deregister_user() {
$registered = self::get_registration_data();
if ( $registered && isset( $registered['username'] ) && isset( $registered['api_key'] ) ) {
Api::get()->deactivate_site( $registered['username'], $registered['api_key'] );
self::get_registration_data( false );
do_action( 'rank_math/deregister_site' );
}
}
/**
* Check if current page is media list page.
*
* @return bool
*/
public static function is_media_library() {
global $pagenow;
return 'upload.php' === $pagenow;
}
/**
* Check if current page is post list page.
*
* @return bool
*/
public static function is_post_list() {
global $pagenow;
return 'edit.php' === $pagenow;
}
/**
* Check if current page is post create/edit screen.
*
* @return bool
*/
public static function is_post_edit() {
global $pagenow;
return ! Helper::is_ux_builder() && ( 'post.php' === $pagenow || 'post-new.php' === $pagenow );
}
/**
* Check if current page is term create/edit screen.
*
* @return bool
*/
public static function is_term_edit() {
global $pagenow;
return 'term.php' === $pagenow || 'edit-tags.php' === $pagenow;
}
/**
* Check if current page is user create/edit screen.
*
* @return bool
*/
public static function is_user_edit() {
global $pagenow;
return 'profile.php' === $pagenow || 'user-edit.php' === $pagenow;
}
/**
* Check if current page is user or term create/edit screen.
*
* @return bool
*/
public static function is_term_profile_page() {
global $pagenow;
return self::is_term_edit() || self::is_user_edit();
}
/**
* Get Social Share buttons.
*
* @codeCoverageIgnore
*/
public static function get_social_share() {
if ( Helper::is_whitelabel() ) {
return;
}
$tw_link = KB::get( 'logo', 'Setup Wizard Tweet Button' );
$fb_link = rawurlencode( KB::get( 'logo', 'Facebook' ) );
/* translators: sitename */
$tw_message = rawurlencode( sprintf( esc_html__( 'I just installed @RankMathSEO #WordPress Plugin. It looks great! %s', 'rank-math' ), $tw_link ) );
/* translators: sitename */
$fb_message = rawurlencode( esc_html__( 'I just installed Rank Math SEO WordPress Plugin. It looks promising!', 'rank-math' ) );
$tweet_url = Security::add_query_arg(
[
'text' => $tw_message,
'hashtags' => 'SEO',
],
'https://twitter.com/intent/tweet'
);
$fb_share_url = Security::add_query_arg(
[
'u' => $fb_link,
'quote' => $fb_message,
'caption' => esc_html__( 'SEO by Rank Math', 'rank-math' ),
],
'https://www.facebook.com/sharer/sharer.php'
);
?>
<span class="wizard-share">
<a href="#" onclick="window.open('<?php echo $tweet_url; ?>', 'sharewindow', 'resizable,width=600,height=300'); return false;" class="share-twitter">
<span class="dashicons dashicons-twitter"></span> <?php esc_html_e( 'Tweet', 'rank-math' ); ?>
</a>
<a href="#" onclick="window.open('<?php echo $fb_share_url; ?>', 'sharewindow', 'resizable,width=600,height=300'); return false;" class="share-facebook">
<span class="dashicons dashicons-facebook-alt"></span> <?php esc_html_e( 'Share', 'rank-math' ); ?>
</a>
</span>
<?php
}
/**
* Get product activation URL.
*
* @param string $redirect_to Redirecto url.
*
* @return string Activate URL.
*/
public static function get_activate_url( $redirect_to = null ) {
if ( empty( $redirect_to ) ) {
$redirect_to = Security::add_query_arg_raw(
[
'page' => 'rank-math',
'view' => 'help',
'nonce' => wp_create_nonce( 'rank_math_register_product' ),
],
( is_multisite() && is_plugin_active_for_network( plugin_basename( RANK_MATH_FILE ) ) ) ? network_admin_url( 'admin.php' ) : admin_url( 'admin.php' )
);
} else {
$redirect_to = Security::add_query_arg_raw(
[
'nonce' => wp_create_nonce( 'rank_math_register_product' ),
],
$redirect_to
);
}
$args = [
'site' => rawurlencode( home_url() ),
'r' => rawurlencode( $redirect_to ),
];
return apply_filters(
'rank_math/license/activate_url',
Security::add_query_arg_raw( $args, RANK_MATH_SITE_URL . '/auth' ),
$args
);
}
/**
* Check if page is set as Homepage.
*
* @since 1.0.42
*
* @return boolean
*/
public static function is_home_page() {
$front_page = (int) get_option( 'page_on_front' );
if ( Helper::is_divi_frontend_editor() ) {
$p = get_post();
return ! empty( $p->ID ) && $p->ID === $front_page;
}
return $front_page && self::is_post_edit() && (int) Param::get( 'post' ) === $front_page;
}
/**
* Check if page is set as Posts Page.
*
* @since 1.0.43
*
* @return boolean
*/
public static function is_posts_page() {
$posts_page = (int) get_option( 'page_for_posts' );
return $posts_page && self::is_post_edit() && (int) Param::get( 'post' ) === $posts_page;
}
/**
* Get Trends icon <svg> element.
*
* @return string
*/
public static function get_trends_icon_svg() {
return '<svg viewBox="0 0 610 610"><path d="M18.85,446,174.32,290.48l58.08,58.08L76.93,504a14.54,14.54,0,0,1-20.55,0L18.83,466.48a14.54,14.54,0,0,1,0-20.55Z" style="fill:#4285f4"/><path d="M242.65,242.66,377.59,377.6l-47.75,47.75a14.54,14.54,0,0,1-20.55,0L174.37,290.43l47.75-47.75A14.52,14.52,0,0,1,242.65,242.66Z" style="fill:#ea4335"/><polygon points="319.53 319.53 479.26 159.8 537.34 217.88 377.61 377.62 319.53 319.53" style="fill:#fabb05"/><path d="M594.26,262.73V118.61h0a16.94,16.94,0,0,0-16.94-16.94H433.2a16.94,16.94,0,0,0-12,28.92L565.34,274.71h0a16.94,16.94,0,0,0,28.92-12Z" style="fill:#34a853"/><rect width="610" height="610" style="fill:none"/></svg>';
}
/**
* Check if siteurl & home options are both valid URLs.
*
* @return boolean
*/
public static function is_site_url_valid() {
return (bool) filter_var( get_option( 'siteurl' ), FILTER_VALIDATE_URL ) && (bool) filter_var( get_option( 'home' ), FILTER_VALIDATE_URL );
}
/**
* Maybe show notice about invalid siteurl.
*/
public static function maybe_show_invalid_siteurl_notice() {
if ( ! self::is_site_url_valid() ) {
?>
<p class="notice notice-warning notice-alt notice-connect-disabled">
<?php
printf(
// Translators: 1 is "WordPress Address (URL)", 2 is "Site Address (URL)", 3 is a link to the General Settings, with "WordPress General Settings" as anchor text.
esc_html__( 'Rank Math cannot be connected because your site URL doesn\'t appear to be a valid URL. If the domain name contains special characters, please make sure to use the encoded version in the %1$s &amp; %2$s fields on the %3$s page.', 'rank-math' ),
'<strong>' . esc_html__( 'WordPress Address (URL)', 'rank-math' ) . '</strong>',
'<strong>' . esc_html__( 'Site Address (URL)', 'rank-math' ) . '</strong>',
'<a href="' . esc_url( admin_url( 'options-general.php' ) ) . '">' . esc_html__( 'WordPress General Settings', 'rank-math' ) . '</a>'
);
?>
</p>
<?php
}
}
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* The admin bootstrap of the plugin.
*
* @since 1.0.9
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Updates;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Init class.
*
* @codeCoverageIgnore
*/
class Admin_Init {
use Hooker;
/**
* The Constructor.
*/
public function __construct() {
rank_math()->admin = new Admin();
rank_math()->admin_assets = new Assets();
$this->load_review_reminders();
$this->load_pro_notice();
$this->load_setup_wizard();
$this->load_post_columns_and_filters();
$this->run(
[
rank_math()->admin,
rank_math()->admin_assets,
new Admin_Menu(),
new Option_Center(),
new Notices(),
new CMB2_Fields(),
new Metabox\Metabox(),
new Import_Export(),
new Updates(),
new Watcher(),
]
);
/**
* Fires when admin is loaded.
*/
$this->do_action( 'admin/loaded' );
}
/**
* Load out post list and edit screen class.
*/
private function load_post_columns_and_filters() {
$this->run( [ new Bulk_Actions() ] );
if ( Admin_Helper::is_post_list() || Admin_Helper::is_media_library() || wp_doing_ajax() ) {
$this->run(
[
new Post_Columns(),
new Post_Filters(),
]
);
}
}
/**
* Load review tab in metabox & footer notice.
*/
private function load_review_reminders() {
if ( get_option( 'rank_math_already_reviewed' ) ) {
return;
}
$this->run( [ new Ask_Review() ] );
}
/**
* Load Pro reminder notice.
*/
private function load_pro_notice() {
if ( ! is_main_site() ) {
return;
}
if ( defined( 'RANK_MATH_PRO_FILE' ) || get_option( 'rank_math_already_upgraded' ) ) {
return;
}
$this->run( [ new Pro_Notice() ] );
}
/**
* Run all the runners.
*
* @param array $runners Instances of runner classes.
*/
private function run( $runners ) {
foreach ( $runners as $runner ) {
$runner->hooks();
}
}
/**
* Load setup wizard.
*/
private function load_setup_wizard() {
if ( Helper::is_wizard() ) {
new Setup_Wizard();
}
}
}

View File

@@ -0,0 +1,269 @@
<?php
/**
* The admin pages of the plugin.
*
* @since 1.0.9
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Traits\Ajax;
use RankMath\Admin\Page;
defined( 'ABSPATH' ) || exit;
/**
* Admin_Menu class.
*
* @codeCoverageIgnore
*/
class Admin_Menu implements Runner {
use Hooker, Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'register_pages' );
$this->action( 'admin_menu', 'fix_admin_menu', 999 );
$this->action( 'admin_head', 'icon_css' );
$this->ajax( 'remove_offer_page', 'remove_offer_page' );
}
/**
* Register admin pages for plugin.
*/
public function register_pages() {
$this->maybe_deregister();
if ( Helper::is_invalid_registration() && ! is_network_admin() ) {
return;
}
$current_user = wp_get_current_user();
$capabilities = array_keys( Helper::get_roles_capabilities() );
if ( empty( array_intersect( $current_user->roles, $capabilities ) ) && ! current_user_can( 'setup_network' ) ) {
return;
}
// Dashboard / Welcome / About.
new Page(
'rank-math',
esc_html__( 'Rank Math', 'rank-math' ),
[
'position' => 50,
'menu_title' => 'Rank Math',
'capability' => 'level_1',
'icon' => 'data:image/svg+xml;base64,' . \base64_encode( '<svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="20"><g fill="#fff"><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"/><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"/></g></svg>' ),
'render' => Admin_Helper::get_view( 'dashboard' ),
'classes' => [ 'rank-math-page' ],
'assets' => [
'styles' => [ 'rank-math-dashboard' => '' ],
'scripts' => [
'rank-math-dashboard' => '',
],
],
'is_network' => is_network_admin() && Helper::is_plugin_active_for_network(),
]
);
}
/**
* Fix menu names.
*/
public function fix_admin_menu() {
// Replace the main menu name "Rank Math" with "Rank Math SEO".
global $menu;
foreach ( $menu as $key => $item ) {
if ( 'Rank Math' === $item[0] ) {
$menu[ $key ][0] = esc_html__( 'Rank Math SEO', 'rank-math' );
break;
}
}
// Replace the first submenu name "Rank Math" with "Dashboard".
global $submenu;
if ( ! isset( $submenu['rank-math'] ) ) {
return;
}
if ( 'Rank Math' === $submenu['rank-math'][0][0] ) {
if ( current_user_can( 'manage_options' ) ) {
$plan = Helper::get_content_ai_plan();
$notification = ( empty( $plan ) || 'free' === $plan ) && get_option( 'rank_math_view_modules' ) ? ' <span class="awaiting-mod count-1"><span class="pending-count" aria-hidden="true">1</span></span>' : '';
$submenu['rank-math'][0][0] = esc_html__( 'Dashboard', 'rank-math' ) . $notification;
} else {
unset( $submenu['rank-math'][0] );
}
}
if ( empty( $submenu['rank-math'] ) ) {
return;
}
$submenu['rank-math'][] = [ esc_html__( 'Help &amp; Support', 'rank-math' ) . '<i class="dashicons dashicons-external" style="font-size:12px;vertical-align:-2px;height:10px;"></i>', 'level_1', KB::get( 'knowledgebase', 'Sidebar Help Link' ) ];
$this->add_offer_link( $submenu );
// Store ID of first_menu item so we can use it in the Admin menu item.
set_transient( 'rank_math_first_submenu_id', array_values( $submenu['rank-math'] )[0][2] );
}
/**
* Print icon CSS for admin menu bar.
*/
public function icon_css() {
?>
<script type="text/javascript">
// Open RM KB menu link in the new tab.
jQuery( document ).ready( function( $ ) {
$( "ul#adminmenu a[href$='<?php KB::the( 'knowledgebase', 'Sidebar Help Link' ); ?>']" ).attr( 'target', '_blank' );
$( "ul#adminmenu a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>']" ).attr( 'target', '_blank' ).on( 'click', function() {
$( this ).remove()
$.ajax( {
url: window.ajaxurl,
type: 'POST',
data: {
action: 'rank_math_remove_offer_page',
security: rankMath.security,
},
} )
} );
} );
</script>
<style>
#wp-admin-bar-rank-math .rank-math-icon {
display: inline-block;
top: 6px;
position: relative;
padding-right: 10px;
max-width: 20px;
}
#wp-admin-bar-rank-math .rank-math-icon svg {
fill-rule: evenodd;
fill: #dedede;
}
#wp-admin-bar-rank-math:hover .rank-math-icon svg {
fill-rule: evenodd;
fill: #00b9eb;
}
#toplevel_page_rank-math:not(.wp-has-submenu) {
display: none;
}
.multisite.network-admin #toplevel_page_rank-math {
display: block;
}
#toplevel_page_rank-math a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>'],
#toplevel_page_rank-math a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>']:hover,
#toplevel_page_rank-math a[href$='<?php KB::the( 'offer', 'Offer Menu Item' ); ?>']:focus {
background-color: #10AC84;
color: #fff;
}
</style>
<?php
}
/**
* Check for deactivation.
*/
private function maybe_deregister() {
if ( ! Helper::has_cap( 'general' ) || 'deregister' !== Param::post( 'registration-action' ) ) {
return;
}
$nonce = Param::post( '_wpnonce' );
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'rank_math_register_product' ) ) {
return;
}
Admin_Helper::deregister_user();
}
/**
* Function to add Offer link based on the date range.
*
* @param array $submenu Submenu items.
*/
private function add_offer_link( &$submenu ) {
$offer = $this->get_active_offer();
if ( ! $offer ) {
return;
}
$submenu['rank-math'][] = [ current( $offer ) . '&nbsp;', 'level_1', KB::get( 'offer', 'Offer Menu Item' ) ];
}
/**
* Ajax handler callback to store active offer so it doesn't show up again on the site.
*/
public function remove_offer_page() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$offer = $this->get_active_offer();
set_site_transient( 'rank_math_active_offer', key( $offer ) );
}
/**
* Function to get active offer
*/
private function get_active_offer() {
// Early Bail if PRO plugin is active.
if ( defined( 'RANK_MATH_PRO_FILE' ) ) {
return false;
}
$timezone = new \DateTimeZone( 'Asia/Kolkata' );
$current_date = new \DateTime( 'now', $timezone );
$dates = [
'christmas' => [
'start' => '2023-12-17',
'end' => '2023-12-26',
'text' => esc_html__( 'Christmas Sale', 'rank-math' ),
],
'new-year' => [
'start' => '2023-12-31',
'end' => '2024-01-05',
'text' => esc_html__( 'New Year Sale', 'rank-math' ),
],
'anniversary' => [
'start' => '2024-11-06',
'end' => '2024-11-13',
'text' => esc_html__( 'Anniversary Sale', 'rank-math' ),
],
'black-friday' => [
'start' => '2024-11-27',
'end' => '2024-12-01',
'text' => esc_html__( 'Black Friday Sale', 'rank-math' ),
],
'cyber-monday' => [
'start' => '2024-12-02',
'end' => '2024-12-04',
'text' => esc_html__( 'Cyber Monday Sale', 'rank-math' ),
],
];
$stored_offer = get_site_transient( 'rank_math_active_offer' );
$active_offer = '';
foreach ( $dates as $key => $date ) {
$start_date = new \DateTime( $date['start'] . ' 16:00:00', $timezone );
$end_date = new \DateTime( $date['end'] . ' 16:00:00', $timezone );
if ( $stored_offer !== $key && $current_date >= $start_date && $current_date <= $end_date ) {
$active_offer = [ $key => $date['text'] ];
break;
}
}
return $active_offer;
}
}

View File

@@ -0,0 +1,493 @@
<?php
/**
* The admin-specific functionality of the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Helper;
use RankMath\Helpers\Str;
use RankMath\Helpers\Param;
use RankMath\Admin\Admin_Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Admin class.
*
* @codeCoverageIgnore
*/
class Admin implements Runner {
use Hooker, Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'flush', 999 );
$this->filter( 'user_contactmethods', 'update_user_contactmethods' );
$this->action( 'admin_footer', 'convert_additional_profile_url_to_textarea' );
$this->action( 'save_post', 'canonical_check_notice' );
$this->action( 'cmb2_save_options-page_fields', 'update_is_configured_value', 10, 2 );
$this->filter( 'action_scheduler_pastdue_actions_check_pre', 'as_exclude_pastdue_actions' );
$this->action( 'rank_math/pro_badge', 'offer_icon' );
$this->filter( 'load_script_translation_file', 'load_script_translation_file', 10, 3 );
// AJAX.
$this->ajax( 'search_pages', 'search_pages' );
$this->ajax( 'is_keyword_new', 'is_keyword_new' );
$this->ajax( 'save_checklist_layout', 'save_checklist_layout' );
$this->ajax( 'deactivate_plugins', 'deactivate_plugins' );
}
/**
* Flush the rewrite rules once if the rank_math_flush_rewrite option is set.
*/
public function flush() {
if ( get_option( 'rank_math_flush_rewrite' ) ) {
flush_rewrite_rules();
delete_option( 'rank_math_flush_rewrite' );
}
if ( 'rank-math' === Param::get( 'page' ) && get_option( 'rank_math_view_modules' ) ) {
delete_option( 'rank_math_view_modules' );
}
}
/**
* Add Facebook and Twitter as user contact methods.
*
* @param array $contactmethods Current contact methods.
* @return array New contact methods with extra items.
*
* @copyright Copyright (C) 2008-2019, Yoast BV
* The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3.
*/
public function update_user_contactmethods( $contactmethods ) {
$contactmethods['twitter'] = esc_html__( 'Twitter username (without @)', 'rank-math' );
$contactmethods['facebook'] = esc_html__( 'Facebook profile URL', 'rank-math' );
$contactmethods['additional_profile_urls'] = esc_html__( 'Additional profile URLs', 'rank-math' );
return $contactmethods;
}
/**
* Display admin header.
*/
public function display_admin_header() {
$nav_tabs = new Admin_Header();
$nav_tabs->display();
}
/**
* Display admin breadcrumbs.
*/
public function display_admin_breadcrumbs() {
$nav_tabs = new Admin_Breadcrumbs();
$nav_tabs->display();
}
/**
* Display dashboard tabs.
*/
public function display_dashboard_nav() {
$nav_tabs = new Admin_Dashboard_Nav();
$nav_tabs->display();
}
/**
* Show notice when canonical URL is not a valid URL.
*
* @param int $post_id The post ID.
*/
public function canonical_check_notice( $post_id ) {
$post_type = get_post_type( $post_id );
$is_allowed = in_array( $post_type, Helper::get_allowed_post_types(), true );
if ( ! $is_allowed || Helper::is_autosave() || Helper::is_ajax() || isset( $_REQUEST['bulk_edit'] ) ) {
return $post_id;
}
if ( ! empty( $_POST['rank_math_canonical_url'] ) && false === Param::post( 'rank_math_canonical_url', false, FILTER_VALIDATE_URL ) ) {
$message = esc_html__( 'The canonical URL you entered does not seem to be a valid URL. Please double check it in the SEO meta box &raquo; Advanced tab.', 'rank-math' );
Helper::add_notification( $message, [ 'type' => 'error' ] );
}
}
/**
* Save checklist layout.
*/
public function save_checklist_layout() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
if ( empty( $_POST['layout'] ) || ! is_array( $_POST['layout'] ) ) {
return;
}
$layout = Param::post( 'layout', [], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$allowed = [
'basic' => 1,
'advanced' => 1,
'title-readability' => 1,
'content-readability' => 1,
];
$layout = array_intersect_key( $layout, $allowed );
update_user_meta( get_current_user_id(), 'rank_math_metabox_checklist_layout', $layout );
exit;
}
/**
* Ajax handler to search pages based on the searched string. Used in the Local SEO Settings.
*/
public function search_pages() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'general' );
$term = Param::get( 'term' );
if ( empty( $term ) ) {
exit;
}
global $wpdb;
$pages = $wpdb->get_results(
$wpdb->prepare(
"SELECT ID, post_title FROM {$wpdb->prefix}posts WHERE post_type = 'page' AND post_status = 'publish' AND post_title LIKE %s",
"%{$wpdb->esc_like( $term )}%"
),
ARRAY_A
);
$data = [];
foreach ( $pages as $page ) {
$data[] = [
'id' => $page['ID'],
'text' => $page['post_title'],
'url' => get_permalink( $page['ID'] ),
];
}
wp_send_json( [ 'results' => $data ] );
}
/**
* Check if the keyword has been used before for another post.
*/
public function is_keyword_new() {
global $wpdb;
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
$result = [ 'isNew' => true ];
if ( empty( $_GET['keyword'] ) ) {
$this->success( $result );
}
$keyword = Param::get( 'keyword', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK );
$object_id = Param::get( 'objectID', 0, FILTER_VALIDATE_INT );
$object_type = Param::get( 'objectType', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
$column_ids = [
'post' => 'ID',
'term' => 'term_id',
'user' => 'ID',
];
if ( ! in_array( $object_type, [ 'post', 'term', 'user' ], true ) ) {
$object_type = 'post';
}
$main = $wpdb->{$object_type . 's'};
$meta = $wpdb->{$object_type . 'meta'};
$query = sprintf( 'select %2$s.%1$s from %2$s inner join %3$s on %2$s.%1$s = %3$s.%4$s_id where ', $column_ids[ $object_type ], $main, $meta, $object_type );
if ( 'post' === $object_type ) {
$query .= sprintf( '%s.post_status = \'publish\' and ', $main );
}
$query .= sprintf( '%1$s.meta_key = \'rank_math_focus_keyword\' and ( %1$s.meta_value = %2$s OR %1$s.meta_value like %3$s ) and %1$s.%4$s_id != %5$d', $meta, '%s', '%s', $object_type, $object_id );
$data = $wpdb->get_row( $wpdb->prepare( $query, $keyword, $wpdb->esc_like( $keyword ) . ',%' ) ); // phpcs:ignore
$result['isNew'] = empty( $data );
$this->success( $result );
}
/**
* Get link suggestions for the current post.
*
* @param int|WP_Post $post Current post.
* @return array
*/
public function get_link_suggestions( $post ) {
global $pagenow;
if ( 'post-new.php' === $pagenow ) {
return;
}
$output = [];
$post = get_post( $post );
$args = [
'post_type' => $post->post_type,
'post__not_in' => [ $post->ID ],
'posts_per_page' => 5,
'meta_key' => 'rank_math_pillar_content',
'meta_value' => 'on',
'tax_query' => [ 'relation' => 'OR' ],
];
$taxonomies = Helper::get_object_taxonomies( $post, 'names' );
$taxonomies = array_filter( $taxonomies, [ $this, 'is_taxonomy_allowed' ] );
foreach ( $taxonomies as $taxonomy ) {
$this->set_term_query( $args, $post->ID, $taxonomy );
}
$posts = get_posts( $args );
foreach ( $posts as $related_post ) {
$item = [
'title' => get_the_title( $related_post->ID ),
'url' => get_permalink( $related_post->ID ),
'post_id' => $related_post->ID,
'focus_keywords' => get_post_meta( $related_post->ID, 'rank_math_focus_keyword', true ),
];
$item['focus_keywords'] = empty( $item['focus_keywords'] ) ? [] : explode( ',', $item['focus_keywords'] );
$output[] = $item;
}
return $output;
}
/**
* Is taxonomy allowed
*
* @param string $taxonomy Taxonomy to check.
*
* @return bool
*/
public function is_taxonomy_allowed( $taxonomy ) {
$exclude_taxonomies = [ 'post_format', 'product_shipping_class' ];
if ( Str::starts_with( 'pa_', $taxonomy ) || in_array( $taxonomy, $exclude_taxonomies, true ) ) {
return false;
}
return true;
}
/**
* Set term query.
*
* @param array $query Array of query.
* @param int $post_id Post ID to get terms from.
* @param string $taxonomy Taxonomy to get terms for.
*/
private function set_term_query( &$query, $post_id, $taxonomy ) {
$terms = wp_get_post_terms( $post_id, $taxonomy, [ 'fields' => 'ids' ] );
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return;
}
$query['tax_query'][] = [
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $terms,
];
}
/**
* Output link suggestions.
*
* @param array $suggestions Link items.
* @return string
*/
public function get_link_suggestions_html( $suggestions ) {
$output = '<div class="rank-math-link-suggestions-content" data-count="' . count( $suggestions ) . '">';
$is_use_fk = 'focus_keywords' === Helper::get_settings( 'titles.pt_' . get_post_type() . '_ls_use_fk' );
foreach ( $suggestions as $suggestion ) {
$label = $suggestion['title'];
if ( $is_use_fk && ! empty( $suggestion['focus_keywords'] ) ) {
$label = $suggestion['focus_keywords'][0];
}
$output .= sprintf(
'<div class="suggestion-item">
<div class="suggestion-actions">
<button class="dashicons dashicons-clipboard suggestion-copy" title="%5$s" data-clipboard-text="%2$s"></button>
<button class="dashicons dashicons-admin-links suggestion-insert" title="%6$s" data-url="%2$s" data-text="%7$s"></button>
</div>
<span class="suggestion-title" data-fk=\'%1$s\'><a target="_blank" href="%2$s" title="%3$s">%4$s</a></span>
</div>',
esc_attr( wp_json_encode( $suggestion['focus_keywords'] ) ),
$suggestion['url'],
$suggestion['title'],
$label,
esc_attr__( 'Copy Link URL to Clipboard', 'rank-math' ),
esc_attr__( 'Insert Link in Content', 'rank-math' ),
esc_attr( $label )
);
}
$output .= '</div>';
return $output;
}
/**
* Updates the is_configured value.
*
* @param int $object_id The ID of the current object.
* @param string $cmb_id The current box ID.
*/
public function update_is_configured_value( $object_id, $cmb_id ) {
if ( 0 !== strpos( $cmb_id, 'rank_math' ) && 0 !== strpos( $cmb_id, 'rank-math' ) ) {
return;
}
Helper::is_configured( true );
}
/**
* Deactivate plugin.
*/
public function deactivate_plugins() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
if ( ! current_user_can( 'activate_plugins' ) ) {
$this->error( esc_html__( 'You are not authorized to perform this action.', 'rank-math' ) );
}
$plugin = Param::post( 'plugin', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( 'all' !== $plugin ) {
deactivate_plugins( $plugin );
die( '1' );
}
Importers\Detector::deactivate_all();
die( '1' );
}
/**
* Action Scheduler: exclude our actions from the past-due checker.
* Since this is a *_pre hook, it replaces the original checker.
*
* We first do the same check as what ActionScheduler_AdminView->check_pastdue_actions() does,
* but then we also count how many of those past-due actions are ours.
*
* @param null $null Null value.
*/
public function as_exclude_pastdue_actions( $null ) {
$query_args = [
'date' => as_get_datetime_object( time() - DAY_IN_SECONDS ),
'status' => \ActionScheduler_Store::STATUS_PENDING,
'per_page' => 1,
];
$store = \ActionScheduler_Store::instance();
$num_pastdue_actions = (int) $store->query_actions( $query_args, 'count' );
if ( 0 !== $num_pastdue_actions ) {
$query_args['group'] = 'rank-math';
$num_pastdue_rm_actions = (int) $store->query_actions( $query_args, 'count' );
$num_pastdue_actions -= $num_pastdue_rm_actions;
}
$threshold_seconds = (int) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS );
$threshhold_min = (int) apply_filters( 'action_scheduler_pastdue_actions_min', 1 );
$check = ( $num_pastdue_actions >= $threshhold_min );
return (bool) apply_filters( 'action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshhold_min );
}
/**
* Check and print the Anniversary icon in the header of Rank Math's setting pages.
*/
public static function offer_icon() {
if ( ! current_user_can( 'manage_options' ) || defined( 'RANK_MATH_PRO_FILE' ) ) {
return;
}
// Holiday Season related variables.
$time = time();
$current_year = 2022;
$anniversary_start_time = gmmktime( 17, 00, 00, 10, 30, $current_year ); // 30 Oct.
$anniversary_end_time = gmmktime( 17, 00, 00, 11, 30, $current_year ); // 30 Nov.
$holiday_start_time = gmmktime( 17, 00, 00, 12, 20, $current_year ); // 20 Dec.
$holiday_end_time = gmmktime( 17, 00, 00, 01, 07, 2023 ); // 07 Jan.
if (
( $time > $anniversary_start_time && $time < $anniversary_end_time ) ||
( $time > $holiday_start_time && $time < $holiday_end_time )
) { ?>
<a href="https://rankmath.com/pricing/?utm_source=Plugin&utm_medium=Header+Offer+Icon&utm_campaign=WP" target="_blank" class="rank-math-tooltip bottom" style="margin-left:5px;">
🎉
<span><?php esc_attr_e( 'Exclusive Offer!', 'rank-math' ); ?></span>
</a>
<?php
}
}
/**
* Code to convert Addiontal Profile URLs from input type text to textarea.
*/
public function convert_additional_profile_url_to_textarea() {
if ( ! Admin_Helper::is_user_edit() ) {
return;
}
$field_description = wp_kses_post( __( 'Additional Profiles to add in the <code>sameAs</code> Schema property.', 'rank-math' ) );
?>
<script type="text/javascript">
( function( $ ) {
$( function() {
const twitterWrapper = $( '.user-twitter-wrap' );
twitterWrapper.before( '<tr><th><h2 style="margin: 0;">Rank Math SEO</h2></th><td></td></tr>' );
const additionalProfileField = $( '#additional_profile_urls' );
if ( ! additionalProfileField.length ) {
return
}
var $txtarea = $( '<textarea />' );
$txtarea.attr( 'id', additionalProfileField[0].id );
$txtarea.attr( 'name', additionalProfileField[0].name );
$txtarea.attr( 'rows', 5 );
$txtarea.val( additionalProfileField[0].value.replaceAll( " ", "\n" ) );
additionalProfileField.replaceWith( $txtarea );
$( '<p class="description"><?php echo $field_description; ?></p>' ).insertAfter( $txtarea );
} );
})(jQuery);
</script>
<?php
}
/**
* Function to replace domain with seo-by-rank-math in translation file.
*
* @param string|false $file Path to the translation file to load. False if there isn't one.
* @param string $handle Name of the script to register a translation domain to.
* @param string $domain The text domain.
*/
public function load_script_translation_file( $file, $handle, $domain ) {
if ( 'rank-math' !== $domain ) {
return $file;
}
$data = explode( '/', $file );
$data[ count( $data ) - 1 ] = preg_replace( '/rank-math/', 'seo-by-rank-math', $data[ count( $data ) - 1 ], 1 );
return implode( '/', $data );
}
}

View File

@@ -0,0 +1,278 @@
<?php
/**
* The RankMath API.
*
* @since 1.5.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
defined( 'ABSPATH' ) || exit;
/**
* Api class.
*/
class Api {
/**
* Rank Math SEO Checkup API.
*
* @var string
*/
protected $api_url = 'https://rankmath.com/wp-json/rankmath/v1/';
/**
* Was the last request successful.
*
* @var bool
*/
protected $is_success = false;
/**
* Last error.
*
* @var string
*/
protected $last_error = '';
/**
* Last response.
*
* @var array
*/
protected $last_response = [];
/**
* Last response header code.
*
* @var int
*/
protected $last_code = 0;
/**
* User agent.
*
* @var string
*/
protected $user_agent = '';
/**
* Is blocking.
*
* @var bool
*/
protected $is_blocking = true;
/**
* Main instance
*
* Ensure only one instance is loaded or can be loaded.
*
* @return Api
*/
public static function get() {
static $instance;
if ( is_null( $instance ) && ! ( $instance instanceof Api ) ) {
$instance = new Api();
$instance->is_blocking = true;
$instance->user_agent = 'RankMath/' . md5( esc_url( home_url( '/' ) ) );
}
return $instance;
}
/**
* Was the last request successful?
*
* @return bool True for success, false for failure
*/
public function is_success() {
return $this->is_success;
}
/**
* Get the last error returned by either the network transport, or by the API.
* If something didn't work, this should contain the string describing the problem.
*
* @return array|false describing the error
*/
public function get_error() {
return $this->last_error ? $this->last_error : false;
}
/**
* Get an array containing the HTTP headers and the body of the API response.
*
* @return array Assoc array with keys 'headers' and 'body'
*/
public function get_response() {
return $this->last_response;
}
/**
* Remove registration data and disconnect from RankMath.com.
*
* @param string $username Username.
* @param string $api_key Api key.
*/
public function deactivate_site( $username, $api_key ) {
$this->is_blocking = false;
$data = wp_json_encode(
[
'username' => $username,
'api_key' => $api_key,
'site_url' => esc_url( home_url() ),
]
);
$response = wp_remote_post(
RANK_MATH_SITE_URL . '/wp-json/rankmath/v1/deactivateSite',
[
'body' => $data,
'headers' => [
'Content-Type' => 'application/json',
],
],
);
}
/**
* Make an HTTP GET request - for retrieving data.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_get( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'GET', $url, $args, $timeout );
}
/**
* Make an HTTP POST request - for creating and updating items.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_post( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'POST', $url, $args, $timeout );
}
/**
* Make an HTTP PUT request - for creating new items.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_put( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'PUT', $url, $args, $timeout );
}
/**
* Make an HTTP DELETE request - for deleting data.
*
* @param string $url URL to do request.
* @param array $args Assoc array of arguments (usually your data).
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of API response, decoded from JSON.
*/
public function http_delete( $url, $args = [], $timeout = 10 ) {
return $this->make_request( 'DELETE', $url, $args, $timeout );
}
/**
* Performs the underlying HTTP request. Not very exciting.
*
* @param string $http_verb The HTTP verb to use: get, post, put, patch, delete.
* @param string $url URL to do request.
* @param array $args Assoc array of parameters to be passed.
* @param int $timeout Timeout limit for request in seconds.
*
* @return array|false Assoc array of decoded result.
*/
protected function make_request( $http_verb, $url, $args = [], $timeout = 10 ) {
$params = [
'timeout' => $timeout,
'method' => $http_verb,
'user-agent' => $this->user_agent,
'blocking' => $this->is_blocking,
];
if ( ! empty( $args ) && is_array( $args ) ) {
$params['body'] = $args;
}
$this->reset();
$response = wp_remote_request( $this->api_url . $url, $params );
$this->determine_success( $response );
return $this->format_response( $response );
}
/**
* Decode the response and format any error messages for debugging
*
* @param array $response The response from the curl request.
*
* @return array|false The JSON decoded into an array
*/
protected function format_response( $response ) {
$this->last_response = $response;
if ( is_wp_error( $response ) ) {
return false;
}
if ( ! empty( $response['body'] ) ) {
return json_decode( $response['body'], true );
}
return false;
}
/**
* Check if the response was successful or a failure. If it failed, store the error.
*
* @param array $response The response from the curl request.
*/
protected function determine_success( $response ) {
if ( is_wp_error( $response ) ) {
$this->last_error = 'WP_Error: ' . $response->get_error_message();
return;
}
$this->last_code = wp_remote_retrieve_response_code( $response );
if ( in_array( $this->last_code, [ 200, 204 ], true ) ) {
$this->is_success = true;
return;
}
$this->last_error = 'Unknown error, call getLastResponse() to find out what happened.';
}
/**
* Reset request.
*/
protected function reset() {
$this->last_code = 0;
$this->last_error = '';
$this->is_success = false;
$this->is_blocking = true;
$this->last_response = [
'body' => null,
'headers' => null,
];
}
}

View File

@@ -0,0 +1,241 @@
<?php
/**
* Ask user to review Rank Math on wp.org, in the meta box after 2 weeks.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Ask_Review class.
*/
class Ask_Review {
use Hooker, Ajax;
/**
* Now.
*
* @var string
*/
public $current_time = '';
/**
* Date of release of version 1.0.57. Turned into a timestamp in the constructor.
*
* @var string
*/
public $record_date = '2021-02-03 13:00';
/**
* Rank Math plugin install date.
*
* @var string
*/
public $install_date = '';
/**
* Constructor method.
*/
public function __construct() {
$this->current_time = current_time( 'timestamp' );
$this->record_date = strtotime( $this->record_date );
$this->install_date = get_option( 'rank_math_install_date' );
if ( false === $this->install_date ) {
$this->install_date = $this->current_time;
}
}
/**
* Register hooks.
*/
public function hooks() {
$this->ajax( 'already_reviewed', 'already_reviewed' );
// Post editor tab.
if ( $this->current_time > $this->install_date + ( 10 * DAY_IN_SECONDS ) ) {
Helper::add_json( 'showReviewTab', true );
}
// Admin notice.
$review_notice_date = $this->get_review_notice_date();
if ( $this->current_time > $review_notice_date ) {
if ( get_option( 'rank_math_review_notice_added' ) === false && ! Helper::has_notification( 'rank_math_pro_notice' ) ) {
$this->add_notice();
}
// Make dismiss button work like the "Maybe later" link.
$this->action( 'wp_helpers_notification_dismissed', 'review_notice_after_dismiss' );
}
$this->action( 'admin_footer', 'review_notice_js', 15 );
}
/**
* Add inline JS related to the review notice.
*
* @return void
*/
public function review_notice_js() {
if ( ! Helper::has_notification( 'rank_math_review_plugin_notice' ) ) {
return;
}
?>
<script>
(function( $ ) {
$( function() {
$('.rank-math-dismiss-review-notice').on( 'click', function(e) {
var $this = $(this);
if ( ! $this.hasClass( 'rank-math-review-action' ) ) {
e.preventDefault();
}
if ( $this.hasClass( 'rank-math-maybe-later-action' ) ) {
$('#rank_math_review_plugin_notice').find( '.notice-dismiss' ).trigger('click');
return false;
}
jQuery.ajax( {
url: rankMath.ajaxurl,
data: { action: 'rank_math_already_reviewed', security: rankMath.security,
},
} );
$('#rank_math_review_plugin_notice').find( '.notice-dismiss' ).trigger('click');
});
});
})(jQuery);
</script>
<style>
#rank_math_review_plugin_notice .rank-math-notice.is-dismissible a,
#rank_math_pro_notice .rank-math-notice.is-dismissible a {
color: #4f52d4;
}
#rank_math_review_plugin_notice.is-dismissible,
#rank_math_pro_notice.is-dismissible {
border-width: 0 0 0 4px;
border-left-color: #6668BD;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
padding: 5px 10px 5px 65px;
}
#rank_math_review_plugin_notice.is-dismissible:before,
#rank_math_pro_notice.is-dismissible:before {
content: '';
width: 50px;
height: 100%;
background: rgba(102, 104, 189, 0.09);
position: absolute;
left: 0;
top: 0;
}
#rank_math_review_plugin_notice.is-dismissible:after,
#rank_math_pro_notice.is-dismissible:after {
content: url('data:image/svg+xml;charset=UTF-8, <svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="20"><g fill="white"><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"></path><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"></path></g></svg>' );
padding: 3px;
border-radius: 3px;
position: absolute;
left: 12px;
top: 18px;
background: linear-gradient(-135deg, #2488e1, #724bb7);
width: 23px;
height: 23px;
display: flex;
justify-content: center;
line-height: 1;
align-items: center;
}
</style>
<?php
}
/**
* Add admin notice.
*
* @return void
*/
public function add_notice() {
$message = '<p>';
// Translators: placeholder is the plugin name.
$message .= sprintf( esc_html__( 'Hey, we noticed you\'ve been using %s for more than a week now that\'s awesome!', 'rank-math' ), '<strong>' . _x( 'Rank Math SEO', 'plugin name inside the review notice', 'rank-math' ) . '</strong>' );
$message .= '<br>';
$message .= esc_html__( 'Could you please do us a BIG favor and give it a rating on WordPress.org to help us spread the word and boost our motivation?', 'rank-math' ) . '</p>
<p><strong>Bhanu Ahluwalia</strong><br>' . esc_html__( 'Co-founder of Rank Math', 'rank-math' ) . '</p>
<p>
<a href="https://wordpress.org/support/plugin/seo-by-rank-math/reviews/?filter=5#new-post" class="rank-math-dismiss-review-notice rank-math-review-action rank-math-review-out" target="_blank" rel="noopener noreferrer"><strong>' . esc_html__( 'Yes, you deserve it', 'rank-math' ) . '</strong></a><br>
<a href="#" class="rank-math-dismiss-review-notice rank-math-maybe-later-action">' . esc_html__( 'No, maybe later', 'rank-math' ) . '</a><br>
<a href="#" class="rank-math-dismiss-review-notice rank-math-already-reviewed-action">' . esc_html__( 'I already did', 'rank-math' ) . '</a>
</p>';
Helper::add_notification(
$message,
[
'type' => 'info',
'id' => 'rank_math_review_plugin_notice',
'capability' => 'install_plugins',
]
);
update_option( 'rank_math_review_notice_added', '1', false );
}
/**
* Set "already reviewed" flag after the user dismisses the notice.
*
* @param string $notification_id Dismissed notice ID.
* @return void
*/
public function review_notice_after_dismiss( $notification_id ) {
if ( 'rank_math_review_plugin_notice' !== $notification_id ) {
return;
}
delete_option( 'rank_math_review_notice_date' );
delete_option( 'rank_math_review_notice_added' );
update_option( 'rank_math_review_notice_delayed', true, false );
}
/**
* Get stored notice start date.
*
* @return int
*/
public function get_review_notice_date() {
$review_notice_date = get_option( 'rank_math_review_notice_date' );
if ( false !== $review_notice_date ) {
return $review_notice_date;
}
$delay_days = 14;
if ( $this->install_date < $this->record_date && ! get_option( 'rank_math_review_notice_delayed' ) ) {
$delay_days = wp_rand( 7, 30 );
}
$review_notice_date = $this->current_time + ( $delay_days * DAY_IN_SECONDS );
update_option( 'rank_math_review_notice_date', $review_notice_date, false );
return $review_notice_date;
}
/**
* Set "already reviewed" flag.
*/
public function already_reviewed() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
update_option( 'rank_math_already_reviewed', current_time( 'timestamp' ) );
$this->success( 'success' );
}
}

View File

@@ -0,0 +1,281 @@
<?php
/**
* Register all the necessary CSS and JS.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Google\Console;
use RankMath\Google\Analytics;
use RankMath\Analytics\Url_Inspection;
defined( 'ABSPATH' ) || exit;
/**
* Assets class.
*
* @codeCoverageIgnore
*/
class Assets implements Runner {
use Hooker;
/**
* Prefix for the enqueue handles.
*/
const PREFIX = 'rank-math-';
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_enqueue_scripts', 'register' );
$this->action( 'admin_enqueue_scripts', 'enqueue' );
$this->action( 'admin_enqueue_scripts', 'overwrite_wplink', 99 );
if ( 'elementor' === \RankMath\Helpers\Param::get( 'action' ) ) {
$this->action( 'elementor/editor/before_enqueue_scripts', 'register' );
$this->action( 'elementor/editor/before_enqueue_scripts', 'enqueue' );
$this->action( 'elementor/editor/before_enqueue_scripts', 'overwrite_wplink', 99 );
}
}
/**
* Register styles and scripts.
*/
public function register() {
$js = rank_math()->plugin_url() . 'assets/admin/js/';
$css = rank_math()->plugin_url() . 'assets/admin/css/';
$vendor = rank_math()->plugin_url() . 'assets/vendor/';
// Styles.
wp_register_style( self::PREFIX . 'common', $css . 'common.css', null, rank_math()->version );
wp_register_style( self::PREFIX . 'cmb2', $css . 'cmb2.css', null, rank_math()->version );
wp_register_style( self::PREFIX . 'dashboard', $css . 'dashboard.css', [ 'rank-math-common', 'wp-components' ], rank_math()->version );
wp_register_style( self::PREFIX . 'dashboard-widget', $css . 'dashboard-widget.css', null, rank_math()->version );
// Scripts.
wp_register_script( self::PREFIX . 'common', $js . 'common.js', [ 'jquery', 'wp-i18n', 'lodash' ], rank_math()->version, true );
wp_register_script( self::PREFIX . 'dashboard', $js . 'dashboard.js', [ 'jquery', 'clipboard', 'lodash', 'wp-components', 'wp-element' ], rank_math()->version, true );
// Select2.
wp_register_style( 'select2-rm', $vendor . 'select2/select2.min.css', null, '4.0.6-rc.1' );
wp_register_script( 'select2-rm', $vendor . 'select2/select2.min.js', null, '4.0.6-rc.1', true );
// Inline script for core admin page Settings > Permalinks.
wp_register_script( self::PREFIX . 'core-permalink-settings', '' ); // phpcs:ignore
wp_add_inline_script( self::PREFIX . 'core-permalink-settings', $this->get_permalinks_inline_script() );
if ( ! wp_script_is( 'wp-hooks', 'registered' ) ) {
wp_register_script( 'wp-hooks', rank_math()->plugin_url() . 'assets/vendor/hooks.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-wordcount', 'registered' ) ) {
wp_register_script( 'wp-wordcount', rank_math()->plugin_url() . 'assets/vendor/wordcount.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-autop', 'registered' ) ) {
wp_register_script( 'wp-autop', rank_math()->plugin_url() . 'assets/vendor/autop.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-url', 'registered' ) ) {
wp_register_script( 'wp-url', rank_math()->plugin_url() . 'assets/vendor/url.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'wp-i18n', 'registered' ) ) {
wp_register_script( 'wp-i18n', rank_math()->plugin_url() . 'assets/vendor/i18n.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'clipboard', 'registered' ) ) {
wp_register_script( 'clipboard', rank_math()->plugin_url() . 'assets/vendor/clipboard.min.js', [], rank_math()->version, true );
}
if ( ! wp_script_is( 'lodash', 'registered' ) ) {
wp_register_script( 'lodash', rank_math()->plugin_url() . 'assets/vendor/lodash.js', [], rank_math()->version );
wp_add_inline_script( 'lodash', 'window.lodash = _.noConflict();' );
}
Helper::add_json(
'api',
[
'root' => esc_url_raw( get_rest_url() ),
'nonce' => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ),
]
);
Helper::add_json(
'keywordsApi',
[
'url' => 'https://api.rankmath.com/ltkw/v1/',
]
);
Helper::add_json(
'links',
KB::get_links()
);
Helper::add_json(
'validationl10n',
[
'regexErrorDefault' => __( 'Please use the correct format.', 'rank-math' ),
'requiredErrorDefault' => __( 'This field is required.', 'rank-math' ),
'emailErrorDefault' => __( 'Please enter a valid email address.', 'rank-math' ),
'urlErrorDefault' => __( 'Please enter a valid URL.', 'rank-math' ),
]
);
Helper::add_json( 'capitalizeTitle', Helper::get_settings( 'titles.capitalize_titles' ) );
Helper::add_json( 'isConsoleConnected', Console::is_console_connected() );
Helper::add_json( 'isAnalyticsConnected', Analytics::is_analytics_connected() );
Helper::add_json( 'isUrlInspectionEnabled', Url_Inspection::is_enabled() );
/**
* Allow other plugins to register/deregister admin styles or scripts after plugin assets.
*/
$this->do_action( 'admin/register_scripts' );
}
/**
* Enqueue styles and scripts.
*/
public function enqueue() {
$screen = get_current_screen();
if ( 'dashboard' === $screen->id ) {
wp_enqueue_style( self::PREFIX . 'dashboard-widget' );
wp_enqueue_script( self::PREFIX . 'dashboard' );
}
// Our screens only.
if ( ! in_array( $screen->taxonomy, Helper::get_allowed_taxonomies(), true ) && ! in_array( $screen->id, $this->get_admin_screen_ids(), true ) ) {
return;
}
// Add thank you.
$this->filter( 'admin_footer_text', 'admin_footer_text' );
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts after plugin assets.
*/
$this->do_action( 'admin/enqueue_scripts' );
}
/**
* Add footer credit on admin pages.
*
* @param string $text Default text for admin footer.
* @return string
*/
public function admin_footer_text( $text ) {
/* translators: plugin url */
return Helper::is_whitelabel() ? $text : sprintf( wp_kses_post( __( 'Thank you for using <a href="%s" target="_blank">Rank Math</a>', 'rank-math' ) ), KB::get( 'seo-suite', 'Admin Footer Text' ) );
}
/**
* Overwrite wplink script file.
* Rank Math adds new options in the link popup when editing a post.
*/
public function overwrite_wplink() {
wp_deregister_script( 'wplink' );
wp_register_script( 'wplink', rank_math()->plugin_url() . 'assets/admin/js/wplink.js', [ 'jquery', 'wp-a11y' ], rank_math()->version, true );
wp_localize_script(
'wplink',
'wpLinkL10n',
[
'title' => esc_html__( 'Insert/edit link', 'rank-math' ),
'update' => esc_html__( 'Update', 'rank-math' ),
'save' => esc_html__( 'Add Link', 'rank-math' ),
'noTitle' => esc_html__( '(no title)', 'rank-math' ),
'noMatchesFound' => esc_html__( 'No matches found.', 'rank-math' ),
'linkSelected' => esc_html__( 'Link selected.', 'rank-math' ),
'linkInserted' => esc_html__( 'Link inserted.', 'rank-math' ),
'relCheckbox' => __( 'Add <code>rel="nofollow"</code>', 'rank-math' ),
'sponsoredCheckbox' => __( 'Add <code>rel="sponsored"</code>', 'rank-math' ),
'linkTitle' => esc_html__( 'Link Title', 'rank-math' ),
]
);
}
/**
* Enqueues styles.
*
* @param string $style Name of the style.
*/
public function enqueue_style( $style ) {
wp_enqueue_style( self::PREFIX . $style );
}
/**
* Enqueues scripts.
*
* @param string $script Name of the script.
*/
public function enqueue_script( $script ) {
wp_enqueue_script( self::PREFIX . $script );
}
/**
* Get admin screen ids.
*
* @return array
*/
private function get_admin_screen_ids() {
$pages = [
'toplevel_page_rank-math',
'rank-math_page_rank-math-role-manager',
'rank-math_page_rank-math-seo-analysis',
'rank-math_page_rank-math-404-monitor',
'rank-math_page_rank-math-redirections',
'rank-math_page_rank-math-link-builder',
'rank-math_page_rank-math-analytics',
'rank-math_page_rank-math-import-export',
'rank-math_page_rank-math-help',
'user-edit',
'profile',
'rank_math_schema',
];
return array_merge( $pages, Helper::get_allowed_post_types() );
}
/**
* Inline script to warn the user about the risks of changing the permalinks on a live site.
*
* @return string
*/
public function get_permalinks_inline_script() {
// Don't add the script if site is set to noindex.
if ( ! get_option( 'blog_public' ) ) {
return '';
}
return "jQuery( window ).load( function() {
var noticeShown = false;
var showNotice = function() {
if ( noticeShown ) {
return true;
}
jQuery( '.rank-math-notice-permalinks-warning' ).removeClass( 'hidden' ).insertBefore( 'p.submit' );
noticeShown = true;
return true;
}
jQuery( '.available-structure-tags button' ).on( 'click', showNotice );
jQuery( 'input[type=text], input[type=radio]' ).on( 'focus change', showNotice );
} );";
}
}

View File

@@ -0,0 +1,152 @@
<?php
/**
* The admin post columns functionality.
*
* @since 1.0.212
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Helpers\Url;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Post_Columns class.
*/
class Bulk_Actions implements Runner {
use Hooker;
/**
* SEO data.
*
* @var array
*/
private $data = [];
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'current_screen', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! Helper::has_cap( 'onpage_general' ) || ! $this->can_add() ) {
return;
}
$this->register_post_columns();
$this->action( 'admin_enqueue_scripts', 'enqueue' );
}
/**
* Register post column hooks.
*/
private function register_post_columns() {
$post_types = Helper::get_allowed_post_types();
foreach ( $post_types as $post_type ) {
$this->filter( "bulk_actions-edit-{$post_type}", 'post_bulk_actions' );
}
$taxonomies = Helper::get_accessible_taxonomies();
unset( $taxonomies['post_format'] );
$taxonomies = wp_list_pluck( $taxonomies, 'label', 'name' );
foreach ( $taxonomies as $taxonomy => $label ) {
$this->filter( "bulk_actions-edit-{$taxonomy}", 'post_bulk_actions' );
}
}
/**
* Add bulk actions for applicable posts, pages, CPTs.
*
* @param array $actions Actions.
* @return array New actions.
*/
public function post_bulk_actions( $actions ) {
$new_actions = [ 'rank_math_options' => __( '&#8595; Rank Math', 'rank-math' ) ];
if ( Helper::has_cap( 'onpage_advanced' ) ) {
$new_actions['rank_math_bulk_robots_noindex'] = __( 'Set to noindex', 'rank-math' );
$new_actions['rank_math_bulk_robots_index'] = __( 'Set to index', 'rank-math' );
$new_actions['rank_math_bulk_robots_nofollow'] = __( 'Set to nofollow', 'rank-math' );
$new_actions['rank_math_bulk_robots_follow'] = __( 'Set to follow', 'rank-math' );
$new_actions['rank_math_bulk_remove_canonical'] = __( 'Remove custom canonical URL', 'rank-math' );
if ( Helper::is_module_active( 'redirections' ) && Helper::has_cap( 'redirections' ) ) {
$new_actions['rank_math_bulk_redirect'] = __( 'Redirect', 'rank-math' );
$new_actions['rank_math_bulk_stop_redirect'] = __( 'Remove redirection', 'rank-math' );
}
}
if ( Helper::is_module_active( 'rich-snippet' ) && Helper::has_cap( 'onpage_snippet' ) ) {
$new_actions['rank_math_bulk_schema_none'] = __( 'Set Schema: None', 'rank-math' );
$post_type = Param::get( 'post_type', get_post_type() );
$post_type_default = Helper::get_settings( 'titles.pt_' . $post_type . '_default_rich_snippet' );
if ( $post_type_default ) {
// Translators: placeholder is the default Schema type setting.
$new_actions['rank_math_bulk_schema_default'] = sprintf( __( 'Set Schema: Default (%s)', 'rank-math' ), $post_type_default );
}
}
if ( is_array( $actions ) && count( $new_actions ) > 1 ) {
return array_merge( $actions, $new_actions );
}
return $actions;
}
/**
* Enqueue styles and scripts.
*/
public function enqueue() {
$screen = get_current_screen();
wp_enqueue_style( 'rank-math-post-bulk-edit', rank_math()->plugin_url() . 'assets/admin/css/post-list.css', [ 'wp-components' ], rank_math()->version );
$allow_editing = Helper::get_settings( 'titles.pt_' . $screen->post_type . '_bulk_editing', true );
if ( ! $allow_editing || 'readonly' === $allow_editing ) {
return;
}
wp_enqueue_script( 'rank-math-post-bulk-edit', rank_math()->plugin_url() . 'assets/admin/js/post-list.js', [ 'lodash', 'wp-element', 'wp-components' ], rank_math()->version, true );
Helper::add_json( 'isUserRegistered', Helper::is_site_connected() );
Helper::add_json( 'contentAICredits', Helper::get_content_ai_credits() );
Helper::add_json( 'contentAIPlan', Helper::get_content_ai_plan() );
Helper::add_json( 'isProActive', defined( 'RANK_MATH_PRO_FILE' ) );
Helper::add_json( 'connectSiteUrl', Admin_Helper::get_activate_url( Url::get_current_url() ) );
}
/**
* Whether to add Bulk actions on the page.
*/
private function can_add() {
global $pagenow;
if ( 'edit-tags.php' === $pagenow ) {
return Helper::get_settings( 'titles.tax_' . Param::get( 'taxonomy' ) . '_add_meta_box' );
}
if ( Admin_Helper::is_post_list() || Admin_Helper::is_media_library() ) {
$screen = get_current_screen();
$allowed_post_types = Helper::get_allowed_post_types();
$allowed_post_types[] = 'attachment';
return in_array( $screen->post_type, $allowed_post_types, true );
}
return false;
}
}

View File

@@ -0,0 +1,290 @@
<?php
/**
* The CMB2 fields for the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* CMB2_Fields class.
*
* @codeCoverageIgnore
*/
class CMB2_Fields implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
if ( ! has_action( 'cmb2_render_switch' ) ) {
$this->action( 'cmb2_render_switch', 'render_switch', 10, 5 );
}
if ( ! has_action( 'cmb2_render_notice' ) ) {
$this->action( 'cmb2_render_notice', 'render_notice' );
}
if ( ! has_action( 'cmb2_render_address' ) ) {
$this->action( 'cmb2_render_address', 'render_address', 10, 5 );
}
if ( ! has_action( 'cmb2_render_advanced_robots' ) ) {
$this->action( 'cmb2_render_advanced_robots', 'render_advanced_robots', 10, 5 );
}
if ( ! has_action( 'cmb2_render_toggle' ) ) {
$this->action( 'cmb2_render_toggle', 'render_toggle', 10, 5 );
}
$this->filter( 'cmb2_sanitize_toggle', 'sanitize_toggle', 10, 2 );
}
/**
* Sanitize toggle field.
*
* @param string $override_value Sanitization override value to return.
* @param string $value The field value.
*/
public function sanitize_toggle( $override_value, $value ) {
return is_null( $value ) ? 'off' : $value;
}
/**
* Render toggle field.
*
* @param array $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_toggle( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
$field_name = $field->_name();
$active_value = ! empty( $field->args( 'active_value' ) ) ? $field->args( 'active_value' ) : 'on';
$escaped_value = ! empty( $field->args( 'force_enable' ) ) ? 'on' : $escaped_value;
$args = [
'type' => 'checkbox',
'id' => $field_name,
'name' => $field_name,
'desc' => '',
'value' => $active_value,
'disabled' => isset( $field->args['disabled'] ) ? $field->args['disabled'] : false,
];
if ( $escaped_value === $active_value ) {
$args['checked'] = 'checked';
}
echo '<label class="cmb2-toggle">';
echo $field_type_object->input( $args );
echo '<span class="cmb2-slider">';
echo '<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>';
echo '<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>';
echo '</span>';
echo '</label>';
$field_type_object->_desc( true, true );
}
/**
* Render switch field.
*
* @param array $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_switch( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
if ( empty( $field->args['options'] ) ) {
$field->args['options'] = [
'off' => esc_html( $field->get_string( 'off', __( 'Off', 'rank-math' ) ) ),
'on' => esc_html( $field->get_string( 'on', __( 'On', 'rank-math' ) ) ),
];
}
$field->set_options();
echo $field_type_object->radio_inline();
}
/**
* Render notices
*
* @param array $field The passed in `CMB2_Field` object.
*/
public function render_notice( $field ) {
$hash = [
'error' => 'notice notice-alt notice-error error inline rank-math-notice',
'info' => 'notice notice-alt notice-info info inline rank-math-notice',
'warning' => 'notice notice-alt notice-warning warning inline rank-math-notice',
];
echo '<div class="' . $hash[ $field->args( 'what' ) ] . '"><p>' . $field->args( 'content' ) . '</p></div>';
}
/**
* Render address field.
*
* @param array $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_address( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
// Make sure we assign each part of the value we need.
$value = wp_parse_args(
$escaped_value,
[
'streetAddress' => '',
'addressLocality' => '',
'addressRegion' => '',
'postalCode' => '',
'addressCountry' => '',
]
);
$strings = [
'streetAddress' => 'Street Address',
'addressLocality' => 'Locality',
'addressRegion' => 'Region',
'postalCode' => 'Postal Code',
'addressCountry' => 'Country',
];
foreach ( array_keys( $value ) as $id ) :
echo '<div class="cmb-address-field">' . $field_type_object->input(
[
'name' => $field_type_object->_name( '[' . $id . ']' ),
'id' => $field_type_object->_id( '_' . $id ),
'value' => $value[ $id ],
'placeholder' => esc_html( $field->get_string( $id . '_text', $strings[ $id ] ) ),
]
) . '</div>';
endforeach;
}
/**
* Render Advanced Robots fields.
*
* @param array $field The passed in `CMB2_Field` object.
* @param mixed $escaped_value The value of this field escaped
* It defaults to `sanitize_text_field`.
* If you need the unescaped value, you can access it
* via `$field->value()`.
* @param int $object_id The ID of the current object.
* @param string $object_type The type of object you are working with.
* Most commonly, `post` (this applies to all post-types),
* but could also be `comment`, `user` or `options-page`.
* @param object $field_type_object This `CMB2_Types` object.
*/
public function render_advanced_robots( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
// Make sure we assign each part of the value we need.
$values = wp_parse_args(
$escaped_value,
[
'max-snippet' => -1,
'max-video-preview' => -1,
'max-image-preview' => 'large',
]
);
$strings = [
'max-snippet' => __( 'Snippet', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Specify a maximum text-length, in characters, of a snippet for your page.', 'rank-math' ) ),
'max-video-preview' => __( 'Video Preview', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Specify a maximum duration in seconds of an animated video preview.', 'rank-math' ) ),
'max-image-preview' => __( 'Image Preview', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Specify a maximum size of image preview to be shown for images on this page.', 'rank-math' ) ),
];
echo '<ul class="cmb-advanced-robots-list no-select-all cmb2-list cmb-advanced-robots-field">';
foreach ( $values as $id => $value ) :
$value = isset( $escaped_value[ $id ] ) ? $escaped_value[ $id ] : $value;
echo '<li>';
echo '<label for="' . $field_type_object->_id( '_' . $id . '_name' ) . '">';
echo $field_type_object->checkbox(
[
'name' => $field_type_object->_name( "[{$id}][enable]" ),
'id' => $field_type_object->_id( '_' . $id . '_name' ),
'value' => true,
'checked' => ! empty( $escaped_value[ $id ] ) || empty( $escaped_value ) ? 'checked' : false,
]
);
echo $field->get_string( $id . '_text', $strings[ $id ] ) . '</label>';
if ( 'max-image-preview' === $id ) {
echo $field_type_object->select(
[
'name' => $field_type_object->_name( "[{$id}][length]" ),
'id' => $field_type_object->_id( '_' . $id . '_name' ),
'options' => $this->get_image_sizes( $value ),
]
);
}
if ( 'max-image-preview' !== $id ) {
echo $field_type_object->input(
[
'name' => $field_type_object->_name( "[{$id}][length]" ),
'id' => $field_type_object->_id( '_' . $id . '_length' ),
'value' => $value ? $value : -1,
'type' => 'number',
'min' => -1,
]
);
}
echo '</li>';
endforeach;
echo '</ul>';
}
/**
* Get Image sizes.
*
* @param string $size The selected image size.
* @return string $options The image sizes.
*/
private function get_image_sizes( $size = 'large' ) {
$values = [
'large' => __( 'Large', 'rank-math' ),
'standard' => __( 'Standard', 'rank-math' ),
'none' => __( 'None', 'rank-math' ),
];
$options = '';
foreach ( $values as $data => $label ) {
$options .= '<option value="' . $data . '" ' . selected( $size, $data, false ) . ' >' . $label . '</option>';
}
return $options;
}
}

View File

@@ -0,0 +1,224 @@
<?php
/**
* The Dashboard Widget of the plugin.
*
* @since 1.0.81
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Dashboard_Widget class.
*
* @codeCoverageIgnore
*/
class Dashboard_Widget {
use Hooker;
/**
* Constructor.
*/
public function __construct() {
$this->action( 'wp_dashboard_setup', 'add_dashboard_widgets' );
$this->action( 'rank_math/dashboard/widget', 'dashboard_widget_feed', 98 );
$this->action( 'rank_math/dashboard/widget', 'dashboard_widget_footer', 99 );
}
/**
* Register dashboard widget.
*/
public function add_dashboard_widgets() {
// Early Bail if action is not registered for the dashboard widget hook.
if (
( ! Helper::is_module_active( '404-monitor' ) || ! Helper::has_cap( '404_monitor' ) ) &&
( ! Helper::is_module_active( 'redirections' ) || ! Helper::has_cap( 'redirections' ) ) &&
( ! Helper::is_module_active( 'analytics' ) || ! Helper::has_cap( 'analytics' ) )
) {
return;
}
$icon = '<span class="rank-math-icon"><svg viewBox="0 0 462.03 462.03" xmlns="http://www.w3.org/2000/svg" width="20"><g><path d="m462 234.84-76.17 3.43 13.43 21-127 81.18-126-52.93-146.26 60.97 10.14 24.34 136.1-56.71 128.57 54 138.69-88.61 13.43 21z"></path><path d="m54.1 312.78 92.18-38.41 4.49 1.89v-54.58h-96.67zm210.9-223.57v235.05l7.26 3 89.43-57.05v-181zm-105.44 190.79 96.67 40.62v-165.19h-96.67z"></path></g></svg></span>';
wp_add_dashboard_widget(
'rank_math_dashboard_widget',
$icon . esc_html__( 'Rank Math Overview', 'rank-math' ),
[ $this, 'render_dashboard_widget' ],
null,
null,
'normal',
'high'
);
}
/**
* Render dashboard widget.
*/
public function render_dashboard_widget() {
echo '<div id="rank-math-dashboard-widget" class="rank-math-loading"></div>';
}
/**
* Add Feed data in the admin dashboard widget.
*/
public function dashboard_widget_feed() {
$posts = $this->get_feed();
?>
<h3 class="rank-math-blog-title"><?php esc_html_e( 'Latest Blog Posts from Rank Math', 'rank-math' ); ?></h3>
<?php if ( empty( $posts ) ) : ?>
<p><?php esc_html_e( 'Error: the Rank Math blog feed could not be downloaded.', 'rank-math' ); ?></p>
<?php
return;
endif;
echo '<ul class="rank-math-blog-list">';
$posts = $this->filter_posts( $posts );
$label = $this->get_item_label( $posts );
foreach ( $posts as $index => $post ) :
$link = $this->add_utm_params( $post['link'], $index );
?>
<li class="rank-math-blog-post">
<h4>
<?php if ( $label ) : ?>
<span class="rank-math-new-badge"><?php echo esc_html( $label ); ?></span>
<?php endif; ?>
<a target="_blank" href="<?php echo esc_url( $link ); ?>">
<?php echo esc_html( $post['title']['rendered'] ); ?>
</a>
</h4>
</li>
<?php
$label = '';
endforeach;
echo '</ul>';
}
/**
* Get label for first post.
*
* @param array $posts Posts.
*/
private function get_item_label( $posts ) {
$label = '';
if ( ! empty( $posts[0]['custom_label'] ) ) {
$label = $posts[0]['custom_label'];
}
$is_new = time() - strtotime( $posts[0]['date'] ) < 15 * DAY_IN_SECONDS;
if ( $is_new && empty( $label ) ) {
$label = esc_html__( 'NEW', 'rank-math' );
}
return $label;
}
/**
* Filter posts by display condition.
*
* @param array $posts Posts.
*/
private function filter_posts( $posts ) {
$posts = array_filter(
$posts,
function( $post ) {
if ( isset( $post['condition'] ) && 'is_free' === $post['condition'] && defined( 'RANK_MATH_PRO_FILE' ) ) {
return false;
}
return true;
}
);
return array_slice( $posts, 0, 3 ); // Max 3 posts.
}
/**
* Add UTM tags to links. Only add if UTM params are not already present.
*
* @param string $link Link.
* @param int $index Array index.
*/
private function add_utm_params( $link, $index ) {
// Skip if link has any UTM tags already set.
if ( preg_match( '/[?&]utm_[a-z_]+=/', $link ) ) {
return $link;
}
$utm_params = [
'utm_source' => 'Plugin',
'utm_medium' => 'Dashboard%20Widget%20Post%20' . ( $index + 1 ),
'utm_campaign' => 'WP',
];
return add_query_arg( $utm_params, $link );
}
/**
* Add footer in the admin dashboard widget.
*/
public function dashboard_widget_footer() {
?>
<div class="rank-math-widget-footer">
<a target="_blank" href="<?php KB::the( 'blog', 'Dashboard Widget Blog' ); ?>">
<?php esc_html_e( 'Blog', 'rank-math' ); ?>
<span class="screen-reader-text"><?php esc_html_e( '(opens in a new window)', 'rank-math' ); ?></span>
<span aria-hidden="true" class="dashicons dashicons-external"></span>
</a>
<a target="_blank" href="<?php KB::the( 'knowledgebase', 'Dashboard Widget Help' ); ?>">
<?php esc_html_e( 'Help', 'rank-math' ); ?>
<span class="screen-reader-text"><?php esc_html_e( '(opens in a new window)', 'rank-math' ); ?></span>
<span aria-hidden="true" class="dashicons dashicons-external"></span>
</a>
<?php if ( ! defined( 'RANK_MATH_PRO_FILE' ) ) { ?>
<a target="_blank" href="<?php KB::the( 'pro', 'Dashboard Widget PRO' ); ?>" class="rank-math-widget-go-pro">
<?php esc_html_e( 'Go Pro', 'rank-math' ); ?>
<span class="screen-reader-text"><?php esc_html_e( '(opens in a new window)', 'rank-math' ); ?></span>
<span aria-hidden="true" class="dashicons dashicons-external"></span>
</a>
<?php } ?>
</div>
<?php
}
/**
* Get posts.
*/
private function get_feed() {
$cache_key = 'rank_math_feed_posts_v2';
$cache = get_transient( $cache_key );
if ( false !== $cache ) {
return $cache;
}
$response = wp_remote_get( 'https://rankmath.com/wp-json/wp/v2/posts?dashboard_widget_feed=1' );
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
set_transient( $cache_key, [], 2 * HOUR_IN_SECONDS );
return false;
}
$posts = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $posts ) || ! is_array( $posts ) ) {
set_transient( $cache_key, [], 2 * HOUR_IN_SECONDS );
return false;
}
set_transient( $cache_key, $posts, 12 * HOUR_IN_SECONDS );
return $posts;
}
}

View File

@@ -0,0 +1,625 @@
<?php
/**
* The Import Export Class
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Param;
use RankMath\Admin\Importers\Detector;
defined( 'ABSPATH' ) || exit;
/**
* Import_Export class.
*/
class Import_Export implements Runner {
use Hooker, Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_init', 'handler' );
$this->action( 'admin_enqueue_scripts', 'enqueue', 1 );
$this->filter( 'rank_math/tools/pages', 'add_status_page', 30 );
$this->filter( 'rank_math/export/settings', 'export_other_panels', 10, 2 );
$this->action( 'rank_math/import/settings/pre_import', 'run_backup', 10, 0 );
$this->ajax( 'create_backup', 'create_backup' );
$this->ajax( 'delete_backup', 'delete_backup' );
$this->ajax( 'restore_backup', 'restore_backup' );
$this->ajax( 'clean_plugin', 'clean_plugin' );
$this->ajax( 'import_plugin', 'import_plugin' );
}
/**
* Add subpage to Status & Tools screen.
*
* @param array $pages Pages.
* @return array New pages.
*/
public function add_status_page( $pages ) {
if ( Helper::is_advanced_mode() ) {
$pages['import_export'] = [
'url' => 'status',
'args' => 'view=import_export',
'cap' => 'manage_options',
'title' => __( 'Import & Export', 'rank-math' ),
'class' => '\\RankMath\\Admin\\Import_Export',
];
}
return $pages;
}
/**
* Display Import/Export tools page.
*
* @return void
*/
public function display() {
include $this->get_view( 'main' );
}
/**
* Display panels for Import/Export tools.
*
* @return void
*/
public function show_panels() {
foreach ( (array) $this->get_panels() as $panel ) {
if ( ! isset( $panel['view'] ) || ! file_exists( $panel['view'] ) ) {
continue;
}
echo '<div class="' . ( isset( $panel['class'] ) ? esc_attr( $panel['class'] ) : '' ) . '">';
include $panel['view'];
echo '</div>';
}
}
/**
* Get list of panels.
*
* @return array
*/
public function get_panels() {
$dir = dirname( __FILE__ ) . '/views/import-export/';
$panels = [
'import-export' => [
'view' => $dir . 'import-export-panel.php',
'class' => 'import-export-settings',
],
'plugins' => [
'view' => $dir . 'plugins-panel.php',
'class' => 'import-plugins',
],
'backup' => [
'view' => $dir . 'backup-panel.php',
'class' => 'settings-backup',
],
];
return apply_filters( 'rank_math/admin/import_export_panels', $panels );
}
/**
* Get view file.
*
* @param string $view View filename.
*
* @return string Complete path to view
*/
public function get_view( $view ) {
$view = sanitize_key( $view );
return rank_math()->admin_dir() . "views/import-export/{$view}.php";
}
/**
* Enqueue files & add JSON.
*
* @return void
*/
public function enqueue() {
if ( ! $this->is_import_export_page() ) {
return;
}
\RankMath\Tools\Update_Score::get()->enqueue();
wp_enqueue_script( 'rank-math-import-export', rank_math()->plugin_url() . 'assets/admin/js/import-export.js', [], rank_math()->version, true );
wp_enqueue_style( 'cmb2-styles' );
wp_enqueue_style( 'rank-math-common' );
wp_enqueue_style( 'rank-math-cmb2' );
Helper::add_json( 'importSettingsConfirm', esc_html__( 'Are you sure you want to import settings into Rank Math? Don\'t worry, your current configuration will be saved as a backup.', 'rank-math' ) );
// Translators: %s is the plugin name.
Helper::add_json( 'importPluginConfirm', esc_html__( 'Are you sure you want to import data from %s?', 'rank-math' ) );
Helper::add_json( 'importPluginSelectAction', esc_html__( 'Select data to import.', 'rank-math' ) );
Helper::add_json( 'restoreConfirm', esc_html__( 'Are you sure you want to restore this backup? Your current configuration will be overwritten.', 'rank-math' ) );
Helper::add_json( 'deleteBackupConfirm', esc_html__( 'Are you sure you want to delete this backup?', 'rank-math' ) );
// Translators: %s is the plugin name.
Helper::add_json( 'cleanPluginConfirm', esc_html__( 'Are you sure you want erase all traces of %s?', 'rank-math' ) );
}
/**
* Check if we're on the Tools > Import & Export admin page.
*
* @return boolean
*/
private function is_import_export_page() {
return Param::get( 'page' ) === 'rank-math-status' && Param::get( 'view' ) === 'import_export';
}
/**
* Handle import or export.
*/
public function handler() {
$object_id = Param::post( 'object_id' );
if ( false === $object_id ) {
return;
}
if ( ! Helper::has_cap( 'general' ) ) {
return false;
}
if ( 'export-plz' === $object_id && check_admin_referer( 'rank-math-export-settings' ) ) {
$this->export();
}
if ( isset( $_FILES['import-me'] ) && 'import-plz' === $object_id && check_admin_referer( 'rank-math-import-settings' ) ) {
$this->import();
}
}
/**
* Handles AJAX run plugin clean.
*/
public function clean_plugin() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$result = Detector::run_by_slug( Param::post( 'pluginSlug' ), 'cleanup' );
if ( $result['status'] ) {
/* translators: Plugin name */
$this->success( sprintf( esc_html__( 'Cleanup of %s data successfully done.', 'rank-math' ), $result['importer']->get_plugin_name() ) );
}
/* translators: Plugin name */
$this->error( sprintf( esc_html__( 'Cleanup of %s data failed.', 'rank-math' ), $result['importer']->get_plugin_name() ) );
}
/**
* Handles AJAX run plugin import.
*/
public function import_plugin() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$perform = Param::post( 'perform', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( ! $this->is_action_allowed( $perform ) ) {
$this->error( esc_html__( 'Action not allowed.', 'rank-math' ) );
}
try {
$result = Detector::run_by_slug( Param::post( 'pluginSlug' ), 'import', $perform );
$this->success( $result );
} catch ( \Exception $e ) {
$this->error( $e->getMessage() );
}
}
/**
* Handles AJAX create backup.
*/
public function create_backup() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$key = $this->run_backup();
if ( is_null( $key ) ) {
$this->error( esc_html__( 'Unable to create backup this time.', 'rank-math' ) );
}
$this->success(
[
'key' => $key,
/* translators: Backup formatted date */
'backup' => sprintf( esc_html__( 'Backup: %s', 'rank-math' ), date_i18n( 'M jS Y, H:i a', $key ) ),
'message' => esc_html__( 'Backup created successfully.', 'rank-math' ),
]
);
}
/**
* Handles AJAX delete backup.
*/
public function delete_backup() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$key = Param::post( 'key', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( ! $key ) {
$this->error( esc_html__( 'No backup key found to delete.', 'rank-math' ) );
}
$this->run_backup( 'delete', $key );
$this->success( esc_html__( 'Backup successfully deleted.', 'rank-math' ) );
}
/**
* Handles AJAX restore backup.
*/
public function restore_backup() {
$this->verify_nonce( 'rank-math-ajax-nonce' );
$this->has_cap_ajax( 'general' );
$key = Param::post( 'key', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
if ( ! $key ) {
$this->error( esc_html__( 'No backup key found to restore.', 'rank-math' ) );
}
if ( ! $this->run_backup( 'restore', $key ) ) {
$this->error( esc_html__( 'Backup does not exist.', 'rank-math' ) );
}
$this->success( esc_html__( 'Backup restored successfully.', 'rank-math' ) );
}
/**
* Run backup actions.
*
* @param string $action Action to perform.
* @param array $key Key to backup.
* @return mixed
*/
public function run_backup( $action = 'add', $key = null ) {
$backups = $this->get_backups();
// Restore.
if ( 'restore' === $action ) {
if ( ! isset( $backups[ $key ] ) ) {
return false;
}
$this->do_import_data( $backups[ $key ], true );
return true;
}
// Add.
if ( 'add' === $action ) {
$key = current_time( 'U' );
$backups = [ $key => $this->get_export_data() ] + $backups;
}
// Delete.
if ( 'delete' === $action && isset( $backups[ $key ] ) ) {
unset( $backups[ $key ] );
}
update_option( 'rank_math_backups', $backups, false );
return $key;
}
/**
* Handle export.
*/
private function export() {
$panels = Param::post( 'panels', [], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$data = $this->get_export_data( $panels );
$filename = 'rank-math-settings-' . date_i18n( 'Y-m-d-H-i-s' ) . '.json';
header( 'Content-Type: application/json' );
header( 'Content-Disposition: attachment; filename=' . $filename );
header( 'Cache-Control: no-cache, no-store, must-revalidate' );
header( 'Pragma: no-cache' );
header( 'Expires: 0' );
echo wp_json_encode( $data );
exit;
}
/**
* Handle import.
*/
private function import() {
$file = $this->has_valid_file();
if ( false === $file ) {
return false;
}
// Parse Options.
$wp_filesystem = Helper::get_filesystem();
if ( is_null( $wp_filesystem ) || ! Helper::is_filesystem_direct() ) {
Helper::add_notification( esc_html__( 'Uploaded file could not be read.', 'rank-math' ), [ 'type' => 'error' ] );
return false;
}
$settings = $wp_filesystem->get_contents( $file['file'] );
$settings = json_decode( $settings, true );
\unlink( $file['file'] );
if ( is_array( $settings ) && $this->do_import_data( $settings ) ) {
Helper::add_notification( esc_html__( 'Settings successfully imported. Your old configuration has been saved as a backup.', 'rank-math' ), [ 'type' => 'success' ] );
return;
}
Helper::add_notification( esc_html__( 'No settings found to be imported.', 'rank-math' ), [ 'type' => 'info' ] );
}
/**
* Import has valid file.
*
* @return mixed
*/
private function has_valid_file() {
// Add upload hooks.
$this->filter( 'upload_mimes', 'allow_txt_upload', 10, 2 );
$this->filter( 'wp_check_filetype_and_ext', 'filetype_and_ext', 10, 4 );
// Do the upload.
$file = wp_handle_upload( $_FILES['import-me'], [ 'test_form' => false ] );
// Remove upload hooks.
$this->remove_filter( 'upload_mimes', 'allow_txt_upload', 10 );
$this->remove_filter( 'wp_check_filetype_and_ext', 'filetype_and_ext', 10 );
if ( is_wp_error( $file ) ) {
Helper::add_notification( esc_html__( 'Settings could not be imported:', 'rank-math' ) . ' ' . $file->get_error_message(), [ 'type' => 'error' ] );
return false;
}
if ( isset( $file['error'] ) ) {
Helper::add_notification( esc_html__( 'Settings could not be imported:', 'rank-math' ) . ' ' . $file['error'], [ 'type' => 'error' ] );
return false;
}
if ( ! isset( $file['file'] ) ) {
Helper::add_notification( esc_html__( 'Settings could not be imported: Upload failed.', 'rank-math' ), [ 'type' => 'error' ] );
return false;
}
return $file;
}
/**
* Filters the "real" file type of the given file.
*
* @param array $types {
* Values for the extension, mime type, and corrected filename.
*
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
* @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
* }
* @param string $file Full path to the file.
* @param string $filename The name of the file (may differ from $file due to
* $file being in a tmp directory).
* @param string[] $mimes Array of mime types keyed by their file extension regex.
*
* @return array
*/
public function filetype_and_ext( $types, $file, $filename, $mimes ) {
if ( false !== strpos( $filename, '.json' ) ) {
$types['ext'] = 'json';
$types['type'] = 'application/json';
} elseif ( false !== strpos( $filename, '.txt' ) ) {
$types['ext'] = 'txt';
$types['type'] = 'text/plain';
}
return $types;
}
/**
* Allow txt & json file upload.
*
* @param array $types Mime types keyed by the file extension regex corresponding to those types.
* @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
*
* @return array
*/
public function allow_txt_upload( $types, $user ) {
$types['json'] = 'application/json';
$types['txt'] = 'text/plain';
return $types;
}
/**
* Does import data.
*
* @param array $data Import data.
* @param bool $suppress_hooks Suppress hooks or not.
* @return bool
*/
private function do_import_data( array $data, $suppress_hooks = false ) {
$this->run_import_hooks( 'pre_import', $data, $suppress_hooks );
// Import options.
$down = $this->set_options( $data );
// Import capabilities.
if ( ! empty( $data['role-manager'] ) ) {
$down = true;
Helper::set_capabilities( $data['role-manager'] );
}
// Import redirections.
if ( ! empty( $data['redirections'] ) ) {
$down = true;
$this->set_redirections( $data['redirections'] );
}
$this->run_import_hooks( 'after_import', $data, $suppress_hooks );
return $down;
}
/**
* Set options from data.
*
* @param array $data An array of data.
*/
private function set_options( $data ) {
$set = false;
$hash = [
'modules' => 'rank_math_modules',
'general' => 'rank-math-options-general',
'titles' => 'rank-math-options-titles',
'sitemap' => 'rank-math-options-sitemap',
];
foreach ( $hash as $key => $option_key ) {
if ( ! empty( $data[ $key ] ) ) {
$set = true;
update_option( $option_key, $data[ $key ] );
}
}
return $set;
}
/**
* Set redirections.
*
* @param array $redirections An array of redirections to import.
*/
private function set_redirections( $redirections ) {
foreach ( $redirections as $key => $redirection ) {
$matched = \RankMath\Redirections\DB::match_redirections_source( $redirection['sources'] );
if ( ! empty( $matched ) ) {
continue;
}
$sources = maybe_unserialize( $redirection['sources'] );
if ( ! is_array( $sources ) ) {
continue;
}
\RankMath\Redirections\DB::add(
[
'url_to' => $redirection['url_to'],
'sources' => $sources,
'header_code' => $redirection['header_code'],
'hits' => $redirection['hits'],
'created' => $redirection['created'],
'updated' => $redirection['updated'],
]
);
}
}
/**
* Run import hooks
*
* @param string $hook Hook to fire.
* @param array $data Import data.
* @param bool $suppress Suppress hooks or not.
*/
private function run_import_hooks( $hook, $data, $suppress ) {
if ( ! $suppress ) {
/**
* Fires while importing settings.
*
* @since 0.9.0
*
* @param array $data Import data.
*/
$this->do_action( 'import/settings/' . $hook, $data );
}
}
/**
* Gets export data.
*
* @param array $panels Which panels to export. All panels will be exported if this param is empty.
* @return array
*/
private function get_export_data( array $panels = [] ) {
if ( ! $panels ) {
$panels = [ 'general', 'titles', 'sitemap', 'role-manager', 'redirections' ];
}
$settings = rank_math()->settings->all_raw();
foreach ( $panels as $panel ) {
if ( isset( $settings[ $panel ] ) ) {
$data[ $panel ] = $settings[ $panel ];
continue;
}
$data = $this->do_filter( 'export/settings', $data, $panel );
}
$data['modules'] = get_option( 'rank_math_modules', [] );
return $data;
}
/**
* Export other panels.
*
* @param array $data Gathered data.
* @param string $panel Panel id.
*
* @return array
*/
public function export_other_panels( $data, $panel ) {
if ( 'role-manager' === $panel ) {
$data['role-manager'] = Helper::get_roles_capabilities();
}
if ( 'redirections' === $panel ) {
$items = \RankMath\Redirections\DB::get_redirections( [ 'limit' => 1000 ] );
$data['redirections'] = $items['redirections'];
}
return $data;
}
/**
* Check if given action is in the list of allowed actions.
*
* @param string $perform Action to check.
*
* @return bool
*/
private function is_action_allowed( $perform ) {
$allowed = [ 'settings', 'postmeta', 'termmeta', 'usermeta', 'redirections', 'blocks', 'deactivate', 'locations', 'news', 'video', 'recalculate' ];
return $perform && in_array( $perform, $allowed, true );
}
/**
* Get backups from the database.
*/
public function get_backups() {
$backups = get_option( 'rank_math_backups', [] );
if ( empty( $backups ) ) {
$backups = [];
} elseif ( ! is_array( $backups ) ) {
$backups = (array) $backups;
}
return $backups;
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* The List Table Base CLass.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_List_Table;
use RankMath\Helpers\Param;
/**
* List_Table class.
*/
class List_Table extends WP_List_Table {
/**
* The Constructor.
*
* @param array $args Array of arguments.
*/
public function __construct( $args = [] ) {
parent::__construct( $args );
}
/**
* Message to be displayed when there are no items.
*/
public function no_items() {
echo isset( $this->_args['no_items'] ) ? $this->_args['no_items'] : esc_html__( 'No items found.', 'rank-math' );
}
/**
* Get order setting.
*
* @return string
*/
protected function get_order() {
$order = Param::request( 'order', 'desc' );
return in_array( $order, [ 'desc', 'asc' ], true ) ? strtoupper( $order ) : 'DESC';
}
/**
* Get orderby setting.
*
* @param string $default (Optional) Extract order by from request.
*
* @return string
*/
protected function get_orderby( $default = 'create_date' ) {
return Param::get( 'orderby', $default, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
}
/**
* Get search query variable.
*
* @return bool|string
*/
protected function get_search() {
return Param::request( 's', false, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK );
}
/**
* Set column headers.
*
* @codeCoverageIgnore
*/
protected function set_column_headers() {
$this->_column_headers = [
$this->get_columns(),
[],
$this->get_sortable_columns(),
];
}
}

View File

@@ -0,0 +1,264 @@
<?php
/**
* The admin notices.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Sitepress;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Notices class.
*/
class Notices implements Runner {
use Hooker, Ajax;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_init', 'notices' );
$this->action( 'wp_helpers_notification_dismissed', 'notice_dismissible' );
}
/**
* Run all notices routine.
*/
public function notices() {
$this->is_plugin_configured();
$this->new_post_type();
$this->convert_wpml_settings();
$this->permalink_changes_warning();
}
/**
* Set known post type after notice dismissal.
*
* @param string $notification_id Notification id.
*/
public function notice_dismissible( $notification_id ) {
if ( 'new_post_type' === $notification_id ) {
$current = get_post_types( [ 'public' => true ] );
update_option( 'rank_math_known_post_types', $current );
if ( Helper::is_module_active( 'sitemap' ) ) {
\RankMath\Sitemap\Cache::invalidate_storage();
}
return;
}
if ( 'convert_wpml_settings' === $notification_id ) {
update_option( 'rank_math_wpml_notice_dismissed', true );
}
if ( 'rank-math-site-url-mismatch' === $notification_id ) {
update_option( 'rank_math_siteurl_mismatch_notice_dismissed', true );
}
}
/**
* If plugin configuration not done.
*/
private function is_plugin_configured() {
if ( 'mts-install-plugins' === Param::get( 'page' ) ) {
return;
}
if ( rank_math()->notification->get_notification_by_id( 'plugin_not_setup' ) && ! Helper::is_configured() ) {
$message = sprintf(
'<b>Warning!</b> You didn\'t set up your Rank Math SEO plugin yet, which means you\'re missing out on essential settings and tweaks! <a href="%s">Complete your setup by clicking here.</a>',
Helper::get_admin_url( 'wizard' )
);
Helper::add_notification(
$message,
[
'type' => 'warning',
'id' => 'plugin_not_setup',
]
);
}
}
/**
* Add notification if a new post type is detected.
*/
private function new_post_type() {
$known = get_option( 'rank_math_known_post_types', [] );
$current = Helper::get_accessible_post_types();
$new = array_diff( $current, $known );
if ( empty( $new ) ) {
return;
}
$list = '<code>' . implode( '</code>, <code>', $new ) . '</code>';
/* Translators: placeholder is the post type name. */
$message = __( 'Rank Math has detected a new post type: %1$s. You may want to check the settings of the <a href="%2$s">Titles &amp; Meta page</a>.', 'rank-math' );
$count = count( $new );
if ( $count > 1 ) {
/* Translators: placeholder is the post type names separated with commas. */
$message = __( 'Rank Math has detected new post types: %1$s. You may want to check the settings of the <a href="%2$s">Titles &amp; Meta page</a>.', 'rank-math' );
}
$message = $this->do_filter( 'admin/notice/new_post_type', $message, $count );
$message = sprintf( wp_kses_post( $message ), $list, Helper::get_admin_url( 'options-titles#setting-panel-post-type-' . key( $new ) ), Helper::get_admin_url( 'options-sitemap#setting-panel-sitemap-post-type-' . key( $new ) ) );
Helper::add_notification(
$message,
[
'type' => 'info',
'id' => 'new_post_type',
]
);
}
/**
* Function to show Show String Translation plugin notice and convert the settings.
*/
private function convert_wpml_settings() {
if ( ! Sitepress::get()->is_active() || get_option( 'rank_math_wpml_data_converted' ) ) {
return;
}
if ( ! function_exists( 'icl_add_string_translation' ) ) {
if ( ! get_option( 'rank_math_wpml_notice_dismissed' ) ) {
Helper::add_notification(
__( 'Please activate the WPML String Translation plugin to convert Rank Math Setting values in different languages.', 'rank-math' ),
[
'type' => 'error',
'id' => 'convert_wpml_settings',
]
);
}
return;
}
$languages = icl_get_languages();
foreach ( $languages as $lang_code => $language ) {
foreach ( [ 'general', 'titles' ] as $option ) {
$data = get_option( "rank-math-options-{$option}_$lang_code" );
if ( empty( $data ) ) {
continue;
}
$common_data = array_intersect( array_keys( $data ), $this->get_translatable_options() );
if ( empty( $common_data ) ) {
continue;
}
foreach ( $common_data as $option_key ) {
$string_id = icl_get_string_id( Helper::get_settings( "$option.$option_key" ), "admin_texts_rank-math-options-$option" );
icl_add_string_translation( $string_id, $lang_code, $data[ $option_key ], 10 );
}
}
}
update_option( 'rank_math_wpml_data_converted', true );
}
/**
* Get Translatable option keys.
*
* @return array
*/
private function get_translatable_options() {
$options = [
'img_alt_format',
'img_title_format',
'breadcrumbs_separator',
'breadcrumbs_prefix',
'breadcrumbs_home_link',
'breadcrumbs_home_label',
'breadcrumbs_archive_format',
'breadcrumbs_search_format',
'breadcrumbs_404_label',
'rss_before_content',
'rss_after_content',
'title_separator',
'homepage_title',
'homepage_description',
'homepage_facebook_title',
'homepage_facebook_description',
'author_archive_title',
'author_archive_description',
'date_archive_title',
'date_archive_description',
'search_title',
'404_title',
];
$post_types = Helper::get_accessible_post_types();
foreach ( $post_types as $post_type => $data ) {
$options = array_merge(
$options,
[
"pt_{$post_type}_title",
"pt_{$post_type}_description",
"pt_{$post_type}_archive_title",
"pt_{$post_type}_archive_description",
"pt_{$post_type}_default_snippet_name",
"pt_{$post_type}_default_snippet_desc",
]
);
}
$taxonomies = Helper::get_accessible_taxonomies();
foreach ( $taxonomies as $taxonomy => $data ) {
$options = array_merge(
$options,
[
"tax_{$taxonomy}_title",
"tax_{$taxonomy}_description",
]
);
}
return $options;
}
/**
* Maybe add notice on Permalinks page about the risks of changing the permalinks on a live site.
*
* @return void
*/
public function permalink_changes_warning() {
global $pagenow;
if ( 'options-permalink.php' !== $pagenow ) {
return;
}
$this->action( 'admin_enqueue_scripts', 'add_permalink_changes_warning', 12 );
}
/**
* Add the notice for the Permalinks page.
*
* @return void
*/
public function add_permalink_changes_warning() {
wp_enqueue_script( 'rank-math-core-permalink-settings' );
$message = __( '<b>Rank Math Warning:</b> Changing the permalinks on a live, indexed site may result in serious loss of traffic if done incorrectly. Consider adding a new redirection from the old URL format to the new one.', 'rank-math' );
Helper::add_notification(
$message,
[
'type' => 'warning',
'screen' => 'options-permalink',
'classes' => 'hidden rank-math-notice-permalinks-warning is-dismissible',
]
);
}
}

View File

@@ -0,0 +1,425 @@
<?php
/**
* The option center of the plugin.
*
* @since 1.0.9
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Arr;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Option_Center class.
*/
class Option_Center implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'register_general_settings', 125 );
$this->action( 'init', 'register_title_settings', 125 );
$this->filter( 'rank_math/settings/title', 'title_post_type_settings', 1 );
$this->filter( 'rank_math/settings/title', 'title_taxonomy_settings', 1 );
$this->filter( 'rank_math/settings/general', 'remove_unwanted_general_tabs', 1 );
// Check for fields and act accordingly.
$this->action( 'cmb2_save_options-page_fields_rank-math-options-general_options', 'check_updated_fields', 25, 2 );
$this->action( 'cmb2_save_options-page_fields_rank-math-options-titles_options', 'check_updated_fields', 25, 2 );
}
/**
* General Settings.
*/
public function register_general_settings() {
$tabs = [
'links' => [
'icon' => 'rm-icon rm-icon-link',
'title' => esc_html__( 'Links', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Change how some of the links open and operate on your website. %s.', 'rank-math' ), '<a href="' . KB::get( 'link-settings', 'Options Panel Links Tab' ) . '" target="_blank">' . esc_html__( 'Learn More', 'rank-math' ) . '</a>' ),
],
'breadcrumbs' => [
'icon' => 'rm-icon rm-icon-direction',
'title' => esc_html__( 'Breadcrumbs', 'rank-math' ),
'classes' => 'rank-math-advanced-option',
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Here you can set up the breadcrumbs function. %s', 'rank-math' ), '<a href="' . KB::get( 'breadcrumbs', 'Options Panel Breadcrumbs Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>. <br/>' ),
'after_row' => current_theme_supports( 'rank-math-breadcrumbs' ) ? '' : '<div class="notice notice-alt notice-warning warning inline rank-math-notice"><p>' . esc_html__( 'Use the following code in your theme template files to display breadcrumbs.', 'rank-math' ) . ' <a href="' . KB::get( 'breadcrumbs-install', 'Options Panel Breadcrumbs Tab' ) . '" target="_blank">' . esc_html__( 'Learn More', 'rank-math' ) . '</a><br /><code>&lt;?php if (function_exists(\'rank_math_the_breadcrumbs\')) rank_math_the_breadcrumbs(); ?&gt;</code> OR <code>[rank_math_breadcrumb]</code></p></div>',
],
'webmaster' => [
'icon' => 'rm-icon rm-icon-toolbox',
'title' => esc_html__( 'Webmaster Tools', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Enter verification codes for third-party webmaster tools. %s', 'rank-math' ), '<a href="' . KB::get( 'webmaster-tools', 'Options Panel Webmaster Tools Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.<br />' ),
],
'others' => [
'icon' => 'rm-icon rm-icon-misc',
'title' => esc_html__( 'Others', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Change some uncommon but essential settings here. %s.', 'rank-math' ), '<a href="' . KB::get( 'other-settings', 'Options Panel Others Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'classes' => 'rank-math-advanced-option',
],
];
if ( is_super_admin() && 'rank-math-options-general' === Param::get( 'page' ) ) {
Arr::insert(
$tabs,
[
'htaccess' => [
'icon' => 'rm-icon rm-icon-htaccess',
'title' => esc_html__( 'Edit .htaccess', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Edit the contents of your .htaccess file easily. %s.', 'rank-math' ), '<a href="' . KB::get( 'edit-htaccess', 'Options Panel htaccess Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'classes' => 'rank-math-advanced-option',
],
],
5
);
}
/**
* Allow developers to add new sections in the General Settings.
*
* @param array $tabs
*/
$tabs = $this->do_filter( 'settings/general', $tabs );
new Options(
[
'key' => 'rank-math-options-general',
'title' => esc_html__( 'SEO Settings', 'rank-math' ),
'menu_title' => esc_html__( 'General Settings', 'rank-math' ),
'capability' => 'rank_math_general',
'folder' => 'general',
'tabs' => $tabs,
]
);
}
/**
* Remove unneeded tabs from the General Settings.
*
* @param array $tabs Hold tabs for optional panel.
* @return array
*/
public function remove_unwanted_general_tabs( $tabs ) {
if ( is_multisite() ) {
unset( $tabs['robots'] );
}
if ( ! Helper::has_cap( 'edit_htaccess' ) && is_multisite() ) {
unset( $tabs['htaccess'] );
}
return $tabs;
}
/**
* Register SEO Titles & Meta Settings.
*/
public function register_title_settings() {
$tabs = [
'global' => [
'icon' => 'rm-icon rm-icon-settings',
'title' => esc_html__( 'Global Meta', 'rank-math' ),
/* translators: Link to KB article */
'desc' => sprintf( esc_html__( 'Change Global meta settings that take effect across your website. %s.', 'rank-math' ), '<a href="' . KB::get( 'titles-meta', 'Options Panel Meta Global Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
],
'local' => [
'icon' => 'rm-icon rm-icon-local-seo',
'title' => esc_html__( 'Local SEO', 'rank-math' ),
/* translators: Redirection page url */
'desc' => sprintf( wp_kses_post( __( 'Optimize for local searches and Knowledge Graph using these settings. %s.', 'rank-math' ) ), '<a href="' . KB::get( 'local-seo-settings', 'Options Panel Meta Local Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'after_row' => '<div class="notice notice-alt notice-info info inline rank-math-notice"><p>' . __( 'Use the <code>[rank_math_contact_info]</code> shortcode to display contact information in a nicely formatted way. You should also claim your business on Google if you have not already.', 'rank-math' ) . '</p></div>',
],
'social' => [
'icon' => 'rm-icon rm-icon-social',
'title' => esc_html__( 'Social Meta', 'rank-math' ),
/* translators: Link to social setting KB article */
'desc' => sprintf( esc_html__( "Add social account information to your website's Schema and Open Graph. %s.", 'rank-math' ), '<a href="' . KB::get( 'social-meta-settings', 'Options Panel Meta Social Tab' ) . '" target="_blank">' . esc_html__( 'Learn More', 'rank-math' ) . '</a>' ),
],
'homepage' => [
'icon' => 'rm-icon rm-icon-home',
'title' => esc_html__( 'Homepage', 'rank-math' ),
'desc' => sprintf(
/* translators: Link to KB article */
esc_html__( 'Add SEO meta and OpenGraph details to your homepage. %s.', 'rank-math' ),
'<a href="' . KB::get( 'homepage-settings', 'Options Panel Meta Home Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>'
),
],
'author' => [
'icon' => 'rm-icon rm-icon-users',
'title' => esc_html__( 'Authors', 'rank-math' ),
/* translators: Link to KB article */
'desc' => sprintf( esc_html__( 'Change SEO options related to the author archives. %s.', 'rank-math' ), '<a href="' . KB::get( 'author-settings', 'Options Panel Meta Author Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
],
'misc' => [
'icon' => 'rm-icon rm-icon-misc',
'title' => esc_html__( 'Misc Pages', 'rank-math' ),
/* translators: Link to KB article */
'desc' => sprintf( esc_html__( 'Customize SEO meta settings of pages like search results, 404s, etc. %s.', 'rank-math' ), '<a href="' . KB::get( 'misc-settings', 'Options Panel Meta Misc Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
],
];
/**
* Allow developers to add new section in the Title Settings.
*
* @param array $tabs
*/
$tabs = $this->do_filter( 'settings/title', $tabs );
new Options(
[
'key' => 'rank-math-options-titles',
'title' => esc_html__( 'SEO Titles &amp; Meta', 'rank-math' ),
'menu_title' => esc_html__( 'Titles &amp; Meta', 'rank-math' ),
'capability' => 'rank_math_titles',
'folder' => 'titles',
'tabs' => $tabs,
]
);
if ( is_admin() ) {
Helper::add_json( 'postTitle', 'Post Title' );
Helper::add_json( 'postUri', home_url( '/post-title' ) );
Helper::add_json( 'blogName', get_bloginfo( 'name' ) );
}
}
/**
* Add post type tabs in the Title Settings panel.
*
* @param array $tabs Holds the tabs of the options panel.
* @return array
*/
public function title_post_type_settings( $tabs ) {
$icons = Helper::choices_post_type_icons();
$links = [
'post' => '<a href="' . KB::get( 'post-settings', 'Options Panel Meta Posts Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'page' => '<a href="' . KB::get( 'page-settings', 'Options Panel Meta Pages Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'product' => '<a href="' . KB::get( 'product-settings', 'Options Panel Meta Products Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'attachment' => '<a href="' . KB::get( 'media-settings', 'Options Panel Meta Attachments Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
];
$names = [
'post' => 'single %s',
'page' => 'single %s',
'product' => 'product pages',
'attachment' => 'media %s',
];
$tabs['p_types'] = [
'title' => esc_html__( 'Post Types:', 'rank-math' ),
'type' => 'seprator',
];
foreach ( Helper::get_accessible_post_types() as $post_type ) {
$obj = get_post_type_object( $post_type );
$link = isset( $links[ $obj->name ] ) ? $links[ $obj->name ] : '';
$obj_name = isset( $names[ $obj->name ] ) ? sprintf( $names[ $obj->name ], $obj->name ) : $obj->name;
$tabs[ 'post-type-' . $obj->name ] = [
'title' => 'attachment' === $post_type ? esc_html__( 'Attachments', 'rank-math' ) : $obj->label,
'icon' => isset( $icons[ $obj->name ] ) ? $icons[ $obj->name ] : $icons['default'],
/* translators: 1. post type name 2. link */
'desc' => sprintf( esc_html__( 'Change Global SEO, Schema, and other settings for %1$s. %2$s', 'rank-math' ), $obj_name, $link ),
'post_type' => $obj->name,
'file' => rank_math()->includes_dir() . 'settings/titles/post-types.php',
'classes' => 'attachment' === $post_type ? 'rank-math-advanced-option' : '',
];
}
return $tabs;
}
/**
* Add taxonomy tabs in the Title Settings panel.
*
* @param array $tabs Holds the tabs of the options panel.
* @return array
*/
public function title_taxonomy_settings( $tabs ) {
$icons = Helper::choices_taxonomy_icons();
$hash_name = [
'category' => 'category archive pages',
'product_cat' => 'Product category pages',
'product_tag' => 'Product tag pages',
];
$hash_link = [
'category' => '<a href="' . KB::get( 'category-settings', 'Options Panel Meta Categories Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'post_tag' => '<a href="' . KB::get( 'tag-settings', 'Options Panel Meta Tags Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'product_cat' => '<a href="' . KB::get( 'product-categories-settings', 'Options Panel Meta Product Categories Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
'product_tag' => '<a href="' . KB::get( 'product-tags-settings', 'Options Panel Meta Product Tags Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>.',
];
$taxonomies_data = [];
foreach ( Helper::get_accessible_taxonomies() as $taxonomy ) {
$attached = implode( ' + ', $taxonomy->object_type );
$taxonomies_data[ $attached ][ $taxonomy->name ] = $taxonomy;
}
foreach ( $taxonomies_data as $attached => $taxonomies ) {
// Seprator.
$tabs[ $attached ] = [
'title' => ucwords( $attached ) . ':',
'type' => 'seprator',
];
foreach ( $taxonomies as $taxonomy ) {
$link = isset( $hash_link[ $taxonomy->name ] ) ? $hash_link[ $taxonomy->name ] : '';
$taxonomy_name = isset( $hash_name[ $taxonomy->name ] ) ? $hash_name[ $taxonomy->name ] : $taxonomy->label;
$tabs[ 'taxonomy-' . $taxonomy->name ] = [
'icon' => isset( $icons[ $taxonomy->name ] ) ? $icons[ $taxonomy->name ] : $icons['default'],
'title' => $taxonomy->label,
/* translators: 1. taxonomy name 2. link */
'desc' => sprintf( esc_html__( 'Change Global SEO, Schema, and other settings for %1$s. %2$s', 'rank-math' ), $taxonomy_name, $link ),
'taxonomy' => $taxonomy->name,
'file' => rank_math()->includes_dir() . 'settings/titles/taxonomies.php',
];
}
}
if ( isset( $tabs['taxonomy-post_format'] ) ) {
$tab = $tabs['taxonomy-post_format'];
unset( $tabs['taxonomy-post_format'] );
$tab['title'] = esc_html__( 'Post Formats', 'rank-math' );
$tab['page_title'] = esc_html__( 'Post Formats Archive', 'rank-math' );
Arr::insert( $tabs, [ 'taxonomy-post_format' => $tab ], 5 );
}
return $tabs;
}
/**
* Check if certain fields got updated.
*
* @param int $object_id The ID of the current object.
* @param array $updated Array of field ids that were updated.
* Will only include field ids that had values change.
*/
public function check_updated_fields( $object_id, $updated ) {
/**
* Filter: Allow developers to add option fields which will flush the rewrite rules when updated.
*
* @param array $flush_fields Array of field IDs for which we need to flush.
*/
$flush_fields = $this->do_filter(
'flush_fields',
[
'strip_category_base',
'disable_author_archives',
'url_author_base',
'attachment_redirect_urls',
'attachment_redirect_default',
'nofollow_external_links',
'nofollow_image_links',
'nofollow_domains',
'nofollow_exclude_domains',
'new_window_external_links',
'redirections_header_code',
'redirections_post_redirect',
'redirections_debug',
]
);
foreach ( $flush_fields as $field_id ) {
if ( in_array( $field_id, $updated, true ) ) {
Helper::schedule_flush_rewrite();
break;
}
}
$this->update_htaccess();
}
/**
* Update .htaccess.
*/
private function update_htaccess() {
if ( empty( Param::post( 'htaccess_accept_changes' ) ) ) {
return;
}
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Writing to .htaccess file and escaping for HTML will break functionality.
$content = wp_unslash( $_POST['htaccess_content'] );
if ( empty( $content ) ) {
return;
}
if ( ! $this->do_htaccess_backup() ) {
Helper::add_notification(
esc_html__( 'Failed to backup .htaccess file. Please check file permissions.', 'rank-math' ),
[ 'type' => 'error' ]
);
return;
}
if ( ! $this->do_htaccess_update( $content ) ) {
Helper::add_notification(
esc_html__( 'Failed to update .htaccess file. Please check file permissions.', 'rank-math' ),
[ 'type' => 'error' ]
);
return;
}
Helper::add_notification( esc_html__( '.htaccess file updated successfully.', 'rank-math' ) );
}
/**
* Create htaccess backup.
*
* @return bool
*/
private function do_htaccess_backup() {
if ( ! Helper::is_filesystem_direct() ) {
return false;
}
$wp_filesystem = Helper::get_filesystem();
$path = get_home_path();
$file = $path . '.htaccess';
if ( ! $wp_filesystem->is_writable( $path ) || ! $wp_filesystem->exists( $file ) ) {
return false;
}
$backup = $path . uniqid( '.htaccess_back_' );
return $wp_filesystem->copy( $file, $backup, true );
}
/**
* Update htaccess file.
*
* @param string $content Htaccess content.
* @return string|bool
*/
private function do_htaccess_update( $content ) {
if ( empty( $content ) || ! Helper::is_filesystem_direct() ) {
return false;
}
$wp_filesystem = Helper::get_filesystem();
$htaccess_file = get_home_path() . '.htaccess';
return ! $wp_filesystem->is_writable( $htaccess_file ) ? false : $wp_filesystem->put_contents( $htaccess_file, $content );
}
}

View File

@@ -0,0 +1,361 @@
<?php
/**
* The option page functionality of the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_Http;
use RankMath\KB;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Str;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Options class.
*/
class Options {
use Hooker;
/**
* Page title.
*
* @var string
*/
public $title = 'Settings';
/**
* Menu title.
*
* @var string
*/
public $menu_title = 'Settings';
/**
* Hold tabs for page.
*
* @var array
*/
public $tabs = [];
/**
* Hold folder name for tab files.
*
* @var string
*/
public $folder = '';
/**
* Menu Position.
*
* @var int
*/
public $position = 10;
/**
* The capability required for this menu to be displayed to the user.
*
* @var string
*/
public $capability = 'manage_options';
/**
* CMB2 option page id.
*
* @var string
*/
private $cmb_id = null;
/**
* Options key.
*
* @var string
*/
public $key = '';
/**
* The Constructor
*
* @param array $config Array of configuration.
*/
public function __construct( $config ) {
$this->config( $config );
$this->cmb_id = $this->key . '_options';
$this->action( 'cmb2_admin_init', 'register_option_page', $this->position );
$this->action( 'admin_post_' . $this->key, 'reset_options', 2 );
if ( true === empty( get_option( $this->key ) ) ) {
$this->action( 'cmb2_init_hookup_' . $this->cmb_id, 'set_defaults', 11 );
}
if ( ! $this->is_current_page() ) {
return;
}
$this->action( 'admin_enqueue_scripts', 'enqueue' );
$this->action( 'admin_body_class', 'body_class' );
}
/**
* Create cmb2 box.
*
* @return CMB2
*/
private function create_cmb2() {
return new_cmb2_box(
[
'id' => $this->cmb_id,
'title' => $this->title,
'menu_title' => $this->menu_title,
'capability' => $this->capability,
'object_types' => [ 'options-page' ],
'option_key' => $this->key,
'parent_slug' => 'rank-math',
'cmb_styles' => false,
'display_cb' => [ $this, 'display' ],
]
);
}
/**
* Create option object and add settings.
*/
public function register_option_page() {
$cmb = $this->create_cmb2();
$tabs = $this->get_tabs();
$cmb->add_field(
[
'id' => 'setting-panel-container-' . $this->cmb_id,
'type' => 'tab_container_open',
'classes' => 'before-header',
'tabs' => $tabs,
]
);
foreach ( $tabs as $id => $tab ) {
$located = $this->locate_file( $id, $tab );
if ( false === $located ) {
continue;
}
$cmb->add_field(
[
'name' => esc_html__( 'Panel', 'rank-math' ),
'id' => 'setting-panel-' . $id,
'type' => 'tab',
'open' => true,
'classes' => isset( $tab['classes'] ) ? $tab['classes'] : '',
]
);
$cmb->add_field(
[
'id' => $id . '_section_title',
'type' => 'title',
'name' => isset( $tab['page_title'] ) ? $tab['page_title'] : ( isset( $tab['title'] ) ? $tab['title'] : '' ),
'desc' => isset( $tab['desc'] ) ? $tab['desc'] : '',
'after' => isset( $tab['after'] ) ? $tab['after'] : '',
'classes' => 'tab-header',
'after_row' => isset( $tab['after_row'] ) ? $tab['after_row'] : '',
]
);
include $located;
$this->do_action( "admin/settings/{$id}", $cmb, $tab );
$cmb->add_field(
[
'id' => 'setting-panel-' . $id . '-close',
'type' => 'tab',
]
);
}
$cmb->add_field(
[
'id' => 'setting-panel-container-close-' . $this->cmb_id,
'type' => 'tab_container_close',
]
);
CMB2::pre_init( $cmb );
}
/**
* Set the default values if not set.
*
* @param CMB2 $cmb The CMB2 object to hookup.
*/
public function set_defaults( $cmb ) {
foreach ( $cmb->prop( 'fields' ) as $id => $field_args ) {
$field = $cmb->get_field( $id );
if ( isset( $field_args['default'] ) || isset( $field_args['default_cb'] ) ) {
$defaults[ $id ] = $field->get_default();
}
}
// Save Defaults if any.
if ( ! empty( $defaults ) ) {
add_option( $this->key, $defaults );
}
}
/**
* Reset options.
*/
public function reset_options() {
if ( ! check_admin_referer( 'rank-math-reset-options' ) || ! current_user_can( 'manage_options' ) ) {
return false;
}
$url = wp_get_referer();
if ( ! $url ) {
$url = admin_url();
}
if ( filter_has_var( INPUT_POST, 'reset-cmb' ) && Param::post( 'action' ) === $this->key ) {
delete_option( $this->key );
Helper::redirect( esc_url_raw( $url ), WP_Http::SEE_OTHER );
exit;
}
}
/**
* Enqueue styles and scripts.
*/
public function enqueue() {
$screen = get_current_screen();
if ( ! Str::contains( $this->key, $screen->id ) ) {
return;
}
\CMB2_Hookup::enqueue_cmb_css();
rank_math()->variables->setup_json();
wp_enqueue_style( 'rank-math-options', rank_math()->plugin_url() . 'assets/admin/css/option-panel.css', [ 'select2-rm', 'rank-math-common', 'rank-math-cmb2' ], rank_math()->version );
wp_enqueue_script( 'rank-math-options', rank_math()->plugin_url() . 'assets/admin/js/option-panel.js', [ 'underscore', 'select2-rm', 'lodash', 'rank-math-common', 'wp-api-fetch' ], rank_math()->version, true );
// Add thank you.
Helper::add_json( 'indexUrl', rank_math()->plugin_url() . 'assets/admin/js/search-index/' );
Helper::add_json( 'optionPage', str_replace( 'rank-math-options-', '', $this->key ) );
}
/**
* Add classes to <body> of WordPress admin.
*
* @param string $classes List of CSS classes.
* @return string
*/
public function body_class( $classes = '' ) {
$mode = Helper::is_advanced_mode() ? 'advanced' : 'basic';
return $classes . ' rank-math-page rank-math-mode-' . $mode;
}
/**
* Display Setting on a page.
*
* @param CMB2_Options $machine Current CMB2 box object.
*/
public function display( $machine ) {
$cmb = $machine->cmb;
// Header.
rank_math()->admin->display_admin_header();
?>
<?php if ( ! defined( 'RANK_MATH_PRO_FILE' ) ) : ?>
<div class="rank-math-unlock-pro-notice" id="rank-math-unlock-pro-notice">
<a href="<?php KB::the( 'pro', 'Unlock PRO Options Panel Notice' ); ?>" target="_blank" class="pro-link">
<p>
<?php esc_html_e( 'Take your SEO to the Next Level!', 'rank-math' ); ?>
<strong><?php esc_html_e( 'Get Rank Math PRO!', 'rank-math' ); ?></strong>
<span><?php esc_html_e( 'Click here to see all the exciting features.', 'rank-math' ); ?></span>
</p>
<div class="close-notice">
<span class="dashicons dashicons-dismiss"></span>
</div>
</a>
</div>
<?php endif; ?>
<div class="wrap rank-math-wrap rank-math-wrap-settings">
<span class="wp-header-end"></span>
<form class="cmb-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="POST" id="<?php echo esc_attr( $cmb->cmb_id ); ?>" enctype="multipart/form-data" encoding="multipart/form-data">
<input type="hidden" name="action" value="<?php echo esc_attr( $machine->option_key ); ?>">
<?php $machine->options_page_metabox(); ?>
<footer class="form-footer rank-math-ui settings-footer wp-clearfix">
<?php wp_nonce_field( 'rank-math-reset-options' ); ?>
<input type="submit" name="submit-cmb" id="submit-cmb" title="<?php echo esc_html__( 'Ctrl/Cmd + Enter', 'rank-math' ); ?>" class="button button-primary save-options" value="<?php esc_attr_e( 'Save Changes', 'rank-math' ); ?>">
<input type="submit" name="reset-cmb" id="rank-math-reset-cmb" value="<?php esc_attr_e( 'Reset Options', 'rank-math' ); ?>" class="button button-secondary reset-options alignleft">
</footer>
</form>
</div>
<?php
}
/**
* Check if we are on the correct page.
*
* @return bool
*/
public function is_current_page() {
return Param::request( 'page' ) === $this->key || Param::request( 'action' ) === $this->key;
}
/**
* Get setting tabs.
*
* @return array
*/
private function get_tabs() {
$filter = str_replace( '-', '_', str_replace( 'rank-math-', '', $this->key ) );
/**
* Allow developers to add new tabs into option panel.
*
* The dynamic part of hook is, page name without 'rank-math-' prefix.
*
* @param array $tabs
*/
return $this->do_filter( "admin/options/{$filter}_tabs", $this->tabs );
}
/**
* Locate tab options file.
*
* @param string $id Tab id.
* @param array $tab Tab options.
* @return string|boolean
*/
private function locate_file( $id, $tab ) {
if ( isset( $tab['type'] ) && 'seprator' === $tab['type'] ) {
return false;
}
$file = isset( $tab['file'] ) && ! empty( $tab['file'] ) ? $tab['file'] : rank_math()->includes_dir() . "settings/{$this->folder}/{$id}.php";
return file_exists( $file ) ? $file : false;
}
}

View File

@@ -0,0 +1,326 @@
<?php
/**
* The admin-page functionality.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helpers\Param;
/**
* Page class.
*/
class Page {
/**
* Unique ID used for menu_slug.
*
* @var string
*/
public $id = null;
/**
* The text to be displayed in the title tags of the page.
*
* @var string
*/
public $title = null;
/**
* The slug name for the parent menu.
*
* @var string
*/
public $parent = null;
/**
* The The on-screen name text for the menu.
*
* @var string
*/
public $menu_title = null;
/**
* The capability required for this menu to be displayed to the user.
*
* @var string
*/
public $capability = 'manage_options';
/**
* The icon for this menu.
*
* @var string
*/
public $icon = 'dashicons-art';
/**
* The position in the menu order this menu should appear.
*
* @var int
*/
public $position = -1;
/**
* The function/file that displays the page content for the menu page.
*
* @var string|callable
*/
public $render = null;
/**
* The function that run on page POST to save data.
*
* @var callable
*/
public $onsave = null;
/**
* Hold contextual help tabs.
*
* @var array
*/
public $help = null;
/**
* Hold scripts and styles.
*
* @var array
*/
public $assets = null;
/**
* Check if plugin is network active.
*
* @var array
*/
public $is_network = false;
/**
* Hold classes for body tag.
*
* @var array
*/
public $classes = null;
/**
* The Constructor.
*
* @param string $id Admin page unique id.
* @param string $title Title of the admin page.
* @param array $config Optional. Override page settings.
*/
public function __construct( $id, $title, $config = [] ) {
// Early bail!
if ( ! $id ) {
wp_die( esc_html__( '$id variable required', 'rank-math' ), esc_html__( 'Variable Required', 'rank-math' ) );
}
if ( ! $title ) {
wp_die( esc_html__( '$title variable required', 'rank-math' ), esc_html__( 'Variable Required', 'rank-math' ) );
}
$this->id = $id;
$this->title = $title;
foreach ( $config as $key => $value ) {
$this->$key = $value;
}
if ( ! $this->menu_title ) {
$this->menu_title = $title;
}
add_action( 'init', [ $this, 'init' ], 25 );
}
/**
* Init admin page when WordPress Initialises.
*
* @codeCoverageIgnore
*/
public function init() {
$priority = $this->parent ? intval( $this->position ) : -1;
add_action( $this->is_network ? 'network_admin_menu' : 'admin_menu', [ $this, 'register_menu' ], $priority );
// If not the page is not this page stop here.
if ( ! $this->is_current_page() ) {
return;
}
$hooks = [
'admin_init' => [
'callback' => 'save',
'condition' => ! is_null( $this->onsave ) && is_callable( $this->onsave ),
],
'admin_enqueue_scripts' => [
'callback' => 'enqueue',
'condition' => ! empty( $this->assets ),
],
'admin_head' => [
'callback' => 'contextual_help',
'condition' => ! empty( $this->help ),
],
'admin_body_class' => [
'callback' => 'body_class',
'condition' => ! empty( $this->classes ),
],
];
foreach ( $hooks as $hook => $data ) {
if ( true === $data['condition'] ) {
add_action( $hook, [ $this, $data['callback'] ] );
}
}
}
/**
* Register Admin Menu.
*
* @codeCoverageIgnore
*/
public function register_menu() {
if ( ! $this->parent ) {
add_menu_page( $this->title, $this->menu_title, $this->capability, $this->id, [ $this, 'display' ], $this->icon, $this->position );
return;
}
add_submenu_page( $this->parent, $this->title, $this->menu_title, $this->capability, $this->id, [ $this, 'display' ] );
}
/**
* Enqueue styles and scripts.
*
* @codeCoverageIgnore
*/
public function enqueue() {
$this->enqueue_styles();
$this->enqueue_scripts();
}
/**
* Add classes to <body> of WordPress admin.
*
* @codeCoverageIgnore
*
* @param string $classes Space-separated list of CSS classes.
*
* @return string
*/
public function body_class( $classes = '' ) {
return $classes . ' ' . join( ' ', $this->classes );
}
/**
* Save anything you want using onsave function.
*
* @codeCoverageIgnore
*/
public function save() {
call_user_func( $this->onsave, $this );
}
/**
* Contextual Help.
*
* @codeCoverageIgnore
*/
public function contextual_help() {
$screen = get_current_screen();
foreach ( $this->help as $tab_id => $tab ) {
$tab['id'] = $tab_id;
$tab['content'] = $this->get_help_content( $tab );
$screen->add_help_tab( $tab );
}
}
/**
* Render admin page content using render function you passed in config.
*
* @codeCoverageIgnore
*/
public function display() {
if ( is_null( $this->render ) ) {
return;
}
if ( is_callable( $this->render ) ) {
call_user_func( $this->render, $this );
return;
}
if ( is_string( $this->render ) ) {
include_once $this->render;
}
}
/**
* Is the page is currrent page.
*
* @return bool
*/
public function is_current_page() {
return Param::get( 'page' ) === $this->id;
}
/**
* Enqueue styles
*
* @codeCoverageIgnore
*/
private function enqueue_styles() {
if ( ! isset( $this->assets['styles'] ) || empty( $this->assets['styles'] ) ) {
return;
}
foreach ( $this->assets['styles'] as $handle => $src ) {
wp_enqueue_style( $handle, $src, null, rank_math()->version );
}
}
/**
* Enqueue scripts.
*
* @codeCoverageIgnore
*/
private function enqueue_scripts() {
if ( ! isset( $this->assets['scripts'] ) || empty( $this->assets['scripts'] ) ) {
return;
}
foreach ( $this->assets['scripts'] as $handle => $src ) {
wp_enqueue_script( $handle, $src, null, rank_math()->version, true );
}
}
/**
* Get tab content
*
* @codeCoverageIgnore
*
* @param array $tab Tab to get content for.
*
* @return string
*/
private function get_help_content( $tab ) {
ob_start();
// If it is a function.
if ( isset( $tab['content'] ) && is_callable( $tab['content'] ) ) {
call_user_func( $tab['content'] );
}
// If it is a file.
if ( isset( $tab['view'] ) && $tab['view'] ) {
require $tab['view'];
}
return ob_get_clean();
}
}

View File

@@ -0,0 +1,381 @@
<?php
/**
* The admin post columns functionality.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Helper;
use RankMath\Helpers\Str;
use RankMath\Helpers\Param;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Admin\Database\Database;
defined( 'ABSPATH' ) || exit;
/**
* Post_Columns class.
*/
class Post_Columns implements Runner {
use Hooker;
/**
* SEO data.
*
* @var array
*/
private $data = [];
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_init', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! Helper::has_cap( 'onpage_general' ) ) {
return;
}
$this->register_post_columns();
$this->register_media_columns();
// Column Content.
$this->filter( 'rank_math_title', 'get_column_title', 5 );
$this->filter( 'rank_math_description', 'get_column_description', 5 );
$this->filter( 'rank_math_seo_details', 'get_column_seo_details', 5 );
}
/**
* Register post column hooks.
*/
private function register_post_columns() {
$post_types = Helper::get_allowed_post_types();
foreach ( $post_types as $post_type ) {
$this->filter( 'edd_download_columns', 'add_columns', 11 );
$this->filter( "manage_{$post_type}_posts_columns", 'add_columns', 11 );
$this->action( "manage_{$post_type}_posts_custom_column", 'columns_contents', 11, 2 );
$this->filter( "manage_edit-{$post_type}_sortable_columns", 'sortable_columns', 11 );
// Also make them hidden by default.
$user_id = get_current_user_id();
$columns_hidden = (array) get_user_meta( $user_id, "manageedit-{$post_type}columnshidden", true );
$maybe_hidden = get_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", true );
// Continue if default is already set.
if ( $maybe_hidden ) {
continue;
}
// Set it to hidden by default.
$columns_hidden = array_unique( array_merge( $columns_hidden, [ 'rank_math_title', 'rank_math_description' ] ) );
update_user_meta( $user_id, "manageedit-{$post_type}columnshidden", $columns_hidden );
update_user_meta( $user_id, "manageedit-{$post_type}columnshidden_default", '1' );
}
}
/**
* Register media column hooks.
*/
private function register_media_columns() {
if ( ! Helper::get_settings( 'titles.pt_attachment_bulk_editing' ) ) {
return;
}
$this->filter( 'manage_media_columns', 'add_media_columns', 11 );
$this->action( 'manage_media_custom_column', 'media_contents', 11, 2 );
}
/**
* Add new columns for SEO title, description and focus keywords.
*
* @param array $columns Array of column names.
*
* @return array
*/
public function add_columns( $columns ) {
global $post_type;
$current_pt = $post_type;
if ( ! $post_type && 'inline-save' === Param::post( 'action' ) ) {
$post_id = Param::post( 'post_ID', 0, FILTER_VALIDATE_INT );
$current_pt = get_post_type( $post_id );
}
$columns['rank_math_seo_details'] = esc_html__( 'SEO Details', 'rank-math' );
if ( Helper::get_settings( 'titles.pt_' . $current_pt . '_bulk_editing', true ) ) {
$columns['rank_math_title'] = esc_html__( 'SEO Title', 'rank-math' );
$columns['rank_math_description'] = esc_html__( 'SEO Desc', 'rank-math' );
}
return $columns;
}
/**
* Make the SEO Score column sortable.
*
* @param array $columns Array of column names.
*
* @return array
*/
public function sortable_columns( $columns ) {
$columns['rank_math_seo_details'] = 'rank_math_seo_score';
return $columns;
}
/**
* Add new columns for Media Alt & Title.
*
* @param array $columns Array of column names.
*
* @return array
*/
public function add_media_columns( $columns ) {
$columns['rank_math_image_title'] = esc_html__( 'Title', 'rank-math' );
$columns['rank_math_image_alt'] = esc_html__( 'Alternative Text', 'rank-math' );
return $columns;
}
/**
* Add content for custom column.
*
* @param string $column_name The name of the column to display.
* @param int $post_id The current post ID.
*/
public function columns_contents( $column_name, $post_id ) {
if ( Str::starts_with( 'rank_math', $column_name ) ) {
do_action( $column_name, $post_id );
}
}
/**
* Add content for title column.
*
* @param int $post_id The current post ID.
*/
public function get_column_title( $post_id ) {
$title = ! empty( $this->data[ $post_id ]['rank_math_title'] ) ? $this->data[ $post_id ]['rank_math_title'] : '';
if ( ! $title ) {
$post_type = get_post_type( $post_id );
$title = Helper::get_settings( "titles.pt_{$post_type}_title" );
}
?>
<span class="rank-math-column-display"><?php echo esc_html( $title ); ?></span>
<textarea class="rank-math-column-value" data-field="title" tabindex="11"><?php echo esc_attr( $title ); ?></textarea>
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Add content for title column.
*
* @param int $post_id The current post ID.
*/
public function get_column_description( $post_id ) {
$description = ! empty( $this->data[ $post_id ]['rank_math_description'] ) ? $this->data[ $post_id ]['rank_math_description'] : '';
if ( ! $description ) {
$post_type = get_post_type( $post_id );
$description = has_excerpt( $post_id ) ? '%excerpt%' : Helper::get_settings( "titles.pt_{$post_type}_description" );
}
?>
<span class="rank-math-column-display"><?php echo esc_html( $description ); ?></span>
<textarea class="rank-math-column-value" data-field="description" tabindex="11"><?php echo esc_attr( $description ); ?></textarea>
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Add content for title column.
*
* @param int $post_id The current post ID.
*/
public function get_column_seo_details( $post_id ) {
if ( empty( $this->data ) ) {
$this->get_seo_data();
}
$data = isset( $this->data[ $post_id ] ) ? $this->data[ $post_id ] : [];
if ( ! self::is_post_indexable( $post_id ) ) {
echo '<span class="rank-math-column-display seo-score no-score "><strong>N/A</strong></span>';
echo '<strong>' . esc_html__( 'No Index', 'rank-math' ) . '</strong>';
$this->do_action( 'post/column/seo_details', $post_id, $data, $this->data );
return;
}
$keyword = ! empty( $data['rank_math_focus_keyword'] ) ? $data['rank_math_focus_keyword'] : '';
$keyword = explode( ',', $keyword )[0];
$is_pillar = ! empty( $data['rank_math_pillar_content'] ) && 'on' === $data['rank_math_pillar_content'] ? true : false;
$score = empty( $keyword ) ? false : $this->get_seo_score( $data );
$class = ! $score ? 'no-score' : $this->get_seo_score_class( $score );
$score = $score ? $score . ' / 100' : 'N/A';
?>
<span class="rank-math-column-display seo-score <?php echo esc_attr( $class ); ?> <?php echo ! $score ? 'disabled' : ''; ?>">
<strong><?php echo esc_html( $score ); ?></strong>
<?php if ( $is_pillar ) { ?>
<img class="is-pillar" src="<?php echo esc_url( rank_math()->plugin_url() . 'assets/admin/img/pillar.svg' ); ?>" alt="<?php esc_html_e( 'Is Pillar', 'rank-math' ); ?>" title="<?php esc_html_e( 'Is Pillar', 'rank-math' ); ?>" width="25" />
<?php } ?>
</span>
<label><?php esc_html_e( 'Focus Keyword', 'rank-math' ); ?>:</label>
<span class="rank-math-column-display">
<strong title="Focus Keyword"><?php esc_html_e( 'Keyword', 'rank-math' ); ?>:</strong>
<span><?php echo $keyword ? esc_html( $keyword ) : esc_html__( 'Not Set', 'rank-math' ); ?></span>
</span>
<input class="rank-math-column-value" data-field="focus_keyword" tabindex="11" value="<?php echo esc_attr( $keyword ); ?>" />
<?php $this->do_action( 'post/column/seo_details', $post_id, $data, $this->data ); ?>
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
}
/**
* Add content for custom media column.
*
* @param string $column_name The name of the column to display.
* @param int $post_id The current post ID.
*/
public function media_contents( $column_name, $post_id ) {
if ( 'rank_math_image_title' === $column_name ) {
$title = get_the_title( $post_id );
?>
<span class="rank-math-column-display"><?php echo esc_html( $title ); ?></span>
<input class="rank-math-column-value" data-field="image_title" tabindex="11" value="<?php echo esc_attr( $title ); ?>" />
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
return;
}
if ( 'rank_math_image_alt' === $column_name ) {
$alt = get_post_meta( $post_id, '_wp_attachment_image_alt', true );
?>
<span class="rank-math-column-display"><?php echo esc_html( $alt ); ?></span>
<input class="rank-math-column-value" data-field="image_alt" tabindex="11" value="<?php echo esc_attr( $alt ); ?>" />
<div class="rank-math-column-edit">
<a href="#" class="rank-math-column-save"><?php esc_html_e( 'Save', 'rank-math' ); ?></a>
<a href="#" class="button-link-delete rank-math-column-cancel"><?php esc_html_e( 'Cancel', 'rank-math' ); ?></a>
</div>
<?php
return;
}
}
/**
* Get SEO data.
*/
private function get_seo_data() {
global $wp_query;
$post_ids = [];
if ( $wp_query->posts ) {
$post_ids = array_filter(
array_map(
function( $post ) {
return isset( $post->ID ) ? $post->ID : '';
},
$wp_query->posts
)
);
}
$post_id = (int) Param::post( 'post_ID' );
if ( $post_id ) {
$post_ids[] = $post_id;
}
if ( empty( $post_ids ) ) {
return false;
}
$results = Database::table( 'postmeta' )->select( [ 'post_id', 'meta_key', 'meta_value' ] )->whereIn( 'post_id', $post_ids )->whereLike( 'meta_key', 'rank_math' )->get( ARRAY_A );
if ( empty( $results ) ) {
return false;
}
foreach ( $results as $result ) {
$this->data[ $result['post_id'] ][ $result['meta_key'] ] = $result['meta_value'];
}
}
/**
* Get SEO score.
*
* @param array $data SEO data of current post.
*
* @return string
*/
private function get_seo_score( $data ) {
if ( ! isset( $data['rank_math_seo_score'] ) ) {
return false;
}
if ( ! Helper::is_score_enabled() ) {
return false;
}
return $data['rank_math_seo_score'] ? $data['rank_math_seo_score'] : 0;
}
/**
* Get SEO score rating string: great/good/bad.
*
* @param int $score Score.
*
* @return string
*/
private function get_seo_score_class( $score ) {
if ( $score > 80 ) {
return 'great';
}
if ( $score > 50 && $score < 81 ) {
return 'good';
}
return 'bad';
}
/**
* Check post indexable status.
*
* @param int $post_id Post ID.
*/
public static function is_post_indexable( $post_id ) {
$robots = Param::post( 'rank_math_robots', false, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$robots = apply_filters( 'rank_math/admin/robots', $robots, $post_id );
if ( ! empty( $robots ) ) {
return in_array( 'index', $robots, true ) ? true : false;
}
return Helper::is_post_indexable( $post_id );
}
}

View File

@@ -0,0 +1,384 @@
<?php
/**
* The admin post filters functionality.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use WP_Meta_Query;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Post_Filters class.
*/
class Post_Filters implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'admin_init', 'init' );
}
/**
* Intialize.
*/
public function init() {
if ( ! Helper::has_cap( 'general' ) ) {
return;
}
$this->filter( 'pre_get_posts', 'posts_by_seo_filters' );
$this->filter( 'parse_query', 'posts_by_focus_keywords' );
$this->filter( 'restrict_manage_posts', 'add_seo_filters', 11 );
foreach ( Helper::get_allowed_post_types() as $post_type ) {
$this->filter( "views_edit-$post_type", 'add_pillar_content_filter_link' );
}
}
/**
* Filter posts in admin by Rank Math's Filter value.
*
* @param \WP_Query $query The wp_query instance.
*/
public function posts_by_seo_filters( $query ) {
if ( ! $this->can_seo_filters() ) {
return;
}
if ( 'rank_math_seo_score' === $query->get( 'orderby' ) ) {
$query->set( 'orderby', 'meta_value' );
$query->set( 'meta_key', 'rank_math_seo_score' );
$query->set( 'meta_type', 'numeric' );
}
if ( empty( $_GET['pillar_content'] ) && empty( $_GET['seo-filter'] ) ) {
return;
}
$meta_query = [];
// Check for Pillar Content filter.
if ( ! empty( $_GET['pillar_content'] ) ) {
$meta_query[] = [
'key' => 'rank_math_pillar_content',
'value' => 'on',
];
}
$this->set_seo_filters( $meta_query );
$query->set( 'meta_query', $meta_query );
}
/**
* Filter post in admin by Pillar Content.
*
* @param \WP_Query $query The wp_query instance.
*/
public function posts_by_focus_keywords( $query ) {
if ( ! $this->can_fk_filter() ) {
return;
}
if ( $ids = $this->posts_had_reviews() ) { // phpcs:ignore
$query->set( 'post_type', 'any' );
$query->set( 'post__in', $ids );
return;
}
$query->set( 'post_status', 'publish' );
if ( $ids = $this->has_fk_in_title() ) { // phpcs:ignore
$query->set( 'post__in', $ids );
return;
}
$focus_keyword = Param::get( 'focus_keyword', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_BACKTICK );
if ( 1 === absint( $focus_keyword ) ) {
$query->set(
'meta_query',
[
'relation' => 'AND',
[
'key' => 'rank_math_focus_keyword',
'compare' => 'NOT EXISTS',
],
[
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
],
]
);
return;
}
$query->set( 'post_type', 'any' );
$query->set(
'meta_query',
[
[
'relation' => 'OR',
[
'key' => 'rank_math_focus_keyword',
'value' => $focus_keyword . ',',
'compare' => 'LIKE',
],
[
'key' => 'rank_math_focus_keyword',
'value' => $focus_keyword,
'compare' => 'LIKE',
],
],
]
);
}
/**
* Add SEO filters.
*/
public function add_seo_filters() {
global $post_type;
if ( 'attachment' === $post_type || ! in_array( $post_type, Helper::get_allowed_post_types(), true ) ) {
return;
}
$options = [
'' => esc_html__( 'Rank Math', 'rank-math' ),
'great-seo' => esc_html__( 'SEO Score: Good', 'rank-math' ),
'good-seo' => esc_html__( 'SEO Score: Ok', 'rank-math' ),
'bad-seo' => esc_html__( 'SEO Score: Bad', 'rank-math' ),
'empty-fk' => esc_html__( 'Focus Keyword Not Set', 'rank-math' ),
'noindexed' => esc_html__( 'Articles noindexed', 'rank-math' ),
];
$options = $this->do_filter( 'manage_posts/seo_filter_options', $options, $post_type );
$selected = Param::get( 'seo-filter' );
?>
<select name="seo-filter" id="rank-math-seo-filter">
<?php foreach ( $options as $val => $option ) : ?>
<option value="<?php echo esc_attr( $val ); ?>" <?php selected( $selected, $val, true ); ?>><?php echo esc_html( $option ); ?></option>
<?php endforeach; ?>
</select>
<?php
}
/**
* Add view to filter list for Pillar Content.
*
* @param array $views An array of available list table views.
*/
public function add_pillar_content_filter_link( $views ) {
global $typenow;
$current = empty( $_GET['pillar_content'] ) ? '' : ' class="current" aria-current="page"';
$pillars = get_posts(
[
'post_type' => $typenow,
'fields' => 'ids',
'posts_per_page' => -1,
'meta_key' => 'rank_math_pillar_content',
'meta_value' => 'on',
]
);
$views['pillar_content'] = sprintf(
'<a href="%1$s"%2$s>%3$s <span class="count">(%4$s)</span></a>',
Security::add_query_arg(
[
'post_type' => $typenow,
'pillar_content' => 1,
]
),
$current,
esc_html__( 'Pillar Content', 'rank-math' ),
number_format_i18n( count( $pillars ) )
);
return $views;
}
/**
* Can apply SEO filters.
*
* @return bool
*/
private function can_seo_filters() {
$screen = get_current_screen();
if ( is_null( $screen ) || ! in_array( $screen->post_type, Helper::get_allowed_post_types(), true ) ) {
return false;
}
return true;
}
/**
* Set SEO filters meta query.
*
* @param array $query Meta query.
*/
private function set_seo_filters( &$query ) {
$filter = Param::get( 'seo-filter' );
if ( false === $filter ) {
return;
}
$hash = [
'empty-fk' => [
'key' => 'rank_math_focus_keyword',
'compare' => 'NOT EXISTS',
],
'bad-seo' => [
'key' => 'rank_math_seo_score',
'value' => 50,
'compare' => '<=',
'type' => 'numeric',
],
'good-seo' => [
'key' => 'rank_math_seo_score',
'value' => [ 51, 80 ],
'compare' => 'BETWEEN',
'type' => 'numeric',
],
'great-seo' => [
'key' => 'rank_math_seo_score',
'value' => 80,
'compare' => '>',
'type' => 'numeric',
],
'noindexed' => [
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'LIKE',
],
];
// Extra conditions for "SEO Score" filters.
$seo_score_filters = [ 'bad-seo', 'good-seo', 'great-seo' ];
if ( in_array( $filter, $seo_score_filters, true ) ) {
$query['relation'] = 'AND';
$query[] = [
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
];
$query[] = [
'key' => 'rank_math_focus_keyword',
'compare' => 'EXISTS',
];
$query[] = [
'key' => 'rank_math_focus_keyword',
'value' => '',
'compare' => '!=',
];
}
if ( isset( $hash[ $filter ] ) ) {
$query[] = $hash[ $filter ];
}
}
/**
* Can apply Focus Keyword filter.
*
* @return bool
*/
private function can_fk_filter() {
$screen = get_current_screen();
if (
is_null( $screen ) ||
'edit' !== $screen->base ||
(
! isset( $_GET['focus_keyword'] ) &&
! isset( $_GET['fk_in_title'] ) &&
! isset( $_GET['review_posts'] )
)
) {
return false;
}
return true;
}
/**
* Check if Focus Keyword appears in the title.
*
* @return bool|array
*/
private function has_fk_in_title() {
global $wpdb;
if ( ! Param::get( 'fk_in_title' ) ) {
return false;
}
$screen = get_current_screen();
$meta_query = new WP_Meta_Query(
[
[
'key' => 'rank_math_focus_keyword',
'compare' => 'EXISTS',
],
[
'relation' => 'OR',
[
'key' => 'rank_math_robots',
'value' => 'noindex',
'compare' => 'NOT LIKE',
],
[
'key' => 'rank_math_robots',
'compare' => 'NOT EXISTS',
],
],
]
);
$meta_query = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
return $wpdb->get_col( "SELECT {$wpdb->posts}.ID FROM $wpdb->posts {$meta_query['join']} WHERE 1=1 {$meta_query['where']} AND {$wpdb->posts}.post_type = '$screen->post_type' AND ({$wpdb->posts}.post_status = 'publish') AND {$wpdb->posts}.post_title NOT LIKE CONCAT( '%', SUBSTRING_INDEX( {$wpdb->postmeta}.meta_value, ',', 1 ), '%' )" ); // phpcs:ignore
}
/**
* Check if any posts had Review schema.
*
* @return bool|array
*/
private function posts_had_reviews() {
global $wpdb;
$review_posts = Param::get( 'review_posts' );
if ( ! $review_posts ) {
return false;
}
return ! get_option( 'rank_math_review_posts_converted', false );
}
}

View File

@@ -0,0 +1,309 @@
<?php
/**
* Inform the user about Rank Math PRO after 20 days of usage.
*
* @since 1.0.69
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Pro_Notice class.
*/
class Pro_Notice {
use Hooker, Ajax;
/**
* Now.
*
* @var string
*/
public $current_time = '';
/**
* Rank Math plugin install date.
*
* @var string
*/
public $install_date = '';
/**
* Date of release of version 1.0.69. Turned into a timestamp in the constructor.
*
* @var string
*/
public $record_date = '2021-07-30 13:00';
/**
* Constructor method.
*/
public function __construct() {
$this->current_time = current_time( 'timestamp' );
$this->record_date = strtotime( $this->record_date );
$this->install_date = get_option( 'rank_math_install_date' );
if ( false === $this->install_date ) {
$this->install_date = $this->current_time;
}
}
/**
* Register hooks.
*/
public function hooks() {
$this->ajax( 'dismiss_pro_notice', 'dismiss' );
// Admin notice.
$notice_date = $this->get_notice_date();
if ( $this->current_time > $notice_date ) {
if ( get_option( 'rank_math_pro_notice_added' ) === false && ! Helper::has_notification( 'rank_math_review_plugin_notice' ) ) {
$this->add_notice( (int) get_option( 'rank_math_pro_notice_delayed' ) );
}
// Make dismiss button work like the "Maybe later" link.
$this->action( 'wp_helpers_notification_dismissed', 'pro_notice_after_dismiss' );
$this->action( 'admin_footer', 'pro_notice_js', 15 );
}
}
/**
* Add inline JS & CSS related to the Pro notice.
*
* @return void
*/
public function pro_notice_js() {
if ( ! Helper::has_notification( 'rank_math_pro_notice' ) ) {
return;
}
?>
<script>
(function( $ ) {
$( function() {
$('.rank-math-dismiss-pro-notice').on( 'click', function(e) {
var $this = $(this);
if ( ! $this.hasClass( 'rank-math-upgrade-action' ) ) {
e.preventDefault();
}
if ( $this.hasClass( 'rank-math-maybe-later-action' ) ) {
$('#rank_math_pro_notice').find( '.notice-dismiss' ).trigger('click');
return false;
}
jQuery.ajax( {
url: rankMath.ajaxurl,
data: { action: 'rank_math_already_upgraded', security: rankMath.security,
},
} );
$('#rank_math_pro_notice').find( '.notice-dismiss' ).trigger('click');
});
});
})(jQuery);
</script>
<style>
#rank_math_pro_notice.is-dismissible {
background: #253142;
color: #e4e5e7;
border-width: 3px;
border-style: solid;
border-color: #161e28;
padding: 0.25rem 1rem 1rem;
border-radius: 5px;
}
#rank_math_pro_notice.is-dismissible p {
font-size: 1.25rem;
color: #f7d070;
margin-bottom: 0;
}
#rank_math_pro_notice.is-dismissible ul {
line-height: 1;
margin-bottom: 0;
text-align: left;
opacity: 0.8;
font-size: 15px;
max-width: 530px;
}
#rank_math_pro_notice.is-dismissible li {
display: inline-block;
width: 49%;
margin-bottom: 0.5rem;
}
#rank_math_pro_notice ul li:before {
font-family: dashicons;
font-size: 20px;
width: 20px;
height: 20px;
margin-right: 5px;
content: '\f147';
text-align: center;
vertical-align: middle;
color: #161e28;
border-radius: 10px;
background: #9ce2b6;
}
#rank_math_pro_notice .button {
border-color: #f7d070;
background: #f7d070;
color: #5a4000;
font-size: 15px;
margin-right: 12px;
}
div#rank_math_pro_notice .rank-math-maybe-later-action,
div#rank_math_pro_notice .rank-math-already-upgraded-action {
color: #f7d070;
opacity: 0.7;
margin: 0 12px;
font-size: 13px;
}
.toplevel_page_rank-math #rank_math_pro_notice,
body[class*="rank-math_page_rank-math-options-"] div#rank_math_pro_notice {
display: none;
}
</style>
<?php
}
/**
* Add admin notice.
*
* @param int $variant Notice variant.
* @return void
*/
public function add_notice( $variant = 0 ) {
$message = $this->get_notice_text( $variant );
Helper::add_notification(
$message,
[
'type' => 'info',
'id' => 'rank_math_pro_notice',
'capability' => 'install_plugins',
]
);
update_option( 'rank_math_pro_notice_added', '1', false );
}
/**
* Get notice texts.
*
* @param integer $variant Message variant.
* @return string
*/
public function get_notice_text( $variant = 0 ) {
$message = '';
switch ( (int) $variant ) {
case 1:
$message = '<p><strong>';
$message .= esc_html__( 'Rank Your Content With the Power of PRO & A.I.', 'rank-math' );
$message .= '</strong></p>';
$message .= '<ul>
<li>' . esc_html__( 'Unlimited Websites', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Content A.I. (Artificial Intelligence)', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Keyword Rank Tracker', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Powerful Schema Generator', 'rank-math' ) . '</li>
<li>' . esc_html__( '24x7 Premium Support', 'rank-math' ) . '</li>
<li>' . esc_html__( 'SEO Email Reports', 'rank-math' ) . '</li>
<li>' . esc_html__( 'and Many More…', 'rank-math' ) . '</li>
</ul>';
$message .= '<p>
<a href="' . KB::get( 'pro', 'Upgrade Notice 2 New Yes' ) . '" class="button rank-math-dismiss-pro-notice rank-math-upgrade-action" target="_blank" rel="noopener noreferrer"><strong>' . esc_html__( 'Yes, I want to learn more', 'rank-math' ) . '</strong></a><a href="#" class="rank-math-dismiss-pro-notice rank-math-already-upgraded-action">' . esc_html__( 'No, I don\'t want it', 'rank-math' ) . '</a><a href="#" class="rank-math-dismiss-pro-notice rank-math-already-upgraded-action">' . esc_html__( 'I already upgraded', 'rank-math' ) . '</a>
</p>';
break;
default:
$message = '<p><strong>';
$message .= esc_html__( 'Rank Your Content With the Power of PRO & A.I.', 'rank-math' );
$message .= '</strong></p><p>';
$message .= '<ul>
<li>' . esc_html__( 'Unlimited Websites', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Content A.I. (Artificial Intelligence)', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Keyword Rank Tracker', 'rank-math' ) . '</li>
<li>' . esc_html__( 'Powerful Schema Generator', 'rank-math' ) . '</li>
<li>' . esc_html__( '24x7 Premium Support', 'rank-math' ) . '</li>
<li>' . esc_html__( 'SEO Email Reports', 'rank-math' ) . '</li>
<li>' . esc_html__( 'and Many More…', 'rank-math' ) . '</li>
</ul>';
$message .= '<p>
<a href="' . KB::get( 'pro', 'Upgrade Notice 1 New Yes' ) . '" class="button rank-math-dismiss-pro-notice rank-math-upgrade-action" target="_blank" rel="noopener noreferrer"><strong>' . esc_html__( 'Yes, I want better SEO', 'rank-math' ) . '</strong></a><a href="#" class="rank-math-dismiss-pro-notice rank-math-maybe-later-action">' . esc_html__( 'No, maybe later', 'rank-math' ) . '</a><a href="#" class="rank-math-dismiss-pro-notice rank-math-already-upgraded-action">' . esc_html__( 'I already purchased', 'rank-math' ) . '</a>
</p>';
break;
}
return $message;
}
/**
* Set "delayed" flag after the user dismisses the notice.
*
* @param string $notification_id Dismissed notice ID.
* @return void
*/
public function pro_notice_after_dismiss( $notification_id ) {
if ( 'rank_math_pro_notice' !== $notification_id ) {
return;
}
// If it has already been delayed once then dismiss it forever.
if ( get_option( 'rank_math_pro_notice_delayed' ) ) {
update_option( 'rank_math_already_upgraded', current_time( 'timestamp' ) );
return;
}
delete_option( 'rank_math_pro_notice_date' );
delete_option( 'rank_math_pro_notice_added' );
update_option( 'rank_math_pro_notice_delayed', 1, false );
}
/**
* Get stored notice start date.
*
* @return int
*/
public function get_notice_date() {
$notice_date = get_option( 'rank_math_pro_notice_date' );
if ( false !== $notice_date ) {
return $notice_date;
}
$delay_days = 10;
if ( $this->install_date < $this->record_date && ! get_option( 'rank_math_pro_notice_delayed' ) ) {
$delay_days = wp_rand( 7, 30 );
}
$notice_date = $this->current_time + ( $delay_days * DAY_IN_SECONDS );
update_option( 'rank_math_pro_notice_date', $notice_date, false );
return $notice_date;
}
/**
* Set the "already upgraded" flag.
* This also sets the "already reviewed" flag, so the review notice will not show up anymore either.
*/
public function dismiss() {
check_ajax_referer( 'rank-math-ajax-nonce', 'security' );
$this->has_cap_ajax( 'onpage_general' );
update_option( 'rank_math_already_upgraded', current_time( 'timestamp' ) );
update_option( 'rank_math_already_reviewed', current_time( 'timestamp' ) );
$this->success( 'success' );
}
}

View File

@@ -0,0 +1,414 @@
<?php
/**
* The Setup Wizard - configure the SEO settings in just a few steps.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\Param;
use RankMath\Helpers\Security;
use RankMath\Google\Authentication;
defined( 'ABSPATH' ) || exit;
/**
* Registration class.
*/
class Registration {
use Hooker;
/**
* Page slug.
*
* @var string
*/
private $slug = 'rank-math-registration';
/**
* Hold current step.
*
* @var string
*/
protected $step = '';
/**
* Current step slug.
*
* @var string
*/
protected $step_slug = '';
/**
* The text string array.
*
* @var array
*/
protected $strings = null;
/**
* Is registration invalid.
*
* @var bool
*/
public $invalid = false;
/**
* The Constructor.
*/
public function __construct() {
// Strings passed in from the config file.
$this->strings = [
'title' => esc_html__( 'Rank Math Product Registration', 'rank-math' ),
'return-to-dashboard' => esc_html__( 'Return to dashboard', 'rank-math' ),
];
$this->step = 'register';
$this->step_slug = 'register';
$this->invalid = Helper::is_invalid_registration();
if ( $this->invalid ) {
$this->action( 'admin_menu', 'admin_menu' );
$this->action( 'admin_init', 'redirect_to_welcome' );
$this->action( 'admin_post_rank_math_save_registration', 'save_registration' );
$this->action( 'admin_post_rank_math_skip_wizard', 'skip_wizard' );
$this->action( 'admin_init', 'render_page', 30 );
}
$this->action( 'admin_init', 'handle_registration' );
}
/**
* Check for activation.
*/
public function handle_registration() {
// Bail if already connected.
if ( Helper::is_site_connected() ) {
return;
}
if ( ! Helper::has_cap( 'general' ) ) {
return;
}
$nonce = Param::get( 'nonce' );
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'rank_math_register_product' ) ) {
return;
}
$status = Param::get( 'rankmath_connect' );
if ( $status && $redirect_to = $this->get_registration_url( $status ) ) { //phpcs:ignore
Helper::redirect( $redirect_to );
exit;
}
}
/**
* Handle activation.
*
* @param string $status Status parameter.
*/
private function get_registration_url( $status ) {
if ( 'cancel' === $status ) {
// User canceled activation.
Helper::add_notification( __( 'Rank Math plugin could not be connected.', 'rank-math' ), [ 'type' => 'error' ] );
return Security::remove_query_arg_raw( [ 'rankmath_connect', 'rankmath_auth' ] );
}
if ( 'banned' === $status ) {
// User or site banned.
Helper::add_notification( __( 'Unable to connect Rank Math.', 'rank-math' ), [ 'type' => 'error' ] );
return Security::remove_query_arg_raw( [ 'rankmath_connect', 'rankmath_auth' ] );
}
if ( 'ok' === $status && $auth_data = $this->get_registration_params() ) { // phpcs:ignore
Admin_Helper::get_registration_data(
[
'username' => $auth_data['username'],
'email' => $auth_data['email'],
'api_key' => $auth_data['api_key'],
'plan' => $auth_data['plan'],
'connected' => true,
'site_url' => Helper::get_home_url(),
]
);
if ( 1 == Param::get( 'analytics' ) ) {
wp_redirect( Authentication::get_auth_url() );
exit;
}
// Redirect to the wizard is registration successful.
if ( Param::get( 'page' ) === 'rank-math-registration' ) {
return Helper::get_admin_url( 'wizard' );
}
return Security::remove_query_arg_raw( [ 'rankmath_connect', 'rankmath_auth', 'nonce' ] );
}
return false;
}
/**
* Check if 'rankmath_auth' contains all the data we need, in the
* correct format.
*
* @return bool|array Whether the input is valid.
*/
private function get_registration_params() {
$params = Param::get( 'rankmath_auth' );
if ( false === $params ) {
return false;
}
$params = json_decode( base64_decode( $params ), true );
if (
! is_array( $params ) ||
! isset( $params['username'] ) ||
! isset( $params['email'] ) ||
! isset( $params['api_key'] )
) {
return false;
}
return $params;
}
/**
* Redirect to welcome page.
*
* Redirect the user to the welcome page after plugin activation.
*/
public function redirect_to_welcome() {
if ( ! $this->can_redirect() ) {
return;
}
$url = '';
if ( $this->invalid ) {
$url = 'registration';
} elseif ( ! get_option( 'rank_math_wizard_completed' ) ) {
$url = 'wizard';
}
Helper::redirect( Helper::get_admin_url( $url ) );
exit;
}
/**
* Add menu items.
*/
public function admin_menu() {
add_menu_page(
esc_html__( 'Rank Math', 'rank-math' ),
esc_html__( 'Rank Math SEO', 'rank-math' ),
'manage_options',
$this->slug,
[ $this, 'render_page' ]
);
}
/**
* Output the admin page.
*/
public function render_page() {
// Early bail if we're not on the right page.
if ( Param::get( 'page' ) !== $this->slug ) {
return;
}
if ( ob_get_length() ) {
ob_end_clean();
}
$assets = new Assets();
$assets->register();
wp_styles()->done = [];
wp_scripts()->done = [];
// Enqueue styles.
\CMB2_Hookup::enqueue_cmb_css();
\CMB2_Hookup::enqueue_cmb_js();
// Wizard.
wp_enqueue_style( 'rank-math-wizard', rank_math()->plugin_url() . 'assets/admin/css/setup-wizard.css', [ 'wp-admin', 'buttons', 'cmb2-styles', 'rank-math-common', 'rank-math-cmb2' ], rank_math()->version );
$logo_url = '<a href="' . KB::get( 'logo', 'SW Logo' ) . '" target="_blank"><img src="' . esc_url( rank_math()->plugin_url() . 'assets/admin/img/logo.svg' ) . '"></a>';
ob_start();
/**
* Start the actual page content.
*/
include_once $this->get_view( 'header' );
include_once $this->get_view( 'content' );
include_once $this->get_view( 'footer' );
exit;
}
/**
* Render page body.
*/
protected function body() {
?>
<header>
<?php $this->header_content(); ?>
</header>
<?php rank_math()->notification->display(); ?>
<?php $this->show_connect_button(); ?>
<footer class="form-footer wp-core-ui rank-math-ui">
<button type="submit" class="button button-<?php echo $this->invalid ? 'secondary' : 'primary alignright'; ?>" formnovalidate id="skip-registration" style="margin-right:15px"><?php echo $this->invalid ? esc_html__( 'Skip Now', 'rank-math' ) : esc_html__( 'Next', 'rank-math' ); ?></button>
</footer>
<?php
$this->print_script();
}
/**
* Output connect button (instead of the old connect form).
*/
private function show_connect_button() {
Admin_Helper::maybe_show_invalid_siteurl_notice();
?>
<div class="text-center wp-core-ui rank-math-ui" style="margin-top: 30px;">
<button type="submit" class="button button-primary button-connect <?php echo Admin_Helper::is_site_url_valid() ? 'button-animated' : 'disabled'; ?>" name="rank_math_activate"><?php echo esc_attr__( 'Connect Your Account', 'rank-math' ); ?></button>
</div>
<?php
}
/**
* Header content.
*/
private function header_content() {
if ( $this->invalid ) :
?>
<h1><?php esc_html_e( 'Connect FREE Account', 'rank-math' ); ?></h1>
<p class="rank-math-gray-box">
<?php
/* translators: Link to Free Account Benefits KB article */
printf( esc_html__( 'By connecting your free account, you get keyword suggestions directly from Google when entering the focus keywords. Not only that, get access to our revolutionary Content AI, SEO Analyzer inside WordPress that scans your website for SEO errors and suggest improvements. %s', 'rank-math' ), '<a href="' . KB::get( 'free-account-benefits', 'SW Connect Free Account' ) . '" target="_blank">' . esc_html__( 'Read more by following this link.', 'rank-math' ) . '</a>' );
?>
</p>
<?php
return;
endif;
?>
<h1><?php esc_html_e( 'Account Successfully Connected', 'rank-math' ); ?></h1>
<h3 style="text-align: center; padding-top:15px;"><?php esc_html_e( 'You have successfully activated Rank Math.', 'rank-math' ); ?></h3>
<?php
}
/**
* Execute save handler for current step.
*/
public function save_registration() {
// If no form submission, bail.
$referer = Param::post( '_wp_http_referer', get_dashboard_url() );
if ( Param::post( 'step' ) !== 'register' ) {
return Helper::redirect( $referer );
}
check_admin_referer( 'rank-math-wizard', 'security' );
if ( ! Helper::has_cap( 'general' ) ) {
return Helper::redirect( $referer );
}
$this->redirect_to_connect( $_POST );
}
/**
* Skip wizard handler.
*/
public function skip_wizard() {
check_admin_referer( 'rank-math-wizard', 'security' );
if ( ! Helper::has_cap( 'general' ) ) {
exit;
}
add_option( 'rank_math_registration_skip', true );
Helper::redirect( Helper::get_admin_url( 'wizard' ) );
exit;
}
/**
* Authenticate registration.
*
* @param array $values Array of values for the step to process.
*/
private function redirect_to_connect( $values ) {
if ( ! isset( $values['rank_math_activate'] ) ) {
Admin_Helper::deregister_user();
return;
}
$url = Admin_Helper::get_activate_url( Helper::get_admin_url( 'registration' ) );
wp_redirect( $url );
die();
}
/**
* Can redirect to setup/registration page after install.
*
* @return bool
*/
private function can_redirect() {
if ( ! get_transient( '_rank_math_activation_redirect' ) ) {
return false;
}
delete_transient( '_rank_math_activation_redirect' );
if ( ( ! empty( $_GET['page'] ) && in_array( $_GET['page'], [ 'rank-math-registration', 'rank-math-wizard' ], true ) ) || ! current_user_can( 'manage_options' ) ) {
return false;
}
return true;
}
/**
* Get view file to display.
*
* @param string $view View to display.
* @return string
*/
private function get_view( $view ) {
if ( 'navigation' === $view ) {
$view = 'no-navigation';
}
return rank_math()->admin_dir() . "wizard/views/{$view}.php";
}
/**
* Print Javascript.
*/
private function print_script() {
?>
<script>
(function($){
$(function() {
$( '#skip-registration' ).on( 'click', function( event ) {
$('[name="action"]').val( 'rank_math_skip_wizard' );
});
});
})(jQuery);
</script>
<?php
}
}

View File

@@ -0,0 +1,516 @@
<?php
/**
* The SERP preview functionality, in the metabox.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Rewrite;
use RankMath\Schema\DB;
defined( 'ABSPATH' ) || exit;
/**
* Serp_Preview class.
*/
class Serp_Preview {
/**
* Display SERP preview.
*/
public function display() {
$method = 'get_' . CMB2::current_object_type() . '_data';
$data = $this->$method();
if ( 'post' === CMB2::current_object_type() && Helper::is_module_active( 'rich-snippet' ) ) {
$snippet_preview = $this->get_snippet_html();
}
$favicon = esc_url( get_site_icon_url( 16 ) );
if ( empty( $favicon ) ) {
$favicon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABs0lEQVR4AWL4//8/RRjO8Iucx+noO0MWUDo16FYABMGP6ZfUcRnWtm27jVPbtm3bttuH2t3eFPcY9pLz7NxiLjCyVd87pKnHyqXyxtCs8APd0rnyxiu4qSeA3QEDrAwBDrT1s1Rc/OrjLZwqVmOSu6+Lamcpp2KKMA9PH1BYXMe1mUP5qotvXTywsOEEYHXxrY+3cqk6TMkYpNr2FeoY3KIr0RPtn9wQ2unlA+GMkRw6+9TFw4YTwDUzx/JVvARj9KaedXRO8P5B1Du2S32smzqUrcKGEyA+uAgQjKX7zf0boWHGfn71jIKj2689gxp7OAGShNcBUmLMPVjZuiKcA2vuWHHDCQxMCz629kXAIU4ApY15QwggAFbfOP9DhgBJ+nWVJ1AZAfICAj1pAlY6hCADZnveQf7bQIwzVONGJonhLIlS9gr5mFg44Xd+4S3XHoGNPdJl1INIwKyEgHckEhgTe1bGiFY9GSFBYUwLh1IkiJUbY407E7syBSFxKTszEoiE/YdrgCEayDmtaJwCI9uu8TKMuZSVfSa4BpGgzvomBR/INhLGzrqDotp01ZR8pn/1L0JN9d9XNyx0AAAAAElFTkSuQmCC';
}
$snippet_type = isset( $snippet_preview['type'] ) ? $snippet_preview['type'] : '';
$desktop_preview = isset( $snippet_preview['desktop'] ) ? $snippet_preview['desktop'] : '';
$mobile_preview = isset( $snippet_preview['mobile'] ) ? $snippet_preview['mobile'] : '';
?>
<div class="serp-preview desktop-preview serp-<?php echo esc_attr( $snippet_type ); ?>">
<div class="serp-preview-title" data-title="<?php esc_attr_e( 'Preview', 'rank-math' ); ?>" data-desktop="<?php esc_attr_e( 'Desktop Preview', 'rank-math' ); ?>" data-mobile="<?php esc_attr_e( 'Mobile Preview', 'rank-math' ); ?>">
<div class="alignright">
<a href="#" class="button button-secondary button-small rank-math-select-device device-desktop" data-device="desktop"><span class="rm-icon rm-icon-desktop"></span></a>
<a href="#" class="button button-secondary button-small rank-math-select-device device-mobile" data-device="mobile"><span class="rm-icon rm-icon-mobile"></span></a>
</div>
</div>
<div class="serp-preview-wrapper">
<div class="serp-preview-bg">
<div class="serp-preview-input">
<input type="text" value="Rank Math" disabled />
<span class="serp-search">
<svg focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></svg>
</span>
<span class="serp-mic"></span>
</div>
<div class="serp-preview-menus">
<ul>
<li class="current"> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgweiIvPjxwYXRoIGZpbGw9IiMzNEE4NTMiIGQ9Ik0xMCAydjJhNiA2IDAgMCAxIDYgNmgyYTggOCAwIDAgMC04LTh6Ii8+PHBhdGggZmlsbD0iI0VBNDMzNSIgZD0iTTEwIDRWMmE4IDggMCAwIDAtOCA4aDJjMC0zLjMgMi43LTYgNi02eiIvPjxwYXRoIGZpbGw9IiNGQkJDMDQiIGQ9Ik00IDEwSDJhOCA4IDAgMCAwIDggOHYtMmMtMy4zIDAtNi0yLjY5LTYtNnoiLz48cGF0aCBmaWxsPSIjNDI4NUY0IiBkPSJNMjIgMjAuNTlsLTUuNjktNS42OUE3Ljk2IDcuOTYgMCAwIDAgMTggMTBoLTJhNiA2IDAgMCAxLTYgNnYyYzEuODUgMCAzLjUyLS42NCA0Ljg4LTEuNjhsNS42OSA1LjY5TDIyIDIwLjU5eiIvPjwvc3ZnPgo=" alt="" data-atf="1"> All</li>
<li><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"></path><path d="M14 13l4 5H6l4-4 1.79 1.78L14 13zm-6.01-2.99A2 2 0 0 0 8 6a2 2 0 0 0-.01 4.01zM22 5v14a3 3 0 0 1-3 2.99H5c-1.64 0-3-1.36-3-3V5c0-1.64 1.36-3 3-3h14c1.65 0 3 1.36 3 3zm-2.01 0a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h7v-.01h7a1 1 0 0 0 1-1V5z"></path></svg> Images</li>
<li><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M0 0h24v24H0z" fill="none"></path><path clip-rule="evenodd" d="M10 16.5l6-4.5-6-4.5v9zM5 20h14a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1zm14.5 2H5a3 3 0 0 1-3-3V4.4A2.4 2.4 0 0 1 4.4 2h15.2A2.4 2.4 0 0 1 22 4.4v15.1a2.5 2.5 0 0 1-2.5 2.5z" fill-rule="evenodd"></path></svg> Videos</li>
<li><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"></path><path d="M12 11h6v2h-6v-2zm-6 6h12v-2H6v2zm0-4h4V7H6v6zm16-7.22v12.44c0 1.54-1.34 2.78-3 2.78H5c-1.64 0-3-1.25-3-2.78V5.78C2 4.26 3.36 3 5 3h14c1.64 0 3 1.25 3 2.78zM19.99 12V5.78c0-.42-.46-.78-1-.78H5c-.54 0-1 .36-1 .78v12.44c0 .42.46.78 1 .78h14c.54 0 1-.36 1-.78V12zM12 9h6V7h-6v2z"></path></svg> News</li>
<li><svg focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></svg> More</li>
</ul>
<ul class="menus-right">
<li>Settings</li>
<li>Tools</li>
</ul>
</div>
<div class="serp-preview-result-stats">
About 43,700,000 results (0.32 seconds)&nbsp;
</div>
</div>
<div class="serp-preview-body">
<div class="serp-url-wrapper">
<img src="<?php echo $favicon; // phpcs:ignore ?>" width="16" height="16" class="serp-favicon" />
<span class="serp-url" data-baseurl="<?php echo trailingslashit( substr( $data['url'], 0, strrpos( $data['url'], '/' ) ) ); ?>" data-format="<?php echo esc_attr( $data['permalink_format'] ); ?>" data-empty-title="<?php esc_attr_e( 'Click to enter permalink', 'rank-math' ); ?>"><?php echo esc_url( $data['permalink'] ); ?></span>
</div>
<h5 class="serp-title" data-format="<?php echo esc_attr( $data['title_format'] ); ?>" data-empty-title="<?php esc_attr_e( 'Click to enter custom title', 'rank-math' ); ?>"></h5>
<p class="serp-description" data-format="<?php echo esc_attr( $data['desc_format'] ); ?>" data-empty-title="<?php esc_attr_e( 'Click to enter custom meta description', 'rank-math' ); ?>"></p>
<?php
if ( 'event' !== $snippet_type ) {
echo $desktop_preview; // phpcs:ignore
}
if ( 'event' === $snippet_type ) {
echo $desktop_preview; // phpcs:ignore
}
echo $mobile_preview; // phpcs:ignore
?>
</div>
<div class="serp-preview-noindex">
<h3><?php esc_html_e( 'Noindex robots meta is enabled', 'rank-math' ); ?></h3>
<p><?php esc_html_e( 'This page will not appear in search results. You can disable noindex in the Advanced tab.', 'rank-math' ); ?></p>
</div>
</div>
</div>
<?php
}
/**
* Get post data for SERP preview.
*
* @return array
*/
private function get_post_data() {
global $post;
setup_postdata( $post );
$post_type = Helper::get_post_type();
$title_format = Helper::get_settings( "titles.pt_{$post_type}_title" );
$desc_format = Helper::get_settings( "titles.pt_{$post_type}_description" );
$title_format = $title_format ? $title_format : '%title%';
// Get the permalink.
list( $permalink_format ) = get_sample_permalink( $post->ID, null, null );
$permalink = $permalink_format;
if ( 'publish' === $post->post_status || 'attachment' === $post->post_type ) {
$permalink = get_permalink( $post );
} elseif ( 'auto-draft' === $post->post_status && 'post' === $post->post_type ) {
$post_temp = $post;
$post_temp->post_status = 'publish';
$permalink = get_permalink( $post_temp, true );
$permalink_format = $permalink;
$post_temp->post_status = 'auto-draft';
} else {
$permalink = str_replace( [ '%pagename%', '%postname%' ], ( $post->post_name ? $post->post_name : sanitize_title( $post->post_title ) ), $permalink_format );
}
$url = untrailingslashit( esc_url( $permalink ) );
return compact( 'title_format', 'desc_format', 'url', 'permalink', 'permalink_format' );
}
/**
* Get term data for SERP preview.
*
* @return array
*/
private function get_term_data() {
global $taxnow, $wp_rewrite;
$term_id = Param::request( 'tag_ID', 0, FILTER_VALIDATE_INT );
$term = get_term( $term_id, $taxnow, OBJECT, 'edit' );
$taxonomy = get_taxonomy( $term->taxonomy );
$title_format = Helper::get_settings( "titles.tax_{$term->taxonomy}_title" );
$desc_format = Helper::get_settings( "titles.tax_{$term->taxonomy}_description" );
$title_format = $title_format ? $title_format : '%term%';
// Get the permalink.
$permalink = untrailingslashit( esc_url( get_term_link( $term_id, $term->taxonomy ) ) );
$termlink = $wp_rewrite->get_extra_permastruct( $term->taxonomy );
// Pretty permalinks disabled.
if ( empty( $termlink ) ) {
$permalink_format = $permalink;
} else {
$termlink = str_replace( $this->get_home_url(), '', $permalink );
$termlink = str_replace( $term->slug, '%postname%', $termlink );
$permalink_format = $this->get_home_url( user_trailingslashit( $termlink, 'category' ) );
}
$url = untrailingslashit( esc_url( $permalink ) );
return compact( 'title_format', 'desc_format', 'url', 'permalink', 'permalink_format' );
}
/**
* Get Home URL based on the language if Polylang plugin is active.
*
* @param string $path Optional. Path relative to the home URL. Default empty.
*
* @return string
*/
private function get_home_url( $path = '' ) {
if ( ! function_exists( 'pll_home_url' ) ) {
return Helper::get_home_url( $path );
}
return trailingslashit( pll_home_url() ) . $path;
}
/**
* Get user data for SERP preview.
*
* @return array
*/
private function get_user_data() {
global $user_id, $wp_rewrite;
$title_format = Helper::get_settings( 'titles.author_archive_title' );
$desc_format = Helper::get_settings( 'titles.author_archive_description' );
$title_format = $title_format ? $title_format : '%author%';
Rewrite::change_author_base();
$permalink = untrailingslashit( esc_url( get_author_posts_url( $user_id ) ) );
$link = $wp_rewrite->get_author_permastruct();
$permalink_format = empty( $link ) ? $permalink : $this->get_author_permalink( $link );
$url = untrailingslashit( esc_url( $permalink ) );
return compact( 'title_format', 'desc_format', 'url', 'permalink', 'permalink_format' );
}
/**
* Get user permalink
*
* @param string $link Permalink structure.
* @return string
*/
private function get_author_permalink( $link ) {
$link = str_replace( '%author%', '%postname%', $link );
return home_url( user_trailingslashit( $link ) );
}
/**
* Get Snippet HTML for SERP preview.
*/
private function get_snippet_html() {
$snippet_data = $this->get_snippet_data();
if ( ! $snippet_data || empty( $snippet_data['data'] ) ) {
return false;
}
$data = $snippet_data['data'];
$rating = isset( $data['rating'] ) ? $data['rating'] : '';
$rating_count = isset( $data['rating_count'] ) ? $data['rating_count'] : '';
unset( $data['rating'] );
unset( $data['rating_count'] );
if ( isset( $data['price'] ) && isset( $data['currency'] ) ) {
$data['price'] = $data['currency'] . ' ' . $data['price'];
unset( $data['currency'] );
}
$html = [
'type' => $snippet_data['type'],
'desktop' => $this->get_desktop_preview( $data, $rating, $rating_count ),
'mobile' => $this->get_mobile_preview( $data, $rating, $rating_count ),
];
return $html;
}
/**
* Get desktop preview.
*
* @param array $data Snippet data array.
* @param int $rating Ratings.
* @param int $rating_count Rating count.
* @return string
*/
private function get_desktop_preview( $data, $rating, $rating_count ) {
$preview = '';
$labels = [
'price_range' => esc_html__( 'Price range: ', 'rank-math' ),
'calories' => esc_html__( 'Calories: ', 'rank-math' ),
];
if ( $rating ) {
$preview .= $this->get_ratings( $rating );
/* translators: total reviews */
$preview .= '<span class="serp-rating-label">' . sprintf( esc_html__( 'Rating: %s', 'rank-math' ), esc_html( $rating ) ) . '</span>';
if ( $rating_count ) {
/* translators: total reviews */
$preview .= '<span class="serp-review-count"> - ' . sprintf( esc_html__( '%s reviews', 'rank-math' ), esc_html( $rating_count ) ) . '</span>';
}
}
foreach ( $data as $key => $value ) {
if ( ! $value || in_array( $key, [ 'min', 'max' ], true ) ) {
continue;
}
if ( ! in_array( $key, [ 'event_date', 'event_place', 'event_name' ], true ) ) {
$preview .= '<span class="separator"> - </span>';
}
$preview .= '<span class="serp-' . $key . '">';
if ( isset( $labels[ $key ] ) ) {
$preview .= $labels[ $key ];
}
$preview .= $value;
$preview .= '</span>';
}
return '<div class="serp-snippet-data">' . $preview . '</div>';
}
/**
* Get mobile preview.
*
* @param array $data Snippet data array.
* @param int $rating Ratings.
* @param int $rating_count Rating count.
* @return string
*/
private function get_mobile_preview( $data, $rating, $rating_count ) {
$labels = [
'price' => esc_html__( 'Price', 'rank-math' ),
'price_range' => esc_html__( 'Price range', 'rank-math' ),
'time' => esc_html__( 'Cooking time', 'rank-math' ),
'calories' => esc_html__( 'Calories', 'rank-math' ),
'in_stock' => esc_html__( 'In Stock', 'rank-math' ),
'event_date' => esc_html__( 'Date', 'rank-math' ),
'event_place' => esc_html__( 'Location', 'rank-math' ),
];
$preview = '';
if ( $rating ) {
$preview .= '<span class="inner-wrapper">';
$preview .= '<span class="serp-mobile-label">';
$preview .= esc_html__( 'Rating', 'rank-math' );
$preview .= '</span>';
$preview .= '<span class="serp-rating-count">' . esc_html( $rating ) . '</span>';
$preview .= $this->get_ratings( $rating );
if ( $rating_count ) {
$preview .= '<span class="serp-review-count">(' . esc_html( $rating_count ) . ')</span>';
}
$preview .= '</span>';
}
foreach ( $data as $key => $value ) {
if ( ! $value || in_array( $key, [ 'event_name', 'min', 'max' ], true ) ) {
continue;
}
$preview .= '<span class="inner-wrapper">';
if ( isset( $labels[ $key ] ) ) {
$preview .= '<span class="serp-mobile-label">';
$preview .= $labels[ $key ];
$preview .= '</span>';
}
if ( 'in_stock' !== $key ) {
$preview .= '<span class="serp-' . $key . '">' . esc_html( $value ) . '</span>';
}
$preview .= '</span>';
}
return '<div class="serp-snippet-mobile">' . $preview . '</div>';
}
/**
* Get Star Ratings.
*
* @param int $rating Rating count.
*/
private function get_ratings( $rating ) {
$html = '';
$rating = $rating * 20;
for ( $i = 1; $i <= 5; $i++ ) {
$html .= '<span class="dashicons dashicons-star-filled"></span>';
}
$html .= '<div class="serp-result" style="width:' . $rating . '%;">';
for ( $i = 1; $i <= 5; $i++ ) {
$html .= '<span class="dashicons dashicons-star-filled"></span>';
}
return '<span class="serp-rating serp-desktop-rating"><div class="serp-star-rating">' . $html . '</div></div></span>';
}
/**
* Get Snippet Data for SERP preview.
*
* @return array
*/
private function get_snippet_data() {
global $post;
setup_postdata( $post );
$schemas = array_filter(
DB::get_schemas( $post->ID ),
function( $schema ) {
return ! empty( $schema['metadata']['isPrimary'] );
}
);
if ( empty( $schemas ) ) {
return false;
}
// Get rich snippet.
$schema = current( $schemas );
$snippet = strtolower( $schema['@type'] );
$method = "get_{$snippet}_data";
return [
'type' => $snippet,
'data' => method_exists( $this, $method ) ? $this->$method( $schema ) : $this->get_ratings_data( $schema ),
];
}
/**
* Get WooCommerce Product schema data.
*
* @param array $schema Schema Data.
* @return array Preview Schema Data.
*/
private function get_woocommerceproduct_data( $schema ) {
if ( ! Helper::is_woocommerce_active() ) {
return [];
}
global $post;
$product = wc_get_product( $post->ID );
return [
'price' => $product->get_price(),
'currency' => get_woocommerce_currency_symbol(),
'in_stock' => 'outofstock' === $product->get_stock_status() ? esc_html__( 'Out of stock', 'rank-math' ) : __( 'In stock', 'rank-math' ),
'rating' => $product->get_average_rating(),
'rating_count' => (string) $product->get_rating_count(),
];
}
/**
* Get Product schema data.
*
* @param array $schema Schema Data.
* @return array Preview Schema Data.
*/
private function get_product_data( $schema ) {
$offers = [];
if ( isset( $schema['offers'] ) ) {
$offers = [
'price' => isset( $schema['offers']['price'] ) ? $schema['offers']['price'] : '',
'currency' => isset( $schema['offers']['priceCurrency'] ) ? $schema['offers']['priceCurrency'] : '',
'in_stock' => isset( $schema['offers']['availability'] ) && 'SoldOut' === $schema['offers']['availability'] ? esc_html__( 'Out of stock', 'rank-math' ) : esc_html__( 'In stock', 'rank-math' ),
];
}
return \array_merge(
$offers,
$this->get_ratings_data( $schema )
);
}
/**
* Get Event schema data.
*
* @param array $schema Schema Data.
* @return array Preview Schema Data.
*/
private function get_event_data( $schema ) {
global $post;
$address = '';
if ( ! empty( $schema['location']['address'] ) ) {
unset( $schema['location']['address']['@type'] );
$address = implode( ', ', array_filter( $schema['location']['address'] ) );
}
return \array_merge(
[
'event_name' => Helper::replace_vars( $schema['name'], $post ),
'event_date' => ! empty( $schema['startDate'] ) ? date_i18n( 'j M Y', $schema['startDate'] ) : '',
'event_place' => $address,
],
$this->get_ratings_data( $schema )
);
}
/**
* Get Recipe schema data.
*
* @param array $schema Schema Data.
* @return array Preview Schema Data.
*/
private function get_recipe_data( $schema ) {
return \array_merge(
[
'time' => ! empty( $schema['totalTime'] ) ? $schema['totalTime'] : '',
'calories' => ! empty( $schema['nutrition'] ) && ! empty( $schema['nutrition']['calories'] ) ? $schema['nutrition']['calories'] : '',
],
$this->get_ratings_data( $schema )
);
}
/**
* Get Ratings schema data.
*
* @param array $schema Schema Data.
* @return array Preview Schema Data.
*/
private function get_ratings_data( $schema ) {
$review = isset( $schema['review'] ) && isset( $schema['review']['reviewRating']['ratingValue'] ) ? $schema['review']['reviewRating'] : '';
if ( empty( $review ) ) {
return [];
}
return [
'rating' => $review['ratingValue'],
'min' => ! empty( $review['worstRating'] ) ? $review['worstRating'] : 1,
'max' => ! empty( $review['bestRating'] ) ? $review['bestRating'] : 5,
];
}
}

View File

@@ -0,0 +1,402 @@
<?php
/**
* The Setup Wizard - configure the SEO settings in just a few steps.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Traits\Wizard;
use RankMath\Helpers\Security;
use RankMath\Admin\Importers\Detector;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Setup_Wizard class.
*/
class Setup_Wizard {
use Hooker, Wizard;
/**
* Hold steps data.
*
* @var array
*/
protected $steps = [];
/**
* Hold current step.
*
* @var string
*/
protected $step = '';
/**
* Current step slug.
*
* @var string
*/
protected $step_slug = '';
/**
* Top level admin page.
*
* @var string
*/
protected $slug = 'rank-math-wizard';
/**
* CMB2 object.
*
* @var \CMB2
*/
public $cmb = null;
/**
* Wizard Step instance.
*
* @var Wizard_Step
*/
public $wizard_step = null;
/**
* Hook suffix.
*
* @var string
*/
public $hook_suffix = '';
/**
* The Constructor.
*/
public function __construct() {
$this->action( 'cmb2_admin_init', 'steps', 9 );
$this->action( 'cmb2_admin_init', 'register_cmb2' );
$this->action( 'admin_menu', 'add_admin_menu' );
$this->action( 'admin_post_rank_math_save_wizard', 'save_wizard' );
// If the page is not this page stop here.
if ( ! $this->is_current_page() ) {
return;
}
$this->action( 'admin_init', 'admin_page', 30 );
$this->filter( 'user_has_cap', 'filter_user_has_cap' );
$this->filter( 'rank_math/wizard/step/label', 'change_label' );
$this->filter( 'rank_math/wizard/step/label_url', 'change_label_url' );
}
/**
* Setup steps.
*/
public function steps() {
$this->steps = [
'compatibility' => [
'slug' => 'requirements',
'name' => esc_html__( 'Requirements', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Compatibility',
],
'import' => [
'name' => esc_html__( 'Import', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Import',
],
'yoursite' => [
'name' => esc_html__( 'Your Site', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Your_Site',
],
'analytics' => [
'name' => esc_html__( 'Analytics', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Search_Console',
],
'sitemaps' => [
'name' => esc_html__( 'Sitemaps', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Sitemap',
],
'optimization' => [
'name' => esc_html__( 'Optimization', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Optimization',
],
'ready' => [
'name' => esc_html__( 'Ready', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Ready',
],
'role' => [
'slug' => 'rolemanager',
'name' => esc_html__( 'Role Manager', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Role',
],
'redirection' => [
'slug' => '404redirection',
'name' => esc_html__( '404 + Redirection', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Monitor_Redirection',
],
'schema-markup' => [
'name' => esc_html__( 'Schema Markup', 'rank-math' ),
'class' => '\\RankMath\\Wizard\\Schema_Markup',
],
];
if ( ! Helper::is_advanced_mode() ) {
unset( $this->steps['sitemaps'] );
unset( $this->steps['optimization'] );
}
$this->set_current_step();
}
/**
* Register CMB2 option page for setup wizard.
*/
public function register_cmb2() {
$this->cmb = new_cmb2_box(
[
'id' => 'rank-math-wizard',
'object_types' => [ 'options-page' ],
'option_key' => 'rank-math-wizard',
'hookup' => false,
'save_fields' => false,
'classes' => 'wp-core-ui rank-math-ui',
]
);
$this->wizard_step->form( $this );
/**
* Add setting on specific Setup Wizard steps.
*
* The dynamic part of the hook name. $this->step, is the step ID.
*
* @param CMB2 $cmb CMB2 object.
*/
$this->do_action( 'wizard/settings/' . $this->step, $this->cmb );
CMB2::pre_init( $this->cmb );
}
/**
* Change label.
*
* @param string $label Label.
*
* @return string
*/
public function change_label( $label ) {
if ( $this->is_advance() ) {
return esc_html__( 'Advanced Options', 'rank-math' );
}
return $label;
}
/**
* Change label url.
*
* @param string $url Label Url.
*
* @return string
*/
public function change_label_url( $url ) {
if ( $this->is_advance() ) {
return Helper::get_admin_url( 'wizard', 'step=ready' );
}
return $url;
}
/**
* Execute save handler for current step.
*/
public function save_wizard() {
// If no form submission, bail!
$referer = Param::post( '_wp_http_referer' );
if ( empty( $_POST ) ) {
return Helper::redirect( $referer );
}
check_admin_referer( 'rank-math-wizard', 'security' );
if ( ! Helper::has_cap( 'general' ) ) {
return false;
}
$values = $this->cmb->get_sanitized_values( $_POST );
$show_content = $this->wizard_step->save( $values, $this );
$redirect = $show_content ? $this->step_next_link() : $referer;
if ( is_string( $show_content ) ) {
$redirect = $show_content;
}
Helper::redirect( $redirect );
exit;
}
/**
* Add the admin menu item, under Appearance.
*/
public function add_admin_menu() {
if ( Param::get( 'page' ) !== $this->slug ) {
return;
}
$this->hook_suffix = add_submenu_page(
'',
esc_html__( 'Setup Wizard', 'rank-math' ),
esc_html__( 'Setup Wizard', 'rank-math' ),
'manage_options',
$this->slug,
[ $this, 'admin_page' ]
);
}
/**
* Output the admin page.
*/
public function admin_page() {
// Do not proceed if we're not on the right page.
if ( Param::get( 'page' ) !== $this->slug ) {
return;
}
if ( ob_get_length() ) {
ob_end_clean();
}
// Enqueue styles.
\CMB2_Hookup::enqueue_cmb_css();
\CMB2_Hookup::enqueue_cmb_js();
rank_math()->admin_assets->register();
wp_enqueue_style( 'rank-math-wizard', rank_math()->plugin_url() . 'assets/admin/css/setup-wizard.css', [ 'wp-admin', 'buttons', 'cmb2-styles', 'select2-rm', 'rank-math-common', 'rank-math-cmb2' ], rank_math()->version );
// Enqueue scripts for the SEO Score Updater tool.
\RankMath\Tools\Update_Score::get()->enqueue();
// Enqueue javascript.
wp_enqueue_script( 'rank-math-wizard', rank_math()->plugin_url() . 'assets/admin/js/wizard.js', [ 'media-editor', 'select2-rm', 'lodash', 'rank-math-common' ], rank_math()->version, true );
Helper::add_json( 'currentStep', $this->step );
Helper::add_json( 'deactivated', esc_html__( 'Deactivated', 'rank-math' ) );
Helper::add_json( 'confirm', esc_html__( 'Are you sure you want to import settings into Rank Math? Don\'t worry, your current configuration will be saved as a backup.', 'rank-math' ) );
Helper::add_json( 'isConfigured', Helper::is_configured() );
ob_start();
/**
* Start the actual page content.
*/
include_once $this->get_view( 'header' );
include_once $this->get_view( 'content' );
include_once $this->get_view( 'footer' );
exit;
}
/**
* Check if navigation item is hidden or not.
*
* @param string $slug Slug of nav item.
*
* @return bool
*/
public function is_nav_item_hidden( $slug ) {
if ( 'compatibility' === $slug ) {
return true;
}
$is_advanced = $this->is_advance();
$advance_steps = [ 'role', 'redirection', 'schema-markup' ];
return in_array( $slug, $advance_steps, true ) ? ! $is_advanced : $is_advanced;
}
/**
* Get view file to display.
*
* @param string $view View to display.
* @return string
*/
public function get_view( $view ) {
return rank_math()->admin_dir() . "wizard/views/{$view}.php";
}
/**
* Get the step URL.
*
* @param string $step Name of the step, appended to the URL.
*/
public function get_step_link( $step ) {
return Security::add_query_arg( 'step', $step );
}
/**
* Get Skip Link.
*/
public function get_skip_link() {
?>
<a href="<?php echo esc_url( $this->step_next_link() ); ?>" class="button button-secondary button-skip"><?php esc_html_e( 'Skip Step', 'rank-math' ); ?></a>
<?php
}
/**
* Set current step.
*/
private function set_current_step() {
if ( $this->maybe_remove_import() ) {
unset( $this->steps['import'] );
}
$this->steps = $this->do_filter( 'wizard/steps', $this->steps );
$this->step = Param::request( 'step', current( array_keys( $this->steps ) ) );
$this->step_slug = isset( $this->steps[ $this->step ]['slug'] ) ? $this->steps[ $this->step ]['slug'] : $this->step;
$this->wizard_step = new $this->steps[ $this->step ]['class']();
}
/**
* Checks if current step is advanced.
*
* @return bool
*/
private function is_advance() {
$step = Param::request( 'step' );
return $step && in_array( $step, [ 'role', 'redirection', 'schema-markup' ], true );
}
/**
* Maybe remove import step.
*
* @return bool
*/
private function maybe_remove_import() {
$pre = $this->do_filter( 'wizard/pre_remove_import_step', null );
if ( ! is_null( $pre ) ) {
return $pre;
}
if ( false === get_option( 'rank_math_is_configured' ) ) {
$detector = new Detector();
$plugins = $detector->detect();
if ( ! empty( $plugins ) ) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* The clauses functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Clauses class.
*/
trait Clauses {
/**
* List of SQL clauses.
*
* @var array
*/
private $sql_clauses = [];
/**
* SQL clause merge filters.
*
* @var array
*/
private $sql_filters = [
'where' => [
'where',
'where_time',
],
'join' => [
'right_join',
'join',
'left_join',
],
];
/**
* Check has SQL clause.
*
* @param string $type Clause type.
*
* @return boolean True if set and not empty.
*/
public function has_sql_clause( $type ) {
return isset( $this->sql_clauses[ $type ] ) && ! empty( $this->sql_clauses[ $type ] );
}
/**
* Add a SQL clause to be included when get_data is called.
*
* @param string $type Clause type.
* @param string $clause SQL clause.
*/
public function add_sql_clause( $type, $clause ) {
if ( isset( $this->sql_clauses[ $type ] ) && ! empty( $clause ) ) {
$this->sql_clauses[ $type ][] = $clause;
}
}
/**
* Clear SQL clauses by type.
*
* @param string|array $types Clause type.
*/
protected function clear_sql_clause( $types ) {
foreach ( (array) $types as $type ) {
if ( isset( $this->sql_clauses[ $type ] ) ) {
$this->sql_clauses[ $type ] = [];
}
}
}
/**
* Get SQL clause by type.
*
* @param string $type Clause type.
* @param string $filtered Whether to filter the return value. Default unfiltered.
*
* @return string SQL clause.
*/
protected function get_sql_clause( $type, $filtered = false ) {
if ( ! isset( $this->sql_clauses[ $type ] ) ) {
return '';
}
$separator = ' ';
if ( in_array( $type, [ 'select', 'order_by', 'group_by' ], true ) ) {
$separator = ', ';
}
/**
* Default to bypassing filters for clause retrieval internal to data stores.
* The filters are applied when the full SQL statement is retrieved.
*/
if ( false === $filtered ) {
return implode( $separator, $this->sql_clauses[ $type ] );
}
if ( isset( $this->sql_filters[ $type ] ) ) {
$clauses = [];
foreach ( $this->sql_filters[ $type ] as $subset ) {
$clauses = array_merge( $clauses, $this->sql_clauses[ $subset ] );
}
} else {
$clauses = $this->sql_clauses[ $type ];
}
/**
* Filter SQL clauses by type and context.
*
* @param array $clauses The original arguments for the request.
* @param string $context The data store context.
*/
$clauses = apply_filters( "rank_math_clauses_{$type}", $clauses, $this->context );
/**
* Filter SQL clauses by type and context.
*
* @param array $clauses The original arguments for the request.
*/
$clauses = apply_filters( "rank_math_clauses_{$type}_{$this->context}", $clauses );
return implode( $separator, $clauses );
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* The Database.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Database class.
*/
class Database {
/**
* Array of all databases objects.
*
* @var array
*/
protected static $instances = [];
/**
* Retrieve a Database instance by table name.
*
* @param string $table_name A Database instance id.
*
* @return Database Database object instance.
*/
public static function table( $table_name ) {
global $wpdb;
if ( empty( self::$instances ) || empty( self::$instances[ $table_name ] ) ) {
self::$instances[ $table_name ] = new Query_Builder( $wpdb->prefix . $table_name );
}
return self::$instances[ $table_name ];
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* The escape functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Escape class.
*/
trait Escape {
/**
* Escape array values for sql
*
* @param array $arr Array to escape.
*
* @return array
*/
public function esc_array( $arr ) {
return array_map( [ $this, 'esc_value' ], $arr );
}
/**
* Escape value for sql
*
* @param mixed $value Value to escape.
*
* @return mixed
*/
public function esc_value( $value ) {
global $wpdb;
if ( is_int( $value ) ) {
return $wpdb->prepare( '%d', $value );
}
if ( is_float( $value ) ) {
return $wpdb->prepare( '%f', $value );
}
return 'NULL' === $value ? $value : $wpdb->prepare( '%s', $value );
}
/**
* Escape value for like statement
*
* @codeCoverageIgnore
*
* @param string $value Value for like statement.
* @param string $start (Optional) The start of like query.
* @param string $end (Optional) The end of like query.
*
* @return string
*/
public function esc_like( $value, $start = '%', $end = '%' ) {
global $wpdb;
return $start . $wpdb->esc_like( $value ) . $end;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* The groupby functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* GroupBy class.
*/
trait GroupBy {
/**
* Add an group by statement to the current query
*
* ->groupBy('created_at')
*
* @param array|string $columns Columns.
*
* @return self The current query builder.
*/
public function groupBy( $columns ) { // @codingStandardsIgnoreLine
if ( is_string( $columns ) ) {
$columns = $this->argument_to_array( $columns );
}
foreach ( $columns as $column ) {
$this->add_sql_clause( 'group_by', $column );
}
return $this;
}
/**
* Generate Having clause
*
* @param string $column The SQL column.
* @param mixed $param1 Operator or value depending if $param2 isset.
* @param mixed $param2 The value if $param1 is an operator.
*
* @return self The current query builder.
*/
public function having( $column, $param1 = null, $param2 = null ) {
$this->add_sql_clause( 'having', $this->generateWhere( $column, $param1, $param2, 'HAVING' ) );
return $this;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* The joins functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Joins class.
*/
trait Joins {
/**
* Generate left join clause.
*
* @param string $table The SQL table.
* @param mixed $column1 The SQL Column.
* @param mixed $column2 The SQL Column.
* @param string $operator The Operator.
* @param string $alias The table alias.
*
* @return self The current query builder.
*/
public function leftJoin( $table, $column1, $column2, $operator = '=', $alias = '' ) { // @codingStandardsIgnoreLine
if ( empty( $table ) || empty( $column1 ) || empty( $column2 ) ) {
return $this;
}
if ( ! empty( $alias ) ) {
$table = "{$table} AS {$alias}";
}
$this->add_sql_clause( 'left_join', "LEFT JOIN {$table} ON {$column1} {$operator} {$column2}" );
return $this;
}
/**
* Generate right join clause.
*
* @param string $table The SQL table.
* @param mixed $column1 The SQL Column.
* @param mixed $column2 The SQL Column.
* @param string $operator The Operator.
* @param string $alias The table alias.
*
* @return self The current query builder.
*/
public function rightJoin( $table, $column1, $column2, $operator = '=', $alias = '' ) { // @codingStandardsIgnoreLine
if ( empty( $table ) || empty( $column1 ) || empty( $column2 ) ) {
return $this;
}
if ( ! empty( $alias ) ) {
$table = "{$table} AS {$alias}";
}
$this->add_sql_clause( 'right_join', "RIGHT JOIN {$table} ON {$column1} {$operator} {$column2}" );
return $this;
}
/**
* Generate left join clause.
*
* @param string $table The SQL table.
* @param mixed $column1 The SQL Column.
* @param mixed $column2 The SQL Column.
* @param string $operator The Operator.
* @param string $alias The table alias.
*
* @return self The current query builder.
*/
public function join( $table, $column1, $column2, $operator = '=', $alias = '' ) { // @codingStandardsIgnoreLine
if ( empty( $table ) || empty( $column1 ) || empty( $column2 ) ) {
return $this;
}
if ( ! empty( $alias ) ) {
$table = "{$table} AS {$alias}";
}
$this->add_sql_clause( 'join', "JOIN {$table} ON {$column1} {$operator} {$column2}" );
return $this;
}
}

View File

@@ -0,0 +1,86 @@
<?php
/**
* The orderby functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
use RankMath\Helpers\Arr;
/**
* OrderBy class.
*/
trait OrderBy {
/**
* Add an order by statement to the current query
*
* ->orderBy('created_at')
* ->orderBy('modified_at', 'desc')
*
* // multiple order clauses
* ->orderBy(['firstname', 'lastname'], 'desc')
*
* // muliple order clauses with diffrent directions
* ->orderBy(['firstname' => 'asc', 'lastname' => 'desc'])
*
* @param array|string $columns Columns.
* @param string $direction Direction.
*
* @return self The current query builder.
*/
public function orderBy( $columns, $direction = 'ASC' ) { // @codingStandardsIgnoreLine
if ( is_string( $columns ) ) {
$columns = $this->argument_to_array( $columns );
}
$direction = $this->sanitize_direction( $direction );
foreach ( $columns as $key => $column ) {
if ( is_numeric( $key ) ) {
$this->add_sql_clause( 'order_by', "{$column}{$direction}" );
continue;
}
$column = $this->sanitize_direction( $column );
$this->add_sql_clause( 'order_by', "{$key}{$column}" );
}
return $this;
}
/**
* Sanitize direction
*
* @param string $direction Value to sanitize.
*
* @return string Sanitized value
*/
protected function sanitize_direction( $direction ) {
if ( empty( $direction ) || 'ASC' === $direction || 'asc' === $direction ) {
return '';
}
return ' ' . \strtoupper( $direction );
}
/**
* Returns an string argument as parsed array if possible
*
* @param string $argument Argument to validate.
*
* @return array
*/
protected function argument_to_array( $argument ) {
if ( false !== strpos( $argument, ',' ) ) {
return Arr::from_string( $argument );
}
return [ $argument ];
}
}

View File

@@ -0,0 +1,288 @@
<?php
/**
* The Query Builder.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Query_Builder class.
*/
class Query_Builder {
use Escape;
use Select;
use Where;
use Joins;
use GroupBy;
use OrderBy;
use Clauses;
use Translate;
/**
* Table name.
*
* @var string
*/
public $table = '';
/**
* Save last query.
*
* @var string
*/
public $last_query = '';
/**
* Make a distinct selection
*
* @var bool
*/
protected $distinct = false;
/**
* Make SQL_CALC_FOUND_ROWS in selection
*
* @var bool
*/
protected $found_rows = false;
/**
* Data store context used to pass to filters.
*
* @var string
*/
protected $context;
/**
* Constructor
*
* @param string $table The table name.
* @param string $context Optional context passed to filters. Default empty string.
*/
public function __construct( $table, $context = '' ) {
$this->table = $table;
$this->context = $context;
$this->reset();
}
/**
* Translate the given query object and return the results
*
* @param string $output (Optional) Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
*
* @return mixed
*/
public function get( $output = \OBJECT ) {
global $wpdb;
$this->last_query = $this->translateSelect();
$this->reset();
return $wpdb->get_results( $this->last_query, $output ); // phpcs:ignore
}
/**
* Translate the given query object and return the results
*
* @param string $output (Optional) Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
*
* @return mixed
*/
public function one( $output = \OBJECT ) {
global $wpdb;
$this->limit( 1 );
$this->last_query = $this->translateSelect();
$this->reset();
return $wpdb->get_row( $this->last_query, $output ); // phpcs:ignore
}
/**
* Translate the given query object and return one variable from the database
*
* @return mixed
*/
public function getVar() { // @codingStandardsIgnoreLine
$row = $this->one( \ARRAY_A );
return is_null( $row ) ? false : current( $row );
}
/**
* Insert a row into a table
*
* @codeCoverageIgnore
* @see wpdb::insert()
*
* @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
* @param array $format (Optional) An array of formats to be mapped to each of the value in $data.
*
* @return mixed
*/
public function insert( $data, $format = null ) {
global $wpdb;
$wpdb->insert( $this->table, $data, $format );
return $wpdb->insert_id;
}
/**
* Update a row into a table
*
* @codeCoverageIgnore
*
* @return mixed
*/
public function update() {
$query = $this->translateUpdate();
$this->reset();
return $this->query( $query );
}
/**
* Delete data from table
*
* @codeCoverageIgnore
*
* @return mixed
*/
public function delete() {
$query = $this->translateDelete();
$this->reset();
return $this->query( $query );
}
/**
* Truncate table.
*
* @codeCoverageIgnore
*
* @return mixed
*/
public function truncate() {
return $this->query( "truncate table {$this->table};" );
}
/**
* Get found rows.
*
* @return int
*/
public function get_found_rows() {
global $wpdb;
return $wpdb->get_var( 'SELECT FOUND_ROWS();' );
}
/**
* Perform a MySQL database query, using current database connection.
*
* @codeCoverageIgnore
*
* @see wpdb::query
*
* @param string $query Database query.
*
* @return int|false Number of rows affected|selected or false on error.
*/
public function query( $query ) {
global $wpdb;
$this->last_query = $query;
return $wpdb->query( $query ); // phpcs:ignore
}
/**
* Set the limit clause.
*
* @param int $limit Limit size.
* @param int $offset Offeset.
*
* @return self The current query builder.
*/
public function limit( $limit, $offset = 0 ) {
global $wpdb;
$limit = \absint( $limit );
$offset = \absint( $offset );
$this->clear_sql_clause( 'limit' );
$this->add_sql_clause( 'limit', $wpdb->prepare( 'LIMIT %d, %d', $offset, $limit ) );
return $this;
}
/**
* Create an query limit based on a page and a page size
*
* @param int $page Page number.
* @param int $size Page size.
*
* @return self The current query builder.
*/
public function page( $page, $size = 25 ) {
$size = \absint( $size );
$offset = $size * \absint( $page );
$this->limit( $size, $offset );
return $this;
}
/**
* Set values for insert/update
*
* @param string|array $name Key of pair.
* @param string|array $value Value of pair.
*
* @return self The current query builder.
*/
public function set( $name, $value = null ) {
if ( is_array( $name ) ) {
$this->sql_clauses['values'] = $this->sql_clauses['values'] + $name;
return $this;
}
$this->sql_clauses['values'][ $name ] = $value;
return $this;
}
/**
* Reset all vaiables.
*
* @return self The current query builder.
*/
private function reset() {
$this->distinct = false;
$this->found_rows = false;
$this->sql_clauses = [
'select' => [],
'from' => [],
'left_join' => [],
'join' => [],
'right_join' => [],
'where' => [],
'where_time' => [],
'group_by' => [],
'having' => [],
'limit' => [],
'order_by' => [],
'values' => [],
];
return $this;
}
}

View File

@@ -0,0 +1,131 @@
<?php
/**
* The select functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Select class.
*/
trait Select {
/**
* Set the selected fields
*
* @param array $fields Fields to select.
*
* @return self The current query builder.
*/
public function select( $fields = '' ) {
if ( empty( $fields ) ) {
return $this;
}
if ( is_string( $fields ) ) {
$this->add_sql_clause( 'select', $fields );
return $this;
}
foreach ( $fields as $key => $field ) {
$this->add_sql_clause( 'select', is_string( $key ) ? "$key AS $field" : $field );
}
return $this;
}
/**
* Shortcut to add a count function
*
* ->selectCount('id')
* ->selectCount('id', 'count')
*
* @param string $field Column name.
* @param string $alias (Optional) Column alias.
*
* @return self The current query builder.
*/
public function selectCount( $field = '*', $alias = null ) { // @codingStandardsIgnoreLine
return $this->selectFunc( 'count', $field, $alias );
}
/**
* Shortcut to add a sum function
*
* ->selectSum('id')
* ->selectSum('id', 'total')
*
* @param string $field Column name.
* @param string $alias (Optional) Column alias.
*
* @return self The current query builder.
*/
public function selectSum( $field, $alias = null ) { // @codingStandardsIgnoreLine
return $this->selectFunc( 'sum', $field, $alias );
}
/**
* Shortcut to add a avg function
*
* ->selectAvg('id')
* ->selectAvg('id', 'average')
*
* @param string $field Column name.
* @param string $alias (Optional) Column alias.
*
* @return self The current query builder.
*/
public function selectAvg( $field, $alias = null ) { // @codingStandardsIgnoreLine
return $this->selectFunc( 'avg', $field, $alias );
}
/**
* Shortcut to add a function
*
* @param string $func Function name.
* @param string $field Column name.
* @param string $alias (Optional) Column alias.
*
* @return self The current query builder.
*/
public function selectFunc( $func, $field, $alias = null ) { // @codingStandardsIgnoreLine
$func = \strtoupper( $func );
$field = "$func({$field})";
if ( ! is_null( $alias ) ) {
$field .= " AS {$alias}";
}
$this->add_sql_clause( 'select', $field );
return $this;
}
/**
* Distinct select setter
*
* @param bool $distinct Is disticnt.
*
* @return self The current query builder.
*/
public function distinct( $distinct = true ) {
$this->distinct = $distinct;
return $this;
}
/**
* SQL_CALC_FOUND_ROWS select setter
*
* @param bool $found_rows Should get found rows.
*
* @return self The current query builder.
*/
public function found_rows( $found_rows = true ) {
$this->found_rows = $found_rows;
return $this;
}
}

View File

@@ -0,0 +1,136 @@
<?php
/**
* The translate functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Translate class.
*/
trait Translate {
/**
* Translate the current query to an SQL select statement
*
* @return string
*/
private function translateSelect() { // @codingStandardsIgnoreLine
$query = [ 'SELECT' ];
if ( $this->found_rows ) {
$query[] = 'SQL_CALC_FOUND_ROWS';
}
if ( $this->distinct ) {
$query[] = 'DISTINCT';
}
$query[] = $this->has_sql_clause( 'select' ) ? $this->get_sql_clause( 'select', true ) : '*';
$query[] = $this->translateFrom();
$query[] = $this->get_sql_clause( 'join', true );
$query[] = $this->get_sql_clause( 'where', true );
$query[] = $this->translateGroupBy();
$query[] = $this->translateOrderBy();
$query[] = $this->translateLimit();
return join( ' ', array_filter( $query ) );
}
/**
* Translate the current query to an SQL update statement
*
* @return string
*/
private function translateUpdate() { // @codingStandardsIgnoreLine
$query = [ "UPDATE {$this->table} SET" ];
// Add the values.
$values = [];
foreach ( $this->sql_clauses['values'] as $key => $value ) {
$values[] = $key . ' = ' . $this->esc_value( $value );
}
if ( ! empty( $values ) ) {
$query[] = join( ', ', $values );
}
$query[] = $this->get_sql_clause( 'where', true );
$query[] = $this->translateLimit();
return join( ' ', array_filter( $query ) );
}
/**
* Translate the current query to an SQL delete statement
*
* @return string
*/
private function translateDelete() { // @codingStandardsIgnoreLine
$query = [ 'DELETE' ];
$query[] = $this->translateFrom();
$query[] = $this->get_sql_clause( 'where', true );
$query[] = $this->translateLimit();
return join( ' ', array_filter( $query ) );
}
/**
* Build the from statement.
*
* @return string
*/
private function translateFrom() { // @codingStandardsIgnoreLine
if ( ! $this->has_sql_clause( 'from' ) ) {
$this->add_sql_clause( 'from', $this->table );
}
return 'FROM ' . $this->get_sql_clause( 'from', true );
}
/**
* Build the order by statement
*
* @return string
*/
protected function translateOrderBy() { // @codingStandardsIgnoreLine
if ( ! $this->has_sql_clause( 'order_by' ) ) {
return '';
}
return 'ORDER BY ' . $this->get_sql_clause( 'order_by', true );
}
/**
* Build the group by clauses.
*
* @return string
*/
private function translateGroupBy() { // @codingStandardsIgnoreLine
if ( ! $this->has_sql_clause( 'group_by' ) ) {
return '';
}
$group_by = 'GROUP BY ' . $this->get_sql_clause( 'group_by', true );
if ( $this->has_sql_clause( 'having' ) ) {
$group_by .= ' ' . $this->get_sql_clause( 'having', true );
}
return $group_by;
}
/**
* Build offset and limit.
*
* @return string
*/
private function translateLimit() { // @codingStandardsIgnoreLine
return $this->get_sql_clause( 'limit', true );
}
}

View File

@@ -0,0 +1,366 @@
<?php
/**
* The where functions.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath\Admin\Database
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Database;
/**
* Where class.
*/
trait Where {
/**
* Create a where statement
*
* ->where('name', 'ladina')
* ->where('age', '>', 18)
* ->where('name', 'in', ['charles', 'john', 'jeffry'])
*
* @throws \Exception If $type is not 'AND', 'OR', 'WHERE'.
*
* @param mixed $column The SQL column.
* @param mixed $param1 Operator or value depending if $param2 isset.
* @param mixed $param2 The value if $param1 is an operator.
* @param string $type the where type ( AND, OR ).
*
* @return self The current query builder.
*/
public function where( $column, $param1 = null, $param2 = null, $type = 'AND' ) {
$this->is_valid_type( $type );
$sub_type = is_null( $param1 ) ? $type : $param1;
if ( ! $this->has_sql_clause( 'where' ) ) {
$type = 'WHERE';
}
// When column is an array we assume to make a bulk and where.
if ( is_array( $column ) ) {
$this->bulk_where( $column, $type, $sub_type );
return $this;
}
$this->add_sql_clause( 'where', $this->generateWhere( $column, $param1, $param2, $type ) );
return $this;
}
/**
* Create an or where statement
*
* @param string $column The SQL column.
* @param mixed $param1 Operator or value depending if $param2 isset.
* @param mixed $param2 The value if $param1 is an operator.
*
* @return self The current query builder.
*/
public function orWhere( $column, $param1 = null, $param2 = null ) { // @codingStandardsIgnoreLine
return $this->where( $column, $param1, $param2, 'OR' );
}
/**
* Creates a where in statement
*
* ->whereIn('id', [42, 38, 12])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function whereIn( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'IN', $options );
}
/**
* Creates a where in statement
*
* ->orWhereIn('id', [42, 38, 12])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function orWhereIn( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'IN', $options, 'OR' );
}
/**
* Creates a where not in statement
*
* ->whereNotIn('id', [42, 38, 12])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function whereNotIn( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'NOT IN', $options );
}
/**
* Creates a where not in statement
*
* ->orWhereNotIn('id', [42, 38, 12])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function orWhereNotIn( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'NOT IN', $options, 'OR' );
}
/**
* Creates a where between statement
*
* ->whereBetween('id', [10, 100])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function whereBetween( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'BETWEEN', $options );
}
/**
* Creates a where between statement
*
* ->orWhereBetween('id', [10, 100])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function orWhereBetween( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'BETWEEN', $options, 'OR' );
}
/**
* Creates a where not between statement
*
* ->whereNotBetween('id', [10, 100])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function whereNotBetween( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'NOT BETWEEN', $options );
}
/**
* Creates a where not between statement
*
* ->orWhereNotBetween('id', [10, 100])
*
* @param string $column The SQL column.
* @param array $options Array of values for in statement.
*
* @return self The current query builder.
*/
public function orWhereNotBetween( $column, $options ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'NOT BETWEEN', $options, 'OR' );
}
/**
* Creates a where like statement
*
* ->whereLike('id', 'value')
*
* @codeCoverageIgnore
*
* @param string $column The SQL column.
* @param string $value Value for like statement.
* @param string $start (Optional) The start of like query.
* @param string $end (Optional) The end of like query.
*
* @return self The current query builder.
*/
public function whereLike( $column, $value, $start = '%', $end = '%' ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'LIKE', $this->esc_like( $value, $start, $end ) );
}
/**
* Creates a where like statement
*
* ->orWhereLike('id', 'value')
*
* @codeCoverageIgnore
*
* @param string $column The SQL column.
* @param string $value Value for like statement.
* @param string $start (Optional) The start of like query.
* @param string $end (Optional) The end of like query.
*
* @return self The current query builder.
*/
public function orWhereLike( $column, $value, $start = '%', $end = '%' ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'LIKE', $this->esc_like( $value, $start, $end ), 'OR' );
}
/**
* Creates a where not like statement
*
* ->whereNotLike('id', 'value' )
*
* @codeCoverageIgnore
*
* @param string $column The SQL column.
* @param mixed $value Value for like statement.
* @param string $start (Optional) The start of like query.
* @param string $end (Optional) The end of like query.
*
* @return self The current query builder.
*/
public function whereNotLike( $column, $value, $start = '%', $end = '%' ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'NOT LIKE', $this->esc_like( $value, $start, $end ) );
}
/**
* Creates a where not like statement
*
* ->orWhereNotLike('id', 'value' )
*
* @codeCoverageIgnore
*
* @param string $column The SQL column.
* @param mixed $value Value for like statement.
* @param string $start (Optional) The start of like query.
* @param string $end (Optional) The end of like query.
*
* @return self The current query builder.
*/
public function orWhereNotLike( $column, $value, $start = '%', $end = '%' ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'NOT LIKE', $this->esc_like( $value, $start, $end ), 'OR' );
}
/**
* Creates a where is null statement
*
* ->whereNull( 'name' )
*
* @param string $column The SQL column.
*
* @return self The current query builder.
*/
public function whereNull( $column ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'IS', 'NULL' );
}
/**
* Creates a where is null statement
*
* ->orWhereNull( 'name' )
*
* @param string $column The SQL column.
*
* @return self The current query builder.
*/
public function orWhereNull( $column ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'IS', 'NULL', 'OR' );
}
/**
* Creates a where is not null statement
*
* ->whereNotNull( 'name' )
*
* @param string $column The SQL column.
*
* @return self The current query builder.
*/
public function whereNotNull( $column ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'IS NOT', 'NULL' );
}
/**
* Creates a where is not null statement
*
* ->orWhereNotNull( 'name' )
*
* @param string $column The SQL column.
*
* @return self The current query builder.
*/
public function orWhereNotNull( $column ) { // @codingStandardsIgnoreLine
return $this->where( $column, 'IS NOT', 'NULL', 'OR' );
}
/**
* Generate Where clause
*
* @param string $column The SQL column.
* @param mixed $param1 Operator or value depending if $param2 isset.
* @param mixed $param2 The value if $param1 is an operator.
* @param string $type the where type ( AND, or ).
*
* @return string
*/
protected function generateWhere( $column, $param1 = null, $param2 = null, $type = 'AND' ) { // @codingStandardsIgnoreLine
// when param2 is null we replace param2 with param one as the
// value holder and make param1 to the = operator.
if ( is_null( $param2 ) ) {
$param2 = $param1;
$param1 = '=';
}
// When param2 is an array we probably
// have an "in" or "between" statement which has no need for duplicates.
if ( is_array( $param2 ) ) {
$param2 = $this->esc_array( array_unique( $param2 ) );
$param2 = in_array( $param1, [ 'BETWEEN', 'NOT BETWEEN' ], true ) ? join( ' AND ', $param2 ) : '(' . join( ', ', $param2 ) . ')';
} elseif ( is_scalar( $param2 ) ) {
$param2 = $this->esc_value( $param2 );
}
return join( ' ', [ $type, $column, $param1, $param2 ] );
}
/**
* Check if the where type is valid.
*
* @param string $type Value to check.
*
* @throws \Exception If not a valid type.
*/
private function is_valid_type( $type ) {
if ( ! in_array( $type, [ 'AND', 'OR', 'WHERE' ], true ) ) {
throw new \Exception( 'Invalid where type "' . $type . '"' );
}
}
/**
* Create bulk where statement.
*
* @param array $where Array of statments.
* @param string $type Statement type.
* @param string $sub_type Statement sub-type.
*/
private function bulk_where( $where, $type, $sub_type ) {
$subquery = [];
foreach ( $where as $value ) {
if ( ! isset( $value[2] ) ) {
$value[2] = $value[1];
$value[1] = '=';
}
$subquery[] = $this->generateWhere( $value[0], $value[1], $value[2], empty( $subquery ) ? '' : $sub_type );
}
$this->add_sql_clause( 'where', $type . ' ( ' . trim( join( ' ', $subquery ) ) . ' )' );
}
}

View File

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

View File

@@ -0,0 +1,584 @@
<?php
/**
* The abstract class for plugins import to inherit from
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin\Importers
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Importers;
use Exception;
use RankMath\Helper;
use RankMath\Traits\Ajax;
use RankMath\Traits\Meta;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\DB;
use RankMath\Helpers\Param;
use RankMath\Helpers\Attachment;
defined( 'ABSPATH' ) || exit;
/**
* Plugin_Importer class.
*/
abstract class Plugin_Importer {
use Hooker, Ajax, Meta;
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name;
/**
* The plugin file.
*
* @var string
*/
protected $plugin_file;
/**
* Plugin options meta key.
*
* @var string
*/
protected $meta_key;
/**
* Option keys to import and clean.
*
* @var array
*/
protected $option_keys;
/**
* Table names to drop while cleaning.
*
* @var array
*/
protected $table_names;
/**
* Choices keys to import.
*
* @var array
*/
protected $choices;
/**
* Number of items to parse per page.
*
* @var int
*/
protected $items_per_page = 100;
/**
* Pagination arguments.
*
* @var array
*/
protected $_pagination_args = [];
/**
* General settings.
*
* @var array
*/
protected $settings;
/**
* Titles settings.
*
* @var array
*/
protected $titles;
/**
* Sitemap settings.
*
* @var array
*/
protected $sitemap;
/**
* Class constructor.
*
* @param string $plugin_file Plugins file.
*/
public function __construct( $plugin_file ) {
$this->plugin_file = $plugin_file;
}
/**
* Get the name of the plugin we're importing from.
*
* @return string Plugin name.
*/
public function get_plugin_name() {
return $this->plugin_name;
}
/**
* Get the plugin file of the plugin we're importing from.
*
* @return string Plugin file
*/
public function get_plugin_file() {
return $this->plugin_file;
}
/**
* Get the actions which can be performed for the plugin.
*
* @return array
*/
public function get_choices() {
if ( empty( $this->choices ) ) {
return [];
}
return array_intersect_key(
[
'settings' => esc_html__( 'Import Settings', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import plugin settings, global meta, sitemap settings, etc.', 'rank-math' ) ),
'postmeta' => esc_html__( 'Import Post Meta', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import meta information of your posts/pages like the focus keyword, titles, descriptions, robots meta, OpenGraph info, etc.', 'rank-math' ) ),
'termmeta' => esc_html__( 'Import Term Meta', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import data like category, tag, and CPT meta data from SEO.', 'rank-math' ) ),
'usermeta' => esc_html__( 'Import Author Meta', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import meta information like titles, descriptions, focus keyword, robots meta, etc., of your author archive pages.', 'rank-math' ) ),
'redirections' => esc_html__( 'Import Redirections', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import all the redirections you have already set up in Yoast Premium.', 'rank-math' ) ),
'blocks' => esc_html__( 'Import Blocks', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import and convert all compatible blocks in post contents.', 'rank-math' ) ),
'locations' => esc_html__( 'Import Locations', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import Locations Settings from Yoast plugin.', 'rank-math' ) ),
'news' => esc_html__( 'Import News Settings', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import News Settings from Yoast News Add-on.', 'rank-math' ) ),
'video' => esc_html__( 'Import Video Sitemap Settings', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import Video Sitemap Settings from Yoast Video Add-on.', 'rank-math' ) ),
],
array_combine(
$this->choices,
$this->choices
)
);
}
/**
* Check if import is needed from this plugin.
*
* @return bool Whether there is something to import.
*/
public function run_detect() {
return true === $this->has_options() ? true : $this->has_postmeta();
}
/**
* Delete all plugin data from the database.
*
* @return bool
*/
public function run_cleanup() {
if ( ! $this->run_detect() ) {
return false;
}
$result = $this->drop_custom_tables();
$result = $this->clean_meta_table();
$result = $this->clean_options();
return $result;
}
/**
* Run importer.
*
* @throws Exception Throws error if no perform function founds.
*
* @param string $perform The action to perform when running import action.
*/
public function run_import( $perform ) {
if ( ! method_exists( $this, $perform ) ) {
throw new Exception( esc_html__( 'Unable to perform action this time.', 'rank-math' ) );
}
/**
* Number of items to import per run.
*
* @param int $items_per_page Default 100.
*/
$this->items_per_page = absint( $this->do_filter( 'importers/items_per_page', 100 ) );
$status = new Status();
$result = $this->$perform();
$is_success = is_array( $result ) || true === $result;
$status->set_action( $perform );
$status->set_status( $is_success );
$message = $this->format_message( $result, $perform, $status->get_message() );
if ( is_scalar( $result ) ) {
$result = [];
}
if ( $is_success ) {
$result['message'] = $message;
$this->success( $result );
}
$result['error'] = $message;
$this->error( $result );
}
/**
* Get success message.
*
* @param array $result Array of result.
* @param string $action Action performed.
* @param string $message Message to format.
*
* @return mixed
*/
private function format_message( $result, $action, $message ) {
if ( 'blocks' === $action || 'recalculate' === $action ) {
return is_array( $result ) ? sprintf( $message, $result['start'], $result['end'], $result['total_items'] ) : $result;
}
if ( 'postmeta' === $action || 'usermeta' === $action ) {
return sprintf( $message, $result['start'], $result['end'], $result['total_items'] );
}
if ( 'termmeta' === $action || 'redirections' === $action ) {
return sprintf( $message, $result['count'] );
}
return $message;
}
/**
* Deactivate plugin action.
*/
protected function deactivate() {
if ( is_plugin_active( $this->get_plugin_file() ) ) {
deactivate_plugins( $this->get_plugin_file() );
}
return true;
}
/**
* Replace settings based on key/value hash.
*
* @param array $hash Array of hash for search and replace.
* @param array $source Array for source where to search.
* @param array $destination Array for destination where to save.
* @param bool $convert (Optional) Conversion type. Default: false.
*/
protected function replace( $hash, $source, &$destination, $convert = false ) {
foreach ( $hash as $search => $replace ) {
if ( ! isset( $source[ $search ] ) ) {
continue;
}
$destination[ $replace ] = false === $convert ? $source[ $search ] : $this->$convert( $source[ $search ] );
}
}
/**
* Replace meta based on key/value hash.
*
* @param array $hash Array of hash for search and replace.
* @param array $source Array for source where to search.
* @param int $object_id Object id for destination where to save.
* @param string $object_type Object type for destination where to save.
* @param bool $convert (Optional) Conversion type. Default: false.
*/
protected function replace_meta( $hash, $source, $object_id, $object_type, $convert = false ) {
foreach ( $hash as $search => $replace ) {
$value = ! empty( $source[ $search ] ) ? $source[ $search ] : $this->get_meta( $object_type, $object_id, $search );
if ( empty( $value ) ) {
continue;
}
$this->update_meta(
$object_type,
$object_id,
$replace,
false !== $convert ? $this->$convert( $value ) : $value
);
}
}
/**
* Replace an image to its URL and ID.
*
* @param string $source Source image url.
* @param array|callable $destination Destination array.
* @param string $image Image field key to save url.
* @param string $image_id Image id field key to save id.
* @param int $object_id Object ID either post ID, term ID or user ID.
*/
protected function replace_image( $source, $destination, $image, $image_id, $object_id = null ) {
if ( empty( $source ) ) {
return;
}
$attachment_id = Attachment::get_by_url( $source );
if ( 1 > $attachment_id ) {
return;
}
if ( is_null( $object_id ) ) {
$destination[ $image ] = $source;
$destination[ $image_id ] = $attachment_id;
return;
}
$this->update_meta( $destination, $object_id, $image, $source );
$this->update_meta( $destination, $object_id, $image_id, $attachment_id );
}
/**
* Convert bool value to switch.
*
* @param mixed $value Value to convert.
* @return string
*/
protected function convert_bool( $value ) {
if ( true === boolval( $value ) ) {
return 'on';
}
if ( false === boolval( $value ) ) {
return 'off';
}
return $value;
}
/**
* Set variable that twitter is using facebook data or not.
*
* @param string $object_type Object type for destination where to save.
* @param int $object_id Object id for destination where to save.
*/
protected function is_twitter_using_facebook( $object_type, $object_id ) {
$keys = [
'rank_math_twitter_title',
'rank_math_twitter_description',
'rank_math_twitter_image',
];
foreach ( $keys as $key ) {
if ( ! empty( $this->get_meta( $object_type, $object_id, $key, true ) ) ) {
$this->update_meta( $object_type, $object_id, 'rank_math_twitter_use_facebook', 'off' );
break;
}
}
}
/**
* Convert Yoast / AIO SEO variables if needed.
*
* @param string $string Value to convert.
* @return string
*/
protected function convert_variables( $string ) {
return str_replace( '%%', '%', $string );
}
/**
* Set pagination arguments.
*
* @param int $total_items Number of total items to set pagination.
*/
protected function set_pagination( $total_items = 0 ) {
$args = [
'total_pages' => 0,
'total_items' => $total_items,
'per_page' => $this->items_per_page,
];
// Total Pages.
if ( ! $args['total_pages'] && $args['per_page'] > 0 ) {
$args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
}
// Current Page.
$pagenum = Param::request( 'paged', 0, FILTER_VALIDATE_INT );
if ( isset( $args['total_pages'] ) && $pagenum > $args['total_pages'] ) {
$pagenum = $args['total_pages'];
}
$args['page'] = max( 1, $pagenum );
// Start n End.
$args['start'] = ( ( $args['page'] - 1 ) * $this->items_per_page ) + 1;
$args['end'] = min( $args['page'] * $this->items_per_page, $total_items );
$this->_pagination_args = $args;
}
/**
* Get pagination arguments.
*
* @param bool $key If any specific data is required from arguments.
* @return mixed
*/
protected function get_pagination_arg( $key = false ) {
if ( false === $key ) {
return $this->_pagination_args;
}
return isset( $this->_pagination_args[ $key ] ) ? $this->_pagination_args[ $key ] : false;
}
/**
* Get all post IDs of all allowed post types only.
*
* @param bool $count If we need count only for pagination purposes.
* @return int|array
*/
protected function get_post_ids( $count = false ) {
$paged = $this->get_pagination_arg( 'page' );
$table = DB::query_builder( 'posts' )->whereIn( 'post_type', Helper::get_accessible_post_types() );
return $count ? absint( $table->selectCount( 'ID', 'total' )->getVar() ) :
$table->select( 'ID' )->page( $paged - 1, $this->items_per_page )->get();
}
/**
* Get all user IDs.
*
* @param bool $count If we need count only for pagination purposes.
* @return int|array
*/
protected function get_user_ids( $count = false ) {
$paged = $this->get_pagination_arg( 'page' );
$table = DB::query_builder( 'users' );
return $count ? absint( $table->selectCount( 'ID', 'total' )->getVar() ) :
$table->select( 'ID' )->page( $paged - 1, $this->items_per_page )->get();
}
/**
* Get system settings.
*/
protected function get_settings() {
$all_opts = rank_math()->settings->all_raw();
$this->settings = $all_opts['general'];
$this->titles = $all_opts['titles'];
$this->sitemap = $all_opts['sitemap'];
}
/**
* Update system settings.
*/
protected function update_settings() {
Helper::update_all_settings(
$this->settings,
$this->titles,
$this->sitemap
);
}
/**
* Clean meta table for post, term and user.
*
* @return bool
*/
private function clean_meta_table() {
if ( empty( $this->meta_key ) ) {
return false;
}
$result = false;
$result = DB::query_builder( 'usermeta' )->whereLike( 'meta_key', $this->meta_key )->delete();
$result = DB::query_builder( 'termmeta' )->whereLike( 'meta_key', $this->meta_key )->delete();
$result = DB::query_builder( 'postmeta' )->whereLike( 'meta_key', $this->meta_key )->delete();
return $result;
}
/**
* Clean options table.
*
* @return bool
*/
private function clean_options() {
if ( empty( $this->option_keys ) ) {
return false;
}
$table = DB::query_builder( 'options' );
foreach ( $this->option_keys as $option_key ) {
$table->orWhereLike( 'option_name', $option_key );
}
return $table->delete();
}
/**
* Drop custom tables for plugins.
*
* @return bool
*/
private function drop_custom_tables() {
global $wpdb;
if ( empty( $this->table_names ) ) {
return false;
}
foreach ( $this->table_names as $table ) {
$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}{$table}" );
}
return true;
}
/**
* Check if plugin has options.
*
* @return bool
*/
private function has_options() {
if ( empty( $this->option_keys ) ) {
return false;
}
$table = DB::query_builder( 'options' )->select( 'option_id' );
foreach ( $this->option_keys as $option_key ) {
if ( '%' === substr( $option_key, -1 ) ) {
$table->orWhereLike( 'option_name', substr( $option_key, 0, -1 ), '' );
} else {
$table->orWhere( 'option_name', $option_key );
}
}
return absint( $table->getVar() ) > 0 ? true : false;
}
/**
* Check if plugin has postmeta.
*
* @return bool
*/
private function has_postmeta() {
if ( empty( $this->meta_key ) ) {
return false;
}
$result = DB::query_builder( 'postmeta' )->select( 'meta_id' )->whereLike( 'meta_key', $this->meta_key, '' )->getVar();
return absint( $result ) > 0 ? true : false;
}
/**
* Recalculate SEO scores.
*/
private function recalculate() {
$this->set_pagination( \RankMath\Tools\Update_Score::get()->find( false ) );
$return = $this->get_pagination_arg();
$data = \RankMath\Tools\Update_Score::get()->update_seo_score();
$return['data'] = $data;
return $return;
}
}

View File

@@ -0,0 +1,361 @@
<?php
/**
* The AIO Schema Rich Snippets Import Class
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin\Importers
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Importers;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\DB;
use RankMath\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* Import_AIO_Rich_Snippet class.
*/
class AIO_Rich_Snippet extends Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'AIO Schema Rich Snippet';
/**
* Plugin options meta key.
*
* @var string
*/
protected $meta_key = '_bsf_post_type';
/**
* Option keys to import and clean.
*
* @var array
*/
protected $option_keys = [ 'bsf_', 'bsf_%' ];
/**
* Choices keys to import.
*
* @var array
*/
protected $choices = [ 'postmeta' ];
/**
* Import post meta of plugin.
*
* @return array
*/
protected function postmeta() {
$this->set_pagination( $this->get_post_ids( true ) );
// Set Converter.
foreach ( $this->get_post_ids() as $snippet_post ) {
$type = $this->is_allowed_type( $snippet_post->meta_value );
$meta_keys = $this->get_metakeys( $type );
if ( false === $type || false === $meta_keys ) {
continue;
}
$this->set_postmeta( $snippet_post->post_id, $type, $meta_keys );
}
return $this->get_pagination_arg();
}
/**
* Set snippet meta.
*
* @param int $post_id Post ID.
* @param string $type Type to get keys for.
* @param array $meta_keys Array of meta keys to save.
*/
private function set_postmeta( $post_id, $type, $meta_keys ) {
$data = [];
foreach ( $meta_keys as $snippet_key => $snippet_value ) {
$value = get_post_meta( $post_id, '_bsf_' . $snippet_key, true );
$this->validate_schema_data( $data, $value, $snippet_value );
}
if ( empty( $data ) ) {
return;
}
// Convert post now.
$data['@type'] = $this->validate_type( $type );
$data['metadata'] = [
'title' => Helper::sanitize_schema_title( $data['@type'] ),
'type' => 'template',
'isPrimary' => 1,
'shortcode' => uniqid( 's-' ),
];
update_post_meta( $post_id, 'rank_math_schema_' . $data['@type'], $data );
}
/**
* Validate schema type.
*
* @param string $type Schema Type.
*/
private function validate_type( $type ) {
if ( 'software' === $type ) {
return 'SoftwareApplication';
}
if ( 'video' === $type ) {
return 'VideoObject';
}
return ucfirst( $type );
}
/**
* Validate schema data.
*
* @param array $data Schema entity data.
* @param string $value Entity value.
* @param string $key Entity key.
*/
private function validate_schema_data( &$data, $value, $key ) {
if ( ! Str::contains( '.', $key ) ) {
$data[ $key ] = $value;
return;
}
$element = explode( '.', $key );
if ( 2 === count( $element ) ) {
$this->add_type( $data[ $element[0] ], $element[0] );
$data[ $element[0] ][ $element[1] ] = $value;
return;
}
if ( count( $element ) > 2 ) {
$this->add_type( $data[ $element[0] ], $element[0] );
$this->add_type( $data[ $element[0] ][ $element[1] ], $element[1] );
$data[ $element[0] ][ $element[1] ][ $element[2] ] = $value;
}
}
/**
* Add property type.
*
* @param array $data Schema entity data.
* @param string $key Entity key.
*/
private function add_type( &$data, $key ) {
if ( 'location' === $key ) {
$data['@type'] = 'Place';
}
if ( 'address' === $key ) {
$data['@type'] = 'PostalAddress';
}
if ( 'offers' === $key ) {
$data['@type'] = 'Offer';
}
if ( 'brand' === $key ) {
$data['@type'] = 'Brand';
}
if ( 'review' === $key ) {
$data['@type'] = 'Review';
}
if ( 'reviewRating' === $key ) {
$data['@type'] = 'Rating';
}
if ( 'nutrition' === $key ) {
$data['@type'] = 'NutritionInformation';
}
}
/**
* Get the actions which can be performed for the plugin.
*
* @return array
*/
public function get_choices() {
return [
'postmeta' => esc_html__( 'Import Schemas', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import all Schema data for Posts, Pages, and custom post types.', 'rank-math' ) ),
];
}
/**
* Get all post IDs of all allowed post types only.
*
* @param bool $count If we need count only for pagination purposes.
* @return int|array
*/
protected function get_post_ids( $count = false ) {
$paged = $this->get_pagination_arg( 'page' );
$table = DB::query_builder( 'postmeta' )->where( 'meta_key', '_bsf_post_type' );
return $count ? absint( $table->selectCount( 'meta_id' )->getVar() ) :
$table->page( $paged - 1, $this->items_per_page )->get();
}
/**
* Get snippet types.
*
* @return array
*/
private function get_types() {
return [
'2' => 'event',
'5' => 'person',
'6' => 'product',
'7' => 'recipe',
'8' => 'software',
'9' => 'video',
'10' => 'article',
'11' => 'service',
];
}
/**
* Is snippet type allowed.
*
* @param string $type Type to check.
*
* @return bool
*/
private function is_allowed_type( $type ) {
$types = $this->get_types();
return isset( $types[ $type ] ) ? $types[ $type ] : false;
}
/**
* Get meta keys hash to import.
*
* @param string $type Type to get keys for.
*
* @return array
*/
private function get_metakeys( $type ) {
$hash = [
'event' => $this->get_event_fields(),
'product' => $this->get_product_fields(),
'recipe' => $this->get_recipe_fields(),
'software' => $this->get_software_fields(),
'video' => $this->get_video_fields(),
'article' => [
'article_name' => 'headline',
'article_desc' => 'description',
],
'person' => [
'people_fn' => 'name',
'people_nickname' => 'description',
'people_job_title' => 'jobTitle',
'people_street' => 'address.streetAddress',
'people_local' => 'address.addressLocality',
'people_region' => 'address.addressRegion',
'people_postal' => 'address.postalCode',
],
'service' => [
'service_type' => 'serviceType',
'service_desc' => 'description',
],
];
return isset( $hash[ $type ] ) ? $hash[ $type ] : false;
}
/**
* Get event fields.
*
* @return array
*/
private function get_event_fields() {
return [
'event_title' => 'name',
'event_desc' => 'description',
'event_organization' => 'location.name',
'event_street' => 'location.address.streetAddress',
'event_local' => 'location.address.addressLocality',
'event_region' => 'location.address.addressRegion',
'event_postal_code' => 'location.address.postalCode',
'event_start_date' => 'startDate',
'event_end_date' => 'endDate',
'event_price' => 'offers.price',
'event_cur' => 'offers.priceCurrency',
'event_ticket_url' => 'offers.url',
];
}
/**
* Get product fields.
*
* @return array
*/
private function get_product_fields() {
return [
'product_brand' => 'brand.name',
'product_name' => 'name',
'product_price' => 'offers.price',
'product_cur' => 'offers.priceCurrency',
'product_status' => 'offers.availability',
];
}
/**
* Get recipe fields.
*
* @return array
*/
private function get_recipe_fields() {
return [
'recipes_name' => 'name',
'recipes_desc' => 'description',
'recipes_preptime' => 'prepTime',
'recipes_cooktime' => 'cookTime',
'recipes_totaltime' => 'totalTime',
'recipes_ingredient' => 'recipeIngredient',
'recipes_nutrition' => 'nutrition.calories',
];
}
/**
* Get software fields.
*
* @return array
*/
private function get_software_fields() {
return [
'software_rating' => 'review.reviewRating.ratingValue',
'software_price' => 'offers.price',
'software_cur' => 'offers.priceCurrency',
'software_name' => 'name',
'software_os' => 'operatingSystem',
'software_cat' => 'applicationCategory',
];
}
/**
* Get video fields.
*
* @return array
*/
private function get_video_fields() {
return [
'video_title' => 'name',
'video_desc' => 'description',
'video_thumb' => 'thumbnailUrl',
'video_url' => 'contentUrl',
'video_emb_url' => 'embedUrl',
'video_duration' => 'duration',
];
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,200 @@
<?php
/**
* The functionality to detect whether we should import from another SEO plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin\Importers
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Importers;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* Detector class.
*/
class Detector {
use Hooker;
/**
* Plugins we can import from.
*
* @var array
*/
public static $plugins = null;
/**
* Detects whether we can import anything or not.
*
* @return array List of plugins we can import from.
*/
public function detect() {
$this->requirements();
if ( ! is_null( self::$plugins ) ) {
return self::$plugins;
}
self::$plugins = [];
$plugins = $this->get();
foreach ( $plugins as $slug => $plugin ) {
if ( ! $this->is_detectable( $plugin, $plugins ) ) {
continue;
}
$this->can_import( $slug, $plugin );
}
return self::$plugins;
}
/**
* Run import class.
*
* @param Plugin_Importer $importer The importer that needs to perform this action.
* @param string $action The action to perform.
* @param string $perform The action to perform when running import action.
*/
public function run( $importer, $action = 'detect', $perform = '' ) {
if ( 'cleanup' === $action ) {
return $importer->run_cleanup();
} elseif ( 'import' === $action ) {
return $importer->run_import( $perform );
}
return $importer->run_detect();
}
/**
* Run action by slug.
*
* @param string $slug The importer slug that needs to perform this action.
* @param string $action The action to perform.
* @param string $perform The action to perform when running import action.
*/
public static function run_by_slug( $slug, $action, $perform = '' ) {
$detector = new self();
$importers = $detector->get();
if ( ! isset( $importers[ $slug ] ) ) {
return false;
}
$importer = $importers[ $slug ];
$importer = new $importer['class']( $importer['file'] );
$status = $detector->run( $importer, $action, $perform );
return \compact( 'importer', 'status' );
}
/**
* Deactivate all plugins.
*/
public static function deactivate_all() {
$detector = new Detector();
$plugins = $detector->get();
foreach ( $plugins as $plugin ) {
deactivate_plugins( $plugin['file'] );
}
}
/**
* Get the list of available importers.
*
* @return array Available importers.
*/
public function get() {
return $this->do_filter(
'importers/detect_plugins',
[
'yoast' => [
'class' => '\\RankMath\\Admin\\Importers\\Yoast',
'file' => 'wordpress-seo/wp-seo.php',
'premium' => 'yoast-premium',
],
'seopress' => [
'class' => '\\RankMath\\Admin\\Importers\\SEOPress',
'file' => 'wp-seopress/seopress.php',
],
'aioseo' => [
'class' => '\\RankMath\\Admin\\Importers\\AIOSEO',
'file' => 'all-in-one-seo-pack/all_in_one_seo_pack.php',
'premium' => 'all-in-one-seo-pack-pro',
],
'all-in-one-seo-pack-pro' => [
'class' => '\\RankMath\\Admin\\Importers\\AIOSEO',
'file' => 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php',
'parent' => 'aioseo',
],
'yoast-premium' => [
'class' => '\\RankMath\\Admin\\Importers\\Yoast',
'file' => 'wordpress-seo-premium/wp-seo-premium.php',
'parent' => 'yoast',
],
'aio-rich-snippet' => [
'class' => '\\RankMath\\Admin\\Importers\\AIO_Rich_Snippet',
'file' => 'all-in-one-schemaorg-rich-snippets/index.php',
],
'wp-schema-pro' => [
'class' => '\\RankMath\\Admin\\Importers\\WP_Schema_Pro',
'file' => 'wp-schema-pro/wp-schema-pro.php',
],
'redirections' => [
'class' => '\\RankMath\\Admin\\Importers\\Redirections',
'file' => 'redirection/redirection.php',
],
]
);
}
/**
* Check requirements.
*/
private function requirements() {
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
}
/**
* Can import plugin data.
*
* @param string $slug Plugin slug.
* @param array $plugin Plugin data.
*/
private function can_import( $slug, $plugin ) {
$importer = new $plugin['class']( $plugin['file'] );
if ( $importer->run_detect() ) {
self::$plugins[ $slug ] = [
'name' => $importer->get_plugin_name(),
'file' => $importer->get_plugin_file(),
'choices' => $importer->get_choices(),
];
}
}
/**
* Check if plugin is detectable.
*
* @param array $check Plugin to check.
* @param array $plugins Plugins data.
*
* @return bool
*/
private function is_detectable( $check, $plugins ) {
// Check if parent is set.
if ( isset( $check['parent'] ) && isset( self::$plugins[ $check['parent'] ] ) ) {
return false;
}
// Check if plugin has premium and it is active.
if ( isset( $check['premium'] ) && is_plugin_active( $plugins[ $check['premium'] ]['file'] ) ) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,104 @@
<?php
/**
* The Redirections Import Class
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin\Importers
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Importers;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use RankMath\Redirections\Redirection;
defined( 'ABSPATH' ) || exit;
/**
* Redirections class.
*/
class Redirections extends Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'Redirections';
/**
* Option keys to import and clean.
*
* @var array
*/
protected $option_keys = [ 'redirection_options' ];
/**
* Choices keys to import.
*
* @var array
*/
protected $choices = [ 'redirections' ];
/**
* Import redirections of plugin.
*
* @return bool
*/
protected function redirections() {
global $wpdb;
$count = 0;
$rows = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}redirection_items" );
if ( empty( $rows ) ) {
return false;
}
foreach ( (array) $rows as $row ) {
$item = Redirection::from(
[
'sources' => [
[
'pattern' => $row->url,
'comparison' => empty( $row->regex ) ? 'exact' : 'regex',
],
],
'url_to' => $this->get_url_to( $row ),
'header_code' => $row->action_code,
'status' => 'disabled' === $row->status ? 'inactive' : 'active',
]
);
$id = $item->save();
if ( false !== $id ) {
do_action( 'rank_math/redirection/after_import', $id, $row );
$count++;
}
}
Helper::update_modules( [ 'redirections' => 'on' ] );
return compact( 'count' );
}
/**
* Get validated url to value
*
* @param object $row Current row we are processing.
* @return string
*/
private function get_url_to( $row ) {
$data = maybe_unserialize( $row->action_data );
if ( is_array( $data ) && ( isset( $data['url'] ) || isset( $data['url_from'] ) ) ) {
return isset( $data['url'] ) ? $data['url'] : $data['url_from'];
}
if ( is_string( $row->action_data ) ) {
return $row->action_data;
}
return '/';
}
}

View File

@@ -0,0 +1,845 @@
<?php
/**
* The SEOPress Import Class
*
* @since 1.0.24
* @package RankMath
* @subpackage RankMath\Admin\Importers
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Importers;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use RankMath\Redirections\Redirection;
use RankMath\Schema\JsonLD;
use RankMath\Schema\Singular;
use RankMath\Helpers\DB;
defined( 'ABSPATH' ) || exit;
/**
* SEOPress class.
*/
class SEOPress extends Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'SEOPress';
/**
* Plugin options meta key.
*
* @var string
*/
protected $meta_key = 'seopress';
/**
* Option keys to import and clean.
*
* @var array
*/
protected $option_keys = [ 'seopress', 'seopress_%' ];
/**
* Choices keys to import.
*
* @var array
*/
protected $choices = [ 'settings', 'postmeta', 'termmeta', 'redirections' ];
/**
* JsonLD.
*
* @var JsonLD
*/
private $json_ld;
/**
* Singular.
*
* @var Singular
*/
private $single;
/**
* Convert SEOPress variables if needed.
*
* @param string $string Value to convert.
*
* @return string
*/
public function convert_variables( $string ) {
$string = str_replace( '%%sitetitle%%', '%sitename%', $string );
$string = str_replace( '%%tagline%%', '%sitedesc%', $string );
$string = str_replace( '%%post_title%%', '%title%', $string );
$string = str_replace( '%%post_excerpt%%', '%excerpt%', $string );
$string = str_replace( '%%post_date%%', '%date%', $string );
$string = str_replace( '%%post_modified_date%%', '%modified%', $string );
$string = str_replace( '%post_author%%', '%name%', $string );
$string = str_replace( '%%post_category%%', '%category%', $string );
$string = str_replace( '%%post_tag%%', '%tag%', $string );
$string = str_replace( '%%_category_title%%', '%term%', $string );
$string = str_replace( '%%_category_description%%', '%term_description%', $string );
$string = str_replace( '%%tag_title%%', '%term%', $string );
$string = str_replace( '%%tag_description%%', '%term_description%', $string );
$string = str_replace( '%%term_title%%', '%term%', $string );
$string = str_replace( '%%term_description%%', '%term_description%', $string );
$string = str_replace( '%%search_keywords%%', '%search_query%', $string );
$string = str_replace( '%%current_pagination%%', '%page%', $string );
$string = str_replace( '%%cpt_plural%%', '%pt_plural%', $string );
$string = str_replace( '%%archive_title%%', '%title%', $string );
$string = str_replace( '%%archive_date%%', '%currentdate%', $string );
$string = str_replace( '%%archive_date_day%%', '%currentday%', $string );
$string = str_replace( '%%archive_date_month%%', '%currentmonth%', $string );
$string = str_replace( '%%archive_date_year%%', '%year%', $string );
$string = str_replace( '%%currentdate%%', '%currentdate%', $string );
$string = str_replace( '%%currentday%%', '%currentday%', $string );
$string = str_replace( '%%currentmonth%%', '%currentmonth%', $string );
$string = str_replace( '%%currentyear%%', '%currentyear%', $string );
$string = str_replace( '%%currenttime%%', '%time%', $string );
$string = str_replace( '%%author_bio%%', '%user_description%', $string );
$string = str_replace( '%%wc_single_cat%%', '%term%', $string );
$string = str_replace( '%%wc_single_tag%%', '%term%', $string );
$string = str_replace( '%%wc_single_short_desc%%', '%wc_shortdesc%', $string );
$string = str_replace( '%%wc_single_price%%', '%wc_price%', $string );
return str_replace( '%%', '%', $string );
}
/**
* Deactivate plugin action.
*/
protected function deactivate() {
if ( is_plugin_active( $this->get_plugin_file() ) ) {
deactivate_plugins( $this->get_plugin_file() );
deactivate_plugins( 'wp-seopress-pro/seopress-pro.php' );
}
return true;
}
/**
* Import settings of plugin.
*
* @return bool
*/
protected function settings() {
$this->get_settings();
$seopress_titles = get_option( 'seopress_titles_option_name' );
$seopress_sitemap = get_option( 'seopress_xml_sitemap_option_name' );
$seopress_local = get_option( 'seopress_pro_option_name' );
// Titles & Descriptions.
$hash = [
'seopress_titles_archives_author_disable' => 'disable_author_archives',
'seopress_titles_archives_date_disable' => 'disable_date_archives',
'seopress_titles_home_site_title' => 'homepage_title',
'seopress_titles_home_site_desc' => 'homepage_description',
'seopress_titles_archives_author_title' => 'author_archive_title',
'seopress_titles_archives_author_desc' => 'author_archive_description',
'seopress_titles_archives_date_title' => 'date_archive_title',
'seopress_titles_archives_date_desc' => 'date_archive_description',
'seopress_titles_archives_search_title' => 'search_title',
'seopress_titles_archives_404_title' => '404_title',
];
$this->replace( $hash, $seopress_titles, $this->titles, 'convert_variables' );
$this->replace( $hash, $seopress_titles, $this->titles, 'convert_bool' );
$this->titles['title_separator'] = \RankMath\CMB2::sanitize_htmlentities( $seopress_titles['seopress_titles_sep'] );
$this->titles['date_archive_robots'] = ! empty( $seopress_titles['seopress_titles_archives_date_noindex'] ) ? [ 'noindex' ] : [];
$this->set_robots( 'author', ! empty( $seopress_titles['seopress_titles_archives_author_noindex'] ), '' );
$this->update_modules( $seopress_local, $seopress_sitemap );
$this->social_settings();
$this->advanced_settings();
$this->post_type_settings( $seopress_titles, $seopress_sitemap );
$this->taxonomies_settings( $seopress_titles, $seopress_sitemap );
$this->local_seo_settings( $seopress_local );
$this->update_settings();
return true;
}
/**
* Import post meta of plugin.
*
* @return array
*/
protected function postmeta() {
$this->set_pagination( $this->get_post_ids( true ) );
$post_ids = $this->get_post_ids();
$this->set_primary_term( $post_ids );
$hash = [
'_seopress_titles_title' => 'rank_math_title',
'_seopress_titles_desc' => 'rank_math_description',
'_seopress_analysis_target_kw' => 'rank_math_focus_keyword',
'_seopress_robots_canonical' => 'rank_math_canonical_url',
'_seopress_social_fb_title' => 'rank_math_facebook_title',
'_seopress_social_fb_desc' => 'rank_math_facebook_description',
'_seopress_social_fb_img' => 'rank_math_facebook_image',
'_seopress_social_twitter_title' => 'rank_math_twitter_title',
'_seopress_social_twitter_desc' => 'rank_math_twitter_description',
'_seopress_social_twitter_img' => 'rank_math_twitter_image',
'_seopress_robots_breadcrumbs' => 'rank_math_breadcrumb_title',
];
// Set Converter.
$this->json_ld = new JsonLD();
$this->single = new Singular();
foreach ( $post_ids as $post ) {
$post_id = $post->ID;
$this->replace_meta( $hash, null, $post_id, 'post', 'convert_variables' );
delete_post_meta( $post_id, 'rank_math_permalink' );
$this->replace_image( get_post_meta( $post_id, '_seopress_social_fb_img', true ), 'post', 'rank_math_facebook_image', 'rank_math_facebook_image_id', $post_id );
$this->replace_image( get_post_meta( $post_id, '_seopress_social_twitter_img', true ), 'post', 'rank_math_twitter_image', 'rank_math_twitter_image_id', $post_id );
$this->is_twitter_using_facebook( 'post', $post_id );
$this->set_object_robots( $post_id, 'post' );
$this->set_schema_data( $post_id );
$this->set_object_redirection( $post_id, 'post' );
}
return $this->get_pagination_arg();
}
/**
* Import term meta of plugin.
*
* @return array
*/
protected function termmeta() {
$count = 0;
$terms = new \WP_Term_Query(
[
'meta_key' => '_seopress_titles_title',
'fields' => 'ids',
'hide_empty' => false,
'get' => 'all',
]
);
if ( empty( $terms ) || is_wp_error( $terms ) ) {
return false;
}
$hash = [
'_seopress_titles_title' => 'rank_math_title',
'_seopress_titles_desc' => 'rank_math_description',
'_seopress_robots_canonical' => 'rank_math_canonical_url',
'_seopress_social_fb_title' => 'rank_math_facebook_title',
'_seopress_social_fb_desc' => 'rank_math_facebook_description',
'_seopress_social_fb_img' => 'rank_math_facebook_image',
'_seopress_social_twitter_title' => 'rank_math_twitter_title',
'_seopress_social_twitter_desc' => 'rank_math_twitter_description',
'_seopress_social_twitter_img' => 'rank_math_twitter_image',
];
foreach ( $terms->get_terms() as $term_id ) {
$count++;
$this->replace_meta( $hash, [], $term_id, 'term', 'convert_variables' );
delete_term_meta( $term_id, 'rank_math_permalink' );
$this->is_twitter_using_facebook( 'term', $term_id );
$this->set_object_robots( $term_id, 'term' );
$this->set_object_redirection( $term_id, 'term' );
}
return compact( 'count' );
}
/**
* Imports redirections data.
*
* @return array
*/
protected function redirections() {
$redirections = get_posts(
[
'posts_per_page' => -1,
'post_type' => 'seopress_404',
]
);
if ( empty( $redirections ) ) {
return false;
}
$count = 0;
foreach ( $redirections as $redirection ) {
$data = [
'source' => $redirection->post_title,
'destination' => get_post_meta( $redirection->ID, '_seopress_redirections_value', true ),
'code' => get_post_meta( $redirection->ID, '_seopress_redirections_type', true ),
'status' => 'publish' === $redirection->post_status ? true : false,
];
if ( false !== $this->save_redirection( $data ) ) {
$count++;
}
}
return compact( 'count' );
}
/**
* Update Modules.
*
* @param array $seopress_local Local SEO Settings.
* @param array $seopress_sitemap Sitemap Settings.
*/
private function update_modules( $seopress_local, $seopress_sitemap ) {
$seopress_toggle = get_option( 'seopress_toggle' );
// Enable/Disable Modules.
$modules = [
'local-seo' => ! empty( $seopress_toggle['toggle-local-business'] ) ? 'on' : 'off',
'sitemap' => ! empty( $seopress_toggle['toggle-xml-sitemap'] ) && ! empty( $seopress_sitemap['seopress_xml_sitemap_general_enable'] ) ? 'on' : 'off',
'rich-snippet' => ! empty( $seopress_toggle['toggle-rich-snippets'] ) ? 'on' : 'off',
'404-monitor' => ! empty( $seopress_toggle['toggle-404'] ) && ! empty( $seopress_local['seopress_404_enable'] ) ? 'on' : 'off',
];
foreach ( $modules as $key => $value ) {
Helper::update_modules( [ $key => $value ] );
}
}
/**
* Save redirection.
*
* @param WP_Post $redirection Redirection object.
*
* @return mixed
*/
private function save_redirection( $redirection ) {
if ( empty( $redirection['source'] ) || empty( $redirection['destination'] ) ) {
return false;
}
$item = Redirection::from(
[
'sources' => [
[
'pattern' => $redirection['source'],
'comparison' => 'exact',
],
],
'url_to' => $redirection['destination'],
'header_code' => $redirection['code'],
'status' => $redirection['status'] ? 'active' : 'inactive',
]
);
return $item->save();
}
/**
* Social settings.
*/
private function social_settings() {
$social = get_option( 'seopress_social_option_name' );
$hash = [
'seopress_social_accounts_facebook' => 'social_url_facebook',
'seopress_social_facebook_link_ownership_id' => 'facebook_author_urls',
'seopress_social_facebook_img' => 'open_graph_image',
'seopress_social_facebook_admin_id' => 'facebook_admin_id',
'seopress_social_facebook_app_id' => 'facebook_app_id',
'seopress_social_accounts_twitter' => 'twitter_author_names',
'seopress_social_knowledge_name' => 'knowledgegraph_name',
'seopress_social_knowledge_img' => 'knowledgegraph_logo',
];
$this->replace( $hash, $social, $this->titles );
$additional_urls = [];
foreach ( [ 'pinterest', 'instagram', 'youtube', 'linkedin' ] as $service ) {
if ( ! empty( $social[ "seopress_social_accounts_{$service}" ] ) ) {
$additional_urls[] = $social[ "seopress_social_accounts_{$service}" ];
}
}
if ( ! empty( $additional_urls ) ) {
$this->titles['social_additional_profiles'] = implode( PHP_EOL, $additional_urls );
}
// OpenGraph.
if ( isset( $social['og_default_image'] ) ) {
$this->replace_image( $social['og_default_image'], $this->titles, 'open_graph_image', 'open_graph_image_id' );
}
if ( isset( $social['og_frontpage_image'] ) ) {
$this->replace_image( $social['og_frontpage_image'], $this->titles, 'homepage_facebook_image', 'homepage_facebook_image_id' );
}
// Phone Numbers.
if ( ! empty( $social['seopress_social_knowledge_phone'] ) ) {
$this->titles['phone_numbers'] = [
[
'type' => $social['seopress_social_knowledge_contact_type'],
'number' => $social['seopress_social_knowledge_phone'],
],
];
}
$this->titles['knowledgegraph_type'] = isset( $social['seopress_social_knowledge_type'] ) && 'organization' === strtolower( $social['seopress_social_knowledge_type'] ) ? 'company' : 'person';
}
/**
* Post type settings.
*
* @param array $seopress_titles Titles & Meta Settings.
* @param array $seopress_sitemap Sitemap Settings.
*/
private function post_type_settings( $seopress_titles, $seopress_sitemap ) {
foreach ( Helper::get_accessible_post_types() as $post_type ) {
$this->titles[ "pt_{$post_type}_title" ] = isset( $seopress_titles['seopress_titles_single_titles'][ $post_type ] ) ? $this->convert_variables( $seopress_titles['seopress_titles_single_titles'][ $post_type ]['title'] ) : '';
$this->titles[ "pt_{$post_type}_description" ] = isset( $seopress_titles['seopress_titles_single_titles'][ $post_type ] ) ? $this->convert_variables( $seopress_titles['seopress_titles_single_titles'][ $post_type ]['description'] ) : '';
$this->set_robots(
"pt_{$post_type}",
! empty( $seopress_titles['seopress_titles_single_titles'][ $post_type ]['noindex'] ),
! empty( $seopress_titles['seopress_titles_single_titles'][ $post_type ]['nofollow'] )
);
$enable_sitemap = $this->enable_sitemap( 'post_types', $post_type, $seopress_sitemap );
$this->sitemap[ "pt_{$post_type}_sitemap" ] = $enable_sitemap ? 'on' : 'off';
if ( 'attachment' === $post_type && $enable_sitemap ) {
$this->settings['attachment_redirect_urls'] = 'off';
}
}
}
/**
* Taxonomies settings.
*
* @param array $seopress_titles Titles & Meta Settings.
* @param array $seopress_sitemap Sitemap Settings.
*/
private function taxonomies_settings( $seopress_titles, $seopress_sitemap ) {
foreach ( Helper::get_accessible_taxonomies() as $taxonomy => $object ) {
$this->titles[ "tax_{$taxonomy}_title" ] = ! empty( $seopress_titles['seopress_titles_tax_titles'][ $taxonomy ]['title'] ) ? $this->convert_variables( $seopress_titles['seopress_titles_tax_titles'][ $taxonomy ]['title'] ) : '';
$this->titles[ "tax_{$taxonomy}_description" ] = ! empty( $seopress_titles['seopress_titles_tax_titles'][ $taxonomy ]['description'] ) ? $this->convert_variables( $seopress_titles['seopress_titles_tax_titles'][ $taxonomy ]['description'] ) : '';
$this->set_robots(
"tax_{$taxonomy}",
! empty( $seopress_titles['seopress_titles_tax_titles'][ $taxonomy ]['noindex'] ),
! empty( $seopress_titles['seopress_titles_tax_titles'][ $taxonomy ]['nofollow'] )
);
$this->sitemap[ "tax_{$taxonomy}_sitemap" ] = $this->enable_sitemap( 'taxonomies', $taxonomy, $seopress_sitemap ) ? 'on' : 'off';
}
}
/**
* Whether to enable sitemap.
*
* @param string $object_prefix post_types/taxonomies.
* @param string $object_type Current object type.
* @param string $seopress_sitemap Sitemap settings.
*
* @return bool
*/
private function enable_sitemap( $object_prefix, $object_type, $seopress_sitemap ) {
return ! empty( $seopress_sitemap[ "seopress_xml_sitemap_{$object_prefix}_list" ][ $object_type ]['include'] );
}
/**
* Set robots settings.
*
* @param string $prefix Setting key prefix.
* @param bool $noindex Is noindex.
* @param bool $nofollow Is nofollow.
*/
private function set_robots( $prefix, $noindex, $nofollow ) {
if ( $noindex || $nofollow ) {
$robots = "{$prefix}_robots";
$custom = "{$prefix}_custom_robots";
// Settings.
$this->titles[ $custom ] = 'on';
$this->titles[ $robots ][] = $noindex ? 'noindex' : '';
$this->titles[ $robots ][] = $nofollow ? 'nofollow' : '';
$this->titles[ $robots ] = array_unique( $this->titles[ $robots ] );
}
}
/**
* Set Advanced settings.
*/
private function advanced_settings() {
$seopress_advanced = get_option( 'seopress_advanced_option_name' );
$hash = [
'seopress_advanced_advanced_google' => 'google_verify',
'seopress_advanced_advanced_bing' => 'bing_verify',
'seopress_advanced_advanced_yandex' => 'yandex_verify',
'seopress_advanced_advanced_pinterest' => 'pinterest_verify',
];
$this->replace( $hash, $seopress_advanced, $this->settings );
$this->replace( $hash, $seopress_advanced, $this->settings, 'convert_bool' );
$this->settings['attachment_redirect_urls'] = ! empty( $seopress_advanced['seopress_advanced_advanced_attachments'] ) ? 'on' : 'off';
$this->settings['strip_category_base'] = ! empty( $seopress_advanced['seopress_advanced_advanced_category_url'] ) ? 'on' : 'off';
$set_alt = ! empty( $seopress_advanced['seopress_advanced_advanced_image_auto_alt_editor'] ) ? 'on' : 'off';
$set_title = ! empty( $seopress_advanced['seopress_advanced_advanced_image_auto_title_editor'] ) ? 'on' : 'off';
$this->settings['add_img_alt'] = $set_alt;
$this->settings['add_img_title'] = $set_title;
$this->settings['img_alt_format'] = 'on' === $set_alt ? ' %filename%' : '';
$this->settings['img_title_format'] = 'on' === $set_title ? ' %filename%' : '';
}
/**
* Local SEO settings.
*
* @param array $seopress_local Local SEOPress data.
*/
private function local_seo_settings( $seopress_local ) {
if ( empty( $seopress_local ) ) {
return;
}
// Breadcrumbs.
$hash = [
'seopress_breadcrumbs_i18n_home' => 'breadcrumbs_home_label',
'seopress_breadcrumbs_i18n_search' => 'breadcrumbs_search_format',
'seopress_breadcrumbs_i18n_404' => 'breadcrumbs_404_label',
'seopress_breadcrumbs_enable' => 'breadcrumbs',
];
$this->replace( $hash, $seopress_local, $this->settings );
$this->replace( $hash, $seopress_local, $this->settings, 'convert_bool' );
$this->settings['breadcrumbs_separator'] = \RankMath\CMB2::sanitize_htmlentities( $seopress_local['seopress_breadcrumbs_separator'] );
$hash = [
'seopress_local_business_type' => 'local_business_type',
'seopress_local_business_price_range' => 'price_range',
'seopress_local_business_url' => 'url',
];
$this->replace( $hash, $seopress_local, $this->titles, 'convert_variables' );
// Street Address.
$address = [];
$hash = [
'seopress_local_business_street_address' => 'streetAddress',
'seopress_local_business_address_locality' => 'addressLocality',
'seopress_local_business_address_region' => 'addressRegion',
'seopress_local_business_postal_code' => 'postalCode',
'seopress_local_business_address_country' => 'addressCountry',
];
$this->replace( $hash, $seopress_local, $address );
$this->titles['local_address'] = $address;
// Coordinates.
if ( ! empty( $seopress_local['seopress_local_business_lat'] ) && ! empty( $seopress_local['seopress_local_business_lon'] ) ) {
$this->titles['geo'] = $seopress_local['seopress_local_business_lat'] . ', ' . $seopress_local['seopress_local_business_lon'];
}
$this->seopress_pro_settings( $seopress_local );
$this->seopress_set_opening_hours( $seopress_local );
}
/**
* 404 settings.
*
* @param array $seopress_local SEOPress Pro Settings.
*/
private function seopress_pro_settings( $seopress_local ) {
Helper::update_modules( [ 'redirections' => 'on' ] );
$hash = [
'seopress_rss_before_html' => 'rss_before_content',
'seopress_rss_after_html' => 'rss_after_content',
'seopress_404_redirect_custom_url' => 'redirections_custom_url',
'seopress_404_redirect_status_code' => 'redirections_header_code',
];
$this->replace( $hash, $seopress_local, $this->settings );
$this->settings['redirections_fallback'] = 'none' === $seopress_local['seopress_404_redirect_home'] ? 'default' : ( 'home' === $seopress_local['seopress_404_redirect_home'] ? 'homepage' : 'custom' );
}
/**
* Set Opening Hours.
*
* @param array $seopress_local SEOPress Pro Settings.
*/
private function seopress_set_opening_hours( $seopress_local ) {
$hash = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ];
$data = [];
foreach ( $seopress_local['seopress_local_business_opening_hours'] as $key => $opening_hour ) {
if ( isset( $opening_hour['open'] ) ) {
continue;
}
$data[] = [
'day' => $hash[ $key ],
'time' => $opening_hour['start']['hours'] . ':' . $opening_hour['start']['mins'] . '-' . $opening_hour['end']['hours'] . ':' . $opening_hour['end']['mins'],
];
}
$this->titles['opening_hours'] = $data;
}
/**
* Set schema data.
*
* @param int $post_id Post ID.
*/
private function set_schema_data( $post_id ) {
if ( ! $type = get_post_meta( $post_id, '_seopress_pro_rich_snippets_type', true ) ) { // phpcs:ignore
return;
}
if ( $meta_keys = $this->get_schema_metakeys( $type ) ) { // phpcs:ignore
$schema_type = 's' === substr( $type, -1 ) ? substr( $type, 0, -1 ) : $type;
update_post_meta( $post_id, 'rank_math_rich_snippet', $schema_type );
foreach ( $meta_keys as $meta_key => $data ) {
$value = $this->get_snippet_value( $post_id, $meta_key );
if ( $value && 'events_location_address' === $meta_key ) {
$value = [ 'streetAddress' => $value ];
}
update_post_meta( $post_id, "rank_math_snippet_{$data}", $value );
}
// Convert post now.
$data = $this->json_ld->get_old_schema( $post_id, $this->single );
if ( isset( $data['richSnippet'] ) ) {
$data = $data['richSnippet'];
$type = $data['@type'];
$data['metadata'] = [
'title' => $type,
'type' => 'template',
];
update_post_meta( $post_id, 'rank_math_schema_' . $type, $data );
}
}
}
/**
* Set object redirection.
*
* @param int $object_id Object id for destination.
* @param string $object_type Object type for destination.
*/
private function set_object_redirection( $object_id, $object_type ) {
$source_url = 'term' === $object_type ? get_term_link( $object_id ) : get_permalink( $object_id );
if ( is_wp_error( $source_url ) ) { // phpcs:ignore
return;
}
$hash = [
'_seopress_redirections_type' => 'redirection_header_code',
'_seopress_redirections_value' => 'redirection_url_to',
];
$this->replace_meta( $hash, null, $object_id, $object_type, 'convert_variables' );
$redirection = [
'source' => trim( parse_url( $source_url, PHP_URL_PATH ), '/' ),
'destination' => $this->get_meta( $object_type, $object_id, '_seopress_redirections_value' ),
'code' => $this->get_meta( $object_type, $object_id, '_seopress_redirections_type' ),
'status' => $this->get_meta( $object_type, $object_id, '_seopress_redirections_enabled' ),
];
$this->save_redirection( $redirection );
}
/**
* Get snippet value.
*
* @param int $post_id Post ID.
* @param int $meta_key Meta key.
*
* @return string $value Snippet value
*/
private function get_snippet_value( $post_id, $meta_key ) {
$prefix = in_array( $meta_key, [ 'events_offers_valid_from_date', 'events_offers_valid_from_time' ], true ) ? '_seopress_rich_snippets_' : '_seopress_pro_rich_snippets_';
$value = get_post_meta( $post_id, $prefix . $meta_key, true );
if ( in_array( $meta_key, [ 'recipes_prep_time', 'recipes_cook_time', 'videos_duration' ], true ) ) {
$value .= 'M';
}
$hash = [
'events_start_date' => 'events_start_time',
'events_end_date' => 'events_end_time',
'events_offers_valid_from_date' => 'events_offers_valid_from_time',
];
if ( isset( $hash[ $meta_key ] ) ) {
$time = get_post_meta( $post_id, $prefix . $hash[ $meta_key ], true );
$value = strtotime( $value . ' ' . $time );
}
return $value;
}
/**
* Get schema meta keys.
*
* @param string $type Type of snippet.
*
* @return array
*/
private function get_schema_metakeys( $type ) {
$hash = [
'articles' => [
'article_type' => 'article_type',
'article_title' => 'name',
],
'recipes' => [
'recipes_name' => 'name',
'recipes_desc' => 'desc',
'recipes_cat' => 'recipe_type',
'recipes_prep_time' => 'recipe_preptime',
'recipes_cook_time' => 'recipe_cooktime',
'recipes_calories' => 'recipe_calories',
'recipes_yield' => 'recipe_yield',
'recipes_ingredient' => 'recipe_ingredients',
],
'courses' => [
'courses_title' => 'name',
'courses_desc' => 'desc',
'courses_school' => 'course_provider',
'courses_website' => 'course_provider_url',
],
'videos' => [
'videos_name' => 'name',
'videos_description' => 'desc',
'videos_img' => 'rank_math_twitter_title',
'videos_url' => 'video_url',
'videos_duration' => 'video_duration',
],
'events' => [
'events_type' => 'event_type',
'events_name' => 'name',
'events_desc' => 'desc',
'events_location_address' => 'event_address',
'events_location_name' => 'event_venue',
'events_location_url' => 'event_venue_url',
'events_start_date' => 'event_startdate',
'events_end_date' => 'event_enddate',
'events_offers_price' => 'event_price',
'events_offers_price_currency' => 'event_currency',
'events_offers_url' => 'event_ticketurl',
'events_offers_availability' => 'event_availability',
'events_offers_valid_from_date' => 'event_availability_starts',
'events_performer' => 'event_performer',
],
'products' => [
'product_description' => 'desc',
'product_name' => 'name',
'product_price_currency' => 'product_currency',
'product_price' => 'product_price',
],
'review' => [
'review_item' => 'name',
'item_name' => 'desc',
'review_rating' => 'review_rating_value',
],
];
return isset( $hash[ $type ] ) ? $hash[ $type ] : false;
}
/**
* Set primary term for post
*
* @param int[] $post_ids Post IDs.
*/
private function set_primary_term( $post_ids ) {
$post_ids = wp_list_pluck( $post_ids, 'ID' );
$table = DB::query_builder( 'postmeta' );
$results = $table->whereLike( 'meta_key', '_seopress_robots_primary_cat' )->whereIn( 'post_id', $post_ids )->get();
foreach ( $results as $result ) {
if ( 'none' !== $result->meta_value ) {
update_post_meta( $result->post_id, 'rank_math_primary_category', $result->meta_value );
}
}
}
/**
* Set post/term robots.
*
* @param int $object_id Object id.
* @param string $object_type Object type.
*/
private function set_object_robots( $object_id, $object_type ) {
// Early bail if robots data is set in Rank Math plugin.
if ( ! empty( $this->get_meta( $object_type, $object_id, 'rank_math_robots' ) ) ) {
return;
}
$current = $this->get_robots_by_hash( $object_id, $object_type );
$is_noindex = in_array( 'noindex', $current, true );
$is_nofollow = in_array( 'nofollow', $current, true );
if ( ! $is_noindex || ! $is_nofollow ) {
$robots = $this->get_default_robots( $object_id, $object_type );
$current[] = ! $is_nofollow && ! empty( $robots['nofollow'] ) ? 'nofollow' : '';
// Keep global no index status.
if ( ! empty( $robots['noindex'] ) ) {
unset( $current['index'] );
$current[] = 'noindex';
}
}
$this->update_meta( $object_type, $object_id, 'rank_math_robots', array_unique( $current ) );
}
/**
* Get by meta hash.
*
* @param int $object_id Object id.
* @param string $object_type Object type.
*
* @return array Array of robots data.
*/
private function get_robots_by_hash( $object_id, $object_type ) {
$current = [];
$hash = [
'_seopress_robots_index' => 'noindex',
'_seopress_robots_follow' => 'nofollow',
'_seopress_robots_imageindex' => 'noimageindex',
'_seopress_robots_archive' => 'noarchive',
'_seopress_robots_snippet' => 'nosnippet',
];
foreach ( $hash as $source => $value ) {
if ( ! empty( $this->get_meta( $object_type, $object_id, $source ) ) ) {
$current[] = $value;
}
}
return $current;
}
/**
* Get default robots data from settings.
*
* @param int $object_id Object id.
* @param string $object_type Object type.
*
* @return array Array of robots data.
*/
private function get_default_robots( $object_id, $object_type ) {
$seopress_titles = get_option( 'seopress_titles_option_name' );
if ( 'post' === $object_type ) {
$post_type = get_post_type( $object_id );
return isset( $seopress_titles['seopress_titles_single_titles'][ $post_type ] ) ? $seopress_titles['seopress_titles_single_titles'][ $post_type ] : [];
}
$term = get_term( $object_id );
return isset( $seopress_titles['seopress_titles_tax_titles'][ $term->taxonomy ] ) ? $seopress_titles['seopress_titles_tax_titles'][ $term->taxonomy ] : [];
}
}

View File

@@ -0,0 +1,137 @@
<?php
/**
* The Status.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin\Importers
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Importers;
defined( 'ABSPATH' ) || exit;
/**
* Status class.
*/
class Status {
/**
* The status.
*
* @var bool
*/
private $status = false;
/**
* The message.
*
* @var string
*/
private $message = '';
/**
* The action being performed.
*
* @var string
*/
private $action;
/**
* Get the status.
*
* @return bool Status.
*/
public function is_success() {
return $this->status;
}
/**
* Get the message.
*
* @return string Status message.
*/
public function get_message() {
if ( '' === $this->message ) {
return $this->get_default_message();
}
return $this->message;
}
/**
* Get the action.
*
* @return string Action type.
*/
public function get_action() {
return $this->action;
}
/**
* Set the status.
*
* @param string $status Status.
*/
public function set_status( $status ) {
$this->status = $status;
}
/**
* Set the message.
*
* @param string $message Status message.
*/
public function set_message( $message ) {
$this->message = $message;
}
/**
* Set the action.
*
* @param string $action Action performing.
*/
public function set_action( $action ) {
$this->action = $action;
}
/**
* Get default message.
*
* @return string
*/
private function get_default_message() {
$hash = [
'settings' => esc_html__( 'Settings imported successfully.', 'rank-math' ),
'news' => esc_html__( 'News Settings imported successfully.', 'rank-math' ),
'video' => esc_html__( 'Video Settings imported successfully.', 'rank-math' ),
'deactivate' => esc_html__( 'Plugin deactivated successfully.', 'rank-math' ),
/* translators: start, end, total */
'postmeta' => esc_html__( 'Imported post meta for posts %1$s - %2$s out of %3$s ', 'rank-math' ),
/* translators: total */
'termmeta' => esc_html__( 'Imported term meta for %s terms.', 'rank-math' ),
/* translators: start, end, total */
'usermeta' => esc_html__( 'Imported user meta for users %1$s - %2$s out of %3$s ', 'rank-math' ),
/* translators: total */
'redirections' => esc_html__( 'Imported %s redirections.', 'rank-math' ),
/* translators: start, end, total */
'blocks' => esc_html__( 'Imported blocks from posts %1$s - %2$s out of %3$s ', 'rank-math' ),
/* translators: start, end, total */
'recalculate' => esc_html__( 'Recalculating scores for posts %1$s - %2$s... ', 'rank-math' ),
];
if ( false === $this->is_success() ) {
$hash = [
'settings' => esc_html__( 'Settings import failed.', 'rank-math' ),
'postmeta' => esc_html__( 'Posts meta import failed.', 'rank-math' ),
'termmeta' => esc_html__( 'Term meta import failed.', 'rank-math' ),
'usermeta' => esc_html__( 'User meta import failed.', 'rank-math' ),
'redirections' => esc_html__( 'There are no redirection to import.', 'rank-math' ),
'blocks' => esc_html__( 'Blocks import failed.', 'rank-math' ),
];
}
return isset( $hash[ $this->get_action() ] ) ? $hash[ $this->get_action() ] : '';
}
}

View File

@@ -0,0 +1,794 @@
<?php
/**
* The WP Schema Pro Import Class
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin\Importers
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Importers;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\Str;
defined( 'ABSPATH' ) || exit;
/**
* WP_Schema_Pro class.
*/
class WP_Schema_Pro extends Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'WP Schema Pro';
/**
* Plugin options meta key.
*
* @var string
*/
protected $meta_key = 'bsf-aiosrs';
/**
* Option keys to import and clean.
*
* @var array
*/
protected $option_keys = [ 'wp-schema-pro-general-settings', 'wp-schema-pro-social-profiles', 'wp-schema-pro-global-schemas' ];
/**
* Choices keys to import.
*
* @var array
*/
protected $choices = [ 'settings', 'postmeta' ];
/**
* Convert Schema Pro variables if needed.
*
* @param string $string Value to convert.
*
* @return string
*/
public function convert_variables( $string ) {
$string = str_replace( 'blogname', '%sitename%', $string );
$string = str_replace( 'blogdescription', '%sitedesc%', $string );
$string = str_replace( 'site_url', get_bloginfo( 'url' ), $string );
$string = str_replace( 'site_logo', get_theme_mod( 'custom_logo' ), $string );
$string = str_replace( 'featured_image', '', $string );
$string = str_replace( 'featured_img', '', $string );
$string = str_replace( 'post_title', '%seo_title%', $string );
$string = str_replace( 'post_excerpt', '%seo_description%', $string );
$string = str_replace( 'post_content', '%seo_description%', $string );
$string = str_replace( 'post_date', '%date%', $string );
$string = str_replace( 'post_modified', '%modified%', $string );
$string = str_replace( 'post_permalink', '', $string );
$string = str_replace( 'author_name', '%name%', $string );
$string = str_replace( 'author_first_name', '%name%', $string );
$string = str_replace( 'author_last_name', '%name%', $string );
$string = str_replace( 'author_image', '', $string );
return $string;
}
/**
* Import settings of plugin.
*
* @return bool
*/
protected function settings() {
$this->get_settings();
$schema_general = get_option( 'wp-schema-pro-general-settings' );
$schema_social = get_option( 'wp-schema-pro-social-profiles' );
$schema_global = get_option( 'wp-schema-pro-global-schemas' );
// Knowledge Graph Logo.
if ( isset( $schema_general['site-logo-custom'] ) ) {
$this->replace_image( $schema_general['site-logo-custom'], $this->titles, 'knowledgegraph_logo', 'knowledgegraph_logo_id' );
}
// General.
$hash = [ 'site-represent' => 'knowledgegraph_type' ];
$has_key = 'person' === $schema_general['site-represent'] ? 'person-name' : 'site-name';
$hash[ $has_key ] = 'knowledgegraph_name';
$this->replace( $hash, $schema_general, $this->titles );
$this->titles['local_seo'] = isset( $schema_general['site-represent'] ) && ! empty( $yoast_titles['site-represent'] ) ? 'on' : 'off';
// Social.
$hash = [
'facebook' => 'social_url_facebook',
'twitter' => 'twitter_author_names',
];
$this->replace( $hash, $schema_social, $this->titles );
// About & Contact Page.
$hash = [
'about-page' => 'local_seo_about_page',
'contact-page' => 'local_seo_contact_page',
];
$this->replace( $hash, $schema_global, $this->titles );
$this->update_settings();
return true;
}
/**
* Import post meta of plugin.
*
* @return array
*/
protected function postmeta() {
$this->set_pagination( $this->get_post_ids( true ) );
foreach ( $this->get_post_ids() as $snippet_post ) {
$post_id = $snippet_post->ID;
$snippet = $this->get_snippet_details( $post_id );
if ( ! $snippet ) {
continue;
}
$this->update_postmeta( $post_id, $snippet );
}
return $this->get_pagination_arg();
}
/**
* Update post meta.
*
* @param int $post_id Post ID.
* @param array $snippet Snippet data.
*/
private function update_postmeta( $post_id, $snippet ) {
$type = $snippet['type'];
$hash = $this->get_schema_types();
if ( ! isset( $hash[ $type ] ) ) {
return;
}
$details = $snippet['details'];
$methods = [
'work-example' => 'get_book_editions',
'steps' => 'get_howto_steps',
'tool' => 'get_howto_tools',
'supply' => 'get_howto_supplies',
'rating' => 'get_rating',
];
$data = [];
foreach ( $hash[ $type ] as $snippet_key => $snippet_value ) {
$method = isset( $methods[ $snippet_key ] ) ? $methods[ $snippet_key ] : 'get_schema_meta';
$value = $this->$method( $details, $snippet_key, $post_id, $snippet, $snippet_value );
$this->validate_schema_data( $data, $value, $snippet_value, $snippet_key );
}
if ( ! empty( $data ) ) {
if ( isset( $data['schema-type'] ) ) {
$type = $data['schema-type'];
unset( $data['schema-type'] );
}
$type = $this->sanitize_schema_type( $type );
$data['@type'] = $type;
$data['metadata'] = [
'title' => Helper::sanitize_schema_title( $type ),
'type' => 'template',
'isPrimary' => 1,
'shortcode' => uniqid( 's-' ),
];
$type = in_array( $type, [ 'BlogPosting', 'NewsArticle' ], true ) ? 'Article' : $type;
update_post_meta( $post_id, 'rank_math_schema_' . $type, $data );
}
}
/**
* Validate schema data.
*
* @param array $data Schema entity data.
* @param string $value Entity value.
* @param string $key Entity key.
* @param string $snippet_key Snippet key.
*/
private function validate_schema_data( &$data, $value, $key, $snippet_key ) {
if ( 'question-answer' === $snippet_key && ! empty( $value ) ) {
foreach ( $value as $question ) {
$data[ $key ][] = [
'@type' => 'Question',
'name' => $question['question'],
'acceptedAnswer' => [
'@type' => 'Answer',
'text' => $question['answer'],
],
];
}
return;
}
if ( ! Str::contains( '.', $key ) ) {
$data[ $key ] = $value;
return;
}
$element = explode( '.', $key );
if ( 2 === count( $element ) ) {
$this->add_type( $data[ $element[0] ], $element[0] );
$data[ $element[0] ][ $element[1] ] = $value;
return;
}
if ( count( $element ) > 2 ) {
$this->add_type( $data[ $element[0] ], $element[0] );
$this->add_type( $data[ $element[0] ][ $element[1] ], $element[1] );
$data[ $element[0] ][ $element[1] ][ $element[2] ] = $value;
}
}
/**
* Add property type.
*
* @param array $data Schema entity data.
* @param string $key Entity key.
*/
private function add_type( &$data, $key ) {
if ( 'location' === $key || 'jobLocation' === $key ) {
$data['@type'] = 'Place';
}
if ( 'address' === $key ) {
$data['@type'] = 'PostalAddress';
}
if ( 'offers' === $key ) {
$data['@type'] = 'Offer';
}
if ( 'brand' === $key ) {
$data['@type'] = 'Brand';
}
if ( 'review' === $key ) {
$data['@type'] = 'Review';
}
if ( 'reviewRating' === $key ) {
$data['@type'] = 'Rating';
}
if ( 'nutrition' === $key ) {
$data['@type'] = 'NutritionInformation';
}
if ( 'baseSalary' === $key ) {
$data['@type'] = 'MonetaryAmount';
}
if ( 'value' === $key ) {
$data['@type'] = 'QuantitativeValue';
}
if ( 'performer' === $key ) {
$data['@type'] = 'Person';
}
if ( 'provider' === $key || 'hiringOrganization' === $key ) {
$data['@type'] = 'Organization';
}
}
/**
* Get ratings value.
*
* @param array $details Array of details.
* @param string $snippet_key Snippet key.
* @param string $post_id Post ID.
* @param array $snippet Snippet data.
* @param string $snippet_value Snippet value.
* @return string
*/
private function get_rating( $details, $snippet_key, $post_id, $snippet, $snippet_value ) {
return get_post_meta( $post_id, 'bsf-schema-pro-rating-' . $snippet['id'], true );
}
/**
* Get post meta for schema plugin
*
* @param array $details Array of details.
* @param string $snippet_key Snippet key.
* @param string $post_id Post ID.
* @param array $snippet Snippet data.
* @param string $snippet_value Snippet value.
* @return string
*/
private function get_schema_meta( $details, $snippet_key, $post_id, $snippet, $snippet_value ) {
$value = isset( $details[ $snippet_key ] ) ? $details[ $snippet_key ] : '';
if ( 'custom-text' === $value ) {
$value = isset( $details[ $snippet_key . '-custom-text' ] ) ? $details[ $snippet_key . '-custom-text' ] : '';
}
if ( 'create-field' === $value ) {
$value = get_post_meta( $post_id, $snippet['type'] . '-' . $snippet['id'] . '-' . $snippet_key, true );
}
if ( 'specific-field' === $value ) {
$key = isset( $details[ $snippet_key . '-specific-field' ] ) ? $details[ $snippet_key . '-specific-field' ] : '';
$value = get_post_meta( $post_id, $key, true );
}
return $this->convert_variables( $value );
}
/**
* Get Book Editions.
*
* @param array $details Array of details.
* @param string $snippet_key Snippet key.
* @param string $post_id Post ID.
* @param array $snippet Snippet data.
* @param string $snippet_value Snippet value.
* @return string
*/
private function get_howto_steps( $details, $snippet_key, $post_id, $snippet, $snippet_value ) {
$steps = get_post_meta( $post_id, "how-to-{$snippet['id']}-steps", true );
if ( empty( $steps ) ) {
return [];
}
$data = [];
foreach ( $steps as $step ) {
$entity = [
'@type' => 'HowToStep',
'name' => $step['name'],
'url' => $step['url'],
];
if ( ! empty( $step['description'] ) ) {
$entity['itemListElement'] = [
'@type' => 'HowToDirection',
'text' => $step['description'],
];
}
if ( ! empty( $step['image'] ) ) {
$entity['image'] = [
'@type' => 'ImageObject',
'text' => wp_get_attachment_url( $step['image'] ),
];
}
$data[] = $entity;
}
return $data;
}
/**
* Get Book Editions.
*
* @param array $details Array of details.
* @param string $snippet_key Snippet key.
* @param string $post_id Post ID.
* @param array $snippet Snippet data.
* @param string $snippet_value Snippet value.
* @return string
*/
private function get_howto_tools( $details, $snippet_key, $post_id, $snippet, $snippet_value ) {
$tools = get_post_meta( $post_id, "how-to-{$snippet['id']}-tool", true );
if ( empty( $tools ) ) {
return [];
}
$data = [];
foreach ( $tools as $tool ) {
$data[] = [
'@type' => 'HowToTool',
'name' => $tool['name'],
];
}
return $data;
}
/**
* Get Book Editions.
*
* @param array $details Array of details.
* @param string $snippet_key Snippet key.
* @param string $post_id Post ID.
* @param array $snippet Snippet data.
* @param string $snippet_value Snippet value.
* @return string
*/
private function get_howto_supplies( $details, $snippet_key, $post_id, $snippet, $snippet_value ) {
$supplies = get_post_meta( $post_id, "how-to-{$snippet['id']}-supply", true );
if ( empty( $supplies ) ) {
return [];
}
$data = [];
foreach ( $supplies as $supply ) {
$data[] = [
'@type' => 'HowToSupply',
'name' => $supply['name'],
];
}
return $data;
}
/**
* Get Book Editions.
*
* @param array $details Array of details.
* @param string $snippet_key Snippet key.
* @param string $post_id Post ID.
* @param array $snippet Snippet data.
* @param string $snippet_value Snippet value.
* @return string
*/
private function get_book_editions( $details, $snippet_key, $post_id, $snippet, $snippet_value ) {
if ( empty( $details[ $snippet_key ] ) ) {
return '';
}
$editions = [];
$data = [
'details' => $details,
'snippet_key' => $snippet_key,
'post_id' => $post_id,
'snippet' => $snippet,
'snippet_value' => $snippet_value,
];
foreach ( $details[ $snippet_key ] as $key => $edition ) {
$editions[] = [
'book_edition' => $this->normalize_edition( $key . '-book-edition', $edition['book-edition'], $data ),
'isbn' => $this->normalize_edition( $key . '-serial-number', $edition['serial-number'], $data ),
'url' => $this->normalize_edition( $key . '-url-template', $edition['url-template'], $data ),
'book_format' => $this->normalize_edition( $key . '-book-format', $edition['book-format'], $data ),
];
}
return $editions;
}
/**
* Normalize Book Edition.
*
* @param string $key Custom field key.
* @param string $value Custom field value.
* @param array $data Snippet data.
* @return string
*/
private function normalize_edition( $key, $value, $data ) {
if ( ! $value ) {
return '';
}
$hash = [
'custom-text' => 'get_custom_text',
'create-field' => 'get_created_field',
'specific-field' => 'get_specific_field',
];
if ( isset( $hash[ $value ] ) ) {
$method = $hash[ $value ];
$value = $this->$method( $key, $value, $data );
}
return $this->convert_variables( $value );
}
/**
* Get Custom Text added in the Settings.
*
* @param string $key Custom field key.
* @param string $value Custom field value.
* @param array $data Snippet data.
* @return string
*/
private function get_custom_text( $key, $value, $data ) {
$key = $data['snippet_key'] . '-custom-text';
return isset( $data['details'][ $key ] ) ? $data['details'][ $key ] : '';
}
/**
* Get Created field value added in the post metabox.
*
* @param string $key Custom field key.
* @param string $value Custom field value.
* @param array $data Snippet data.
* @return string
*/
private function get_created_field( $key, $value, $data ) {
$meta_key = $data['snippet']['type'] . '-' . $data['snippet']['id'] . '-' . $data['snippet_key'] . '-' . $key;
return get_post_meta( $data['post_id'], $meta_key, true );
}
/**
* Get Specific Custom field value.
*
* @param string $key Custom field key.
* @param string $value Custom field value.
* @param array $data Snippet data.
* @return string
*/
private function get_specific_field( $key, $value, $data ) {
$key = isset( $data['details'][ $data[ $snippet_key . '-specific-field' ] ] ) ? $data['details'][ $data[ $snippet_key . '-specific-field' ] ] : '';
return get_post_meta( $data['post_id'], $key, true );
}
/**
* Sanitize schema type before saving
*
* @param string $type Schema type to sanitize.
* @return string
*/
private function sanitize_schema_type( $type ) {
$hash = [
'job-posting' => 'JobPosting',
'video-object' => 'VideoObject',
'software-application' => 'SoftwareApplication',
'faq' => 'FAQPage',
'how-to' => 'HowTo',
];
$type = in_array( $type, [ 'AdvertiserContentArticle', 'Report', 'SatiricalArticle', 'ScholarlyArticle', 'TechArticle' ], true )
? 'Article'
: $type;
return isset( $hash[ $type ] ) ? $hash[ $type ] : ucfirst( $type );
}
/**
* Get Snippet Details stored in aiosrs-schema posts
*
* @param int $post_id Post ID.
* @return array
*/
private function get_snippet_details( $post_id ) {
global $wpdb;
$post_type = addcslashes( get_post_type( $post_id ), '_' );
$query = "SELECT p.ID, pm.meta_value FROM {$wpdb->postmeta} as pm
INNER JOIN {$wpdb->posts} as p ON pm.post_id = p.ID
WHERE pm.meta_key = 'bsf-aiosrs-schema-location'
AND p.post_type = 'aiosrs-schema'
AND p.post_status = 'publish'";
$orderby = ' ORDER BY p.post_date DESC LIMIT 1';
$meta_args = "pm.meta_value LIKE '%\"basic-global\"%'";
$meta_args .= " OR pm.meta_value LIKE '%\"basic-singulars\"%'";
$meta_args .= " OR pm.meta_value LIKE '%\"{$post_type}|all\"%'";
$meta_args .= " OR pm.meta_value LIKE '%\"post-{$post_id}\"%'";
$local_posts = $wpdb->get_col( $query . ' AND (' . $meta_args . ')' . $orderby ); // phpcs:ignore
if ( empty( $local_posts ) ) {
return false;
}
$current_page_data = [];
foreach ( $local_posts as $local_post ) {
$snippet_type = get_post_meta( $local_post, 'bsf-aiosrs-schema-type', true );
return [
'id' => $local_post,
'type' => $snippet_type,
'details' => get_post_meta( $local_post, 'bsf-aiosrs-' . $snippet_type, true ),
];
}
}
/**
* Get the actions which can be performed for the plugin.
*
* @return array
*/
public function get_choices() {
return [
'settings' => esc_html__( 'Import Settings', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Plugin settings and site-wide meta data.', 'rank-math' ) ),
'postmeta' => esc_html__( 'Import Schemas', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import all Schema data for Posts, Pages, and custom post types.', 'rank-math' ) ),
];
}
/**
* Get schema types
*
* @return array
*/
private function get_schema_types() {
return [
'event' => $this->get_event_fields(),
'job-posting' => $this->get_job_posting_fields(),
'product' => $this->get_product_fields(),
'recipe' => $this->get_recipe_fields(),
'software-application' => $this->get_software_fields(),
'video-object' => $this->get_video_fields(),
'article' => [
'name' => 'headline',
'description' => 'description',
'schema-type' => 'schema-type',
],
'book' => [
'name' => 'name',
'url' => 'url',
'author' => 'author.name',
'work-example' => 'book_editions',
'rating' => 'review.reviewRating.ratingValue',
],
'course' => [
'name' => 'name',
'description' => 'description',
'orgnization-name' => 'provider.name',
'same-as' => 'provider.sameAs',
'rating' => 'review.reviewRating.ratingValue',
],
'person' => [
'name' => 'name',
'email' => 'email',
'gender' => 'gender',
'job-title' => 'jobTitle',
'street' => 'address.streetAddress',
'locality' => 'address.addressLocality',
'region' => 'address.addressRegion',
'postal' => 'address.postalCode',
'country' => 'address.addressCountry',
],
'service' => [
'name' => 'name',
'description' => 'description',
'type' => 'serviceType',
'price-range' => 'offers.price',
],
'faq' => [
'question-answer' => 'mainEntity',
],
'how-to' => [
'name' => 'name',
'description' => 'description',
'total-time' => 'totalTime',
'steps' => 'step',
'supply' => 'supply',
'tool' => 'tool',
],
];
}
/**
* Get event fields.
*
* @return array
*/
private function get_event_fields() {
return [
'name' => 'name',
'description' => 'description',
'schema-type' => 'schema-type',
'event-status' => 'eventStatus',
'event-attendance-mode' => 'eventAttendanceMode',
'start-date' => 'startDate',
'end-date' => 'endDate',
'location' => 'location.name',
'location-street' => 'location.address.streetAddress',
'location-locality' => 'location.address.addressLocality',
'location-region' => 'location.address.addressRegion',
'location-postal' => 'location.address.postalCode',
'location-country' => 'location.address.addressCountry',
'ticket-buy-url' => 'offers.url',
'price' => 'offers.price',
'currency' => 'offers.priceCurrency',
'avail' => 'offers.availability',
'performer' => 'performer.name',
'rating' => 'review.reviewRating.ratingValue',
];
}
/**
* Get job_posting fields.
*
* @return array
*/
private function get_job_posting_fields() {
return [
'title' => 'title',
'description' => 'description',
'job-type' => 'employmentType',
'start-date' => 'datePosted',
'expiry-date' => 'validThrough',
'orgnization-name' => 'hiringOrganization.name',
'same-as' => 'hiringOrganization.sameAs',
'organization-logo' => 'hiringOrganization.logo',
'location-street' => 'jobLocation.address.streetAddress',
'location-locality' => 'jobLocation.address.addressLocality',
'location-region' => 'jobLocation.address.addressRegion',
'location-postal' => 'jobLocation.address.postalCode',
'location-country' => 'jobLocation.address.addressCountry',
'salary' => 'baseSalary.value.value',
'salary-currency' => 'baseSalary.currency',
'salary-unit' => 'baseSalary.value.unitText',
];
}
/**
* Get product fields.
*
* @return array
*/
private function get_product_fields() {
return [
'name' => 'name',
'description' => 'description',
'sku' => 'sku',
'brand-name' => 'brand.name',
'price' => 'offers.price',
'currency' => 'offers.priceCurrency',
'avail' => 'offers.availability',
'price-valid-until' => 'offers.priceValidUntil',
'rating' => 'review.reviewRating.ratingValue',
];
}
/**
* Get recipe fields.
*
* @return array
*/
private function get_recipe_fields() {
return [
'name' => 'name',
'description' => 'description',
'recipe-category' => 'recipeCategory',
'recipe-cuisine' => 'recipeCuisine',
'recipe-yield' => 'recipeYield',
'recipe-keywords' => 'keywords',
'nutrition' => 'nutrition.calories',
'preperation-time' => 'prepTime',
'cook-time' => 'cookTime',
'ingredients' => 'recipeIngredient',
'rating' => 'review.reviewRating.ratingValue',
];
}
/**
* Get software fields.
*
* @return array
*/
private function get_software_fields() {
return [
'name' => 'name',
'rating' => 'review.reviewRating.ratingValue',
'price' => 'offers.price',
'currency' => 'offers.priceCurrency',
'operating-system' => 'operatingSystem',
'category' => 'applicationCategory',
];
}
/**
* Get video fields.
*
* @return array
*/
private function get_video_fields() {
return [
'name' => 'name',
'description' => 'description',
'content-url' => 'contentUrl',
'embed-url' => 'embedUrl',
'duration' => 'duration',
'rating' => 'review.reviewRating.ratingValue',
];
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -0,0 +1,375 @@
<?php
/**
* The metabox functionality of the plugin.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin\Metabox
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Metabox;
use RankMath\CMB2;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Metabox class.
*/
class Metabox implements Runner {
use Hooker;
/**
* Metabox id.
*
* @var string
*/
private $metabox_id = 'rank_math_metabox';
/**
* Screen object.
*
* @var Screen
*/
private $screen;
/**
* Register hooks.
*/
public function hooks() {
if ( $this->dont_load() ) {
return;
}
$this->screen = new Screen();
if ( $this->screen->is_loaded() ) {
$this->action( 'cmb2_admin_init', 'add_main_metabox', 30 );
$this->action( 'rank_math/admin/enqueue_scripts', 'enqueue' );
if ( Helper::has_cap( 'link_builder' ) ) {
$this->action( 'cmb2_admin_init', 'add_link_suggestion_metabox', 30 );
}
}
$this->action( 'cmb2_' . CMB2::current_object_type() . '_process_fields_' . $this->metabox_id, 'save_meta' );
$this->action( 'cmb2_save_field', 'invalidate_facebook_object_cache', 10, 4 );
}
/**
* Enqueue styles and scripts for the metabox.
*/
public function enqueue() {
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts before plugin assets.
*/
$this->do_action( 'admin/before_editor_scripts' );
$screen = get_current_screen();
$js = rank_math()->plugin_url() . 'assets/admin/js/';
$this->enqueue_commons();
$this->screen->enqueue();
$this->screen->localize();
$this->enqueue_translation();
rank_math()->variables->setup_json();
$is_gutenberg = Helper::is_block_editor() && \rank_math_is_gutenberg();
$is_elementor = 'elementor' === Param::get( 'action' );
Helper::add_json( 'knowledgegraphType', Helper::get_settings( 'titles.knowledgegraph_type' ) );
if (
! $is_gutenberg &&
! $is_elementor &&
'rank_math_schema' !== $screen->post_type &&
'edit-tags' !== $screen->base
) {
\CMB2_Hookup::enqueue_cmb_css();
wp_enqueue_style(
'rank-math-metabox',
rank_math()->plugin_url() . 'assets/admin/css/metabox.css',
[
'rank-math-common',
'rank-math-cmb2',
'rank-math-editor',
'wp-components',
],
rank_math()->version
);
wp_enqueue_media();
wp_enqueue_script(
'rank-math-editor',
rank_math()->plugin_url() . 'assets/admin/js/classic.js',
[
'clipboard',
'wp-hooks',
'moment',
'wp-date',
'wp-data',
'wp-api-fetch',
'wp-components',
'wp-element',
'wp-i18n',
'wp-url',
'wp-media-utils',
'rank-math-common',
'rank-math-analyzer',
'wp-block-editor',
'rank-math-app',
],
rank_math()->version,
true
);
}
$this->do_action( 'enqueue_scripts/assessor' );
/**
* Allow other plugins to enqueue/dequeue admin styles or scripts after plugin assets.
*/
$this->do_action( 'admin/editor_scripts' );
}
/**
* Enqueque scripts common for all builders.
*/
private function enqueue_commons() {
wp_register_style( 'rank-math-editor', rank_math()->plugin_url() . 'assets/admin/css/gutenberg.css', [ 'rank-math-common' ], rank_math()->version );
wp_register_script( 'rank-math-analyzer', rank_math()->plugin_url() . 'assets/admin/js/analyzer.js', [ 'lodash', 'wp-autop', 'wp-wordcount' ], rank_math()->version, true );
}
/**
* Enqueue translation.
*/
private function enqueue_translation() {
if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( 'rank-math-analyzer', 'rank-math', rank_math()->plugin_dir() . 'languages/' );
wp_set_script_translations( 'rank-math-app', 'rank-math', rank_math()->plugin_dir() . 'languages/' );
}
}
/**
* Add main metabox.
*/
public function add_main_metabox() {
if ( $this->can_add_metabox() ) {
return;
}
$cmb = $this->create_metabox();
$cmb->add_field(
[
'id' => 'setting-panel-container-' . $this->metabox_id,
'type' => 'meta_tab_container_open',
'tabs' => [],
]
);
$cmb->add_field(
[
'id' => 'rank_math_metabox_wrapper',
'type' => 'raw',
'content' => '<div id="rank-math-metabox-wrapper"></div>',
'save_field' => false,
]
);
/**
* Allow disabling the primary term feature.
*
* @param bool $return True to disable.
*/
if ( false === apply_filters_deprecated( 'rank_math/primary_term', [ false ], '1.0.43', 'rank_math/admin/disable_primary_term' )
&& false === $this->do_filter( 'admin/disable_primary_term', false ) ) {
$taxonomies = Helper::get_object_taxonomies( Helper::get_post_type(), 'objects' );
$taxonomies = wp_filter_object_list( $taxonomies, [ 'hierarchical' => true ], 'and', 'name' );
foreach ( $taxonomies as $taxonomy ) {
$cmb->add_field(
[
'id' => 'rank_math_primary_' . $taxonomy,
'type' => 'hidden',
'default' => 0,
'attributes' => [
'data-primary-term' => $taxonomy,
],
]
);
}
}
$cmb->add_field(
[
'id' => 'setting-panel-container-close-' . $this->metabox_id,
'type' => 'tab_container_close',
]
);
CMB2::pre_init( $cmb );
}
/**
* Add link suggestion metabox.
*/
public function add_link_suggestion_metabox() {
$allowed_post_types = [];
foreach ( Helper::get_accessible_post_types() as $post_type ) {
if ( false === Helper::get_settings( 'titles.pt_' . $post_type . '_link_suggestions' ) ) {
continue;
}
$allowed_post_types[] = $post_type;
}
// Early bail.
if ( empty( $allowed_post_types ) ) {
return;
}
$cmb = new_cmb2_box(
[
'id' => $this->metabox_id . '_link_suggestions',
'title' => esc_html__( 'Link Suggestions', 'rank-math' ),
'object_types' => $allowed_post_types,
'context' => 'side',
'priority' => 'default',
]
);
$cmb->add_field(
[
'id' => $this->metabox_id . '_link_suggestions_tooltip',
'type' => 'raw',
'content' => '<div id="rank-math-link-suggestions-tooltip" class="hidden">' . Admin_Helper::get_tooltip( esc_html__( 'Click on the button to copy URL or insert link in content. You can also drag and drop links in the post content.', 'rank-math' ) ) . '</div>',
]
);
$cmb->add_field(
[
'id' => 'rank_math_social_tabs',
'type' => 'raw',
'file' => rank_math()->includes_dir() . 'metaboxes/link-suggestions.php',
'not_found' => '<em><small>' . esc_html__( 'We can\'t show any link suggestions for this post. Try selecting categories and tags for this post, and mark other posts as Pillar Content to make them show up here.', 'rank-math' ) . '</small></em>',
]
);
CMB2::pre_init( $cmb );
}
/**
* Save post meta handler.
*
* @param CMB2 $cmb CMB2 metabox object.
*/
public function save_meta( $cmb ) {
/**
* Hook into save handler for main metabox.
*
* @param CMB2 $cmb CMB2 object.
*/
$this->do_action( 'metabox/process_fields', $cmb );
}
/**
* Invalidate facebook object cache for the post.
*
* @param string $field_id The current field id paramater.
* @param bool $updated Whether the metadata update action occurred.
* @param string $action Action performed. Could be "repeatable", "updated", or "removed".
* @param CMB2_Field $field This field object.
*/
public function invalidate_facebook_object_cache( $field_id, $updated, $action, $field ) {
// Early Bail!
if ( ! in_array( $field_id, [ 'rank_math_facebook_title', 'rank_math_facebook_image', 'rank_math_facebook_description' ], true ) || ! $updated ) {
return;
}
$app_id = Helper::get_settings( 'titles.facebook_app_id' );
$secret = Helper::get_settings( 'titles.facebook_secret' );
// Early bail!
if ( ! $app_id || ! $secret ) {
return;
}
wp_remote_post(
'https://graph.facebook.com/',
[
'body' => [
'id' => get_permalink( $field->object_id() ),
'scrape' => true,
'access_token' => $app_id . '|' . $secret,
],
]
);
}
/**
* Create metabox
*
* @return CMB2
*/
private function create_metabox() {
return new_cmb2_box(
[
'id' => $this->metabox_id,
'title' => esc_html__( 'Rank Math SEO', 'rank-math' ),
'object_types' => $this->screen->get_object_types(),
'taxonomies' => Helper::get_allowed_taxonomies(),
'new_term_section' => false,
'new_user_section' => 'add-existing-user',
'context' => 'normal',
'priority' => $this->get_priority(),
'cmb_styles' => false,
'classes' => 'rank-math-metabox-wrap' . ( Admin_Helper::is_term_profile_page() ? ' rank-math-metabox-frame postbox' : '' ),
'mb_callback_args' => [ '__back_compat_meta_box' => \rank_math_is_gutenberg() ],
]
);
}
/**
* Get metabox priority
*
* @return string
*/
private function get_priority() {
$post_type = Param::get( 'post_type' );
if ( ! $post_type ) {
$post_type = get_post_type( Param::get( 'post', 0, FILTER_VALIDATE_INT ) );
}
$priority = 'product' === $post_type ? 'default' : 'high';
/**
* Filter: Change metabox priority.
*/
return $this->do_filter( 'metabox/priority', $priority );
}
/**
* Can add metabox
*
* @return bool
*/
private function can_add_metabox() {
return ! Helper::has_cap( 'onpage_general' ) &&
! Helper::has_cap( 'onpage_advanced' ) &&
! Helper::has_cap( 'onpage_snippet' ) &&
! Helper::has_cap( 'onpage_social' );
}
/**
* Can load metabox.
*
* @return bool
*/
private function dont_load() {
return Helper::is_heartbeat() || Helper::is_ajax() ||
( class_exists( 'Vc_Manager' ) && Param::get( 'vc_action' ) ) ||
is_network_admin();
}
}

View File

@@ -0,0 +1,444 @@
<?php
/**
* The post metabox screen.
*
* @since 1.0.25
* @package RankMath
* @subpackage RankMath\Admin\Metabox
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Metabox;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Editor;
use RankMath\Frontend_SEO_Score;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\Str;
use RankMath\Helpers\Url;
defined( 'ABSPATH' ) || exit;
/**
* Post metabox class.
*/
class Post_Screen implements IScreen {
use Hooker;
/**
* Hold primary taxonomy
*
* @var object
*/
private $primary_taxonomy = null;
/**
* Class construct
*/
public function __construct() {
$this->filter( 'rank_math/researches/tests', 'remove_tests', 10, 2 );
}
/**
* Get object id
*
* @return int
*/
public function get_object_id() {
global $post;
return $post->ID;
}
/**
* Get object type
*
* @return string
*/
public function get_object_type() {
return 'post';
}
/**
* Get object types to register metabox to
*
* @return array
*/
public function get_object_types() {
return Helper::get_allowed_post_types();
}
/**
* Enqueue Styles and Scripts required for screen.
*/
public function enqueue() {
$is_elementor = Helper::is_elementor_editor();
$is_block_editor = Helper::is_block_editor() && \rank_math_is_gutenberg();
Helper::add_json( 'postType', get_post_type() );
if ( ! $is_elementor ) {
$this->enqueue_custom_fields();
}
wp_register_script(
'rank-math-formats',
rank_math()->plugin_url() . 'assets/admin/js/gutenberg-formats.js',
[],
rank_math()->version,
true
);
if ( $is_block_editor || $is_elementor ) {
$this->enqueue_commons();
}
if ( $is_block_editor && ! $is_elementor && Editor::can_add_editor() ) {
$this->enqueue_for_gutenberg();
return;
}
if ( $is_elementor ) {
return;
}
// Classic.
if ( Helper::is_block_editor() ) {
wp_enqueue_script( 'rank-math-formats' );
}
if ( $is_block_editor ) {
wp_enqueue_script( 'rank-math-primary-term', rank_math()->plugin_url() . 'assets/admin/js/gutenberg-primary-term.js', [], rank_math()->version, true );
}
}
/**
* Get values for localize.
*
* @return array
*/
public function get_values() {
$post_type = $this->get_current_post_type();
return [
'parentDomain' => Url::get_domain( home_url() ),
'noFollowDomains' => Str::to_arr_no_empty( Helper::get_settings( 'general.nofollow_domains' ) ),
'noFollowExcludeDomains' => Str::to_arr_no_empty( Helper::get_settings( 'general.nofollow_exclude_domains' ) ),
'noFollowExternalLinks' => Helper::get_settings( 'general.nofollow_external_links' ),
'featuredImageNotice' => esc_html__( 'The featured image should be at least 200 by 200 pixels to be picked up by Facebook and other social media sites.', 'rank-math' ),
'pluginReviewed' => $this->plugin_reviewed(),
'postSettings' => [
'linkSuggestions' => Helper::get_settings( 'titles.pt_' . $post_type . '_link_suggestions' ),
'useFocusKeyword' => 'focus_keywords' === Helper::get_settings( 'titles.pt_' . $post_type . '_ls_use_fk' ),
],
'frontEndScore' => Frontend_SEO_Score::show_on(),
'postName' => get_post_field( 'post_name', get_post() ),
'permalinkFormat' => $this->get_permalink_format(),
'assessor' => [
'focusKeywordLink' => admin_url( 'edit.php?focus_keyword=%focus_keyword%&post_type=%post_type%' ),
'hasTOCPlugin' => $this->has_toc_plugin(),
'primaryTaxonomy' => $this->get_primary_taxonomy(),
],
];
}
/**
* Get object values for localize
*
* @return array
*/
public function get_object_values() {
global $post;
return [
'primaryTerm' => $this->get_primary_term_id(),
'authorName' => get_the_author_meta( 'display_name', $post->post_author ),
'titleTemplate' => Helper::get_settings( "titles.pt_{$post->post_type}_title", '%title% %sep% %sitename%' ),
'descriptionTemplate' => Helper::get_settings( "titles.pt_{$post->post_type}_description", '' ),
'showScoreFrontend' => ! Helper::get_post_meta( 'dont_show_seo_score', $this->get_object_id() ),
];
}
/**
* Get analysis to run.
*
* @return array
*/
public function get_analysis() {
$tests = [
'contentHasTOC' => true,
'contentHasShortParagraphs' => true,
'contentHasAssets' => true,
'keywordInTitle' => true,
'keywordInMetaDescription' => true,
'keywordInPermalink' => true,
'keywordIn10Percent' => true,
'keywordInContent' => true,
'keywordInSubheadings' => true,
'keywordInImageAlt' => true,
'keywordDensity' => true,
'keywordNotUsed' => true,
'lengthContent' => true,
'lengthPermalink' => true,
'linksHasInternal' => true,
'linksHasExternals' => true,
'linksNotAllExternals' => true,
'titleStartWithKeyword' => true,
'titleSentiment' => true,
'titleHasPowerWords' => true,
'titleHasNumber' => true,
'hasContentAI' => true,
];
return $tests;
}
/**
* Remove few tests on static Homepage.
*
* @since 1.0.42
*
* @param array $tests Array of tests with score.
* @param string $type Object type. Can be post, user or term.
*/
public function remove_tests( $tests, $type ) {
if ( ! Admin_Helper::is_home_page() && ! Admin_Helper::is_posts_page() ) {
return $tests;
}
return array_diff_assoc( $tests, $this->exclude_tests() );
}
/**
* Function to get the permalink format.
*
* @since 1.0.69.2
*/
private function get_permalink_format() {
$post_id = $this->get_object_id();
$post = get_post( $post_id );
if ( 'attachment' === $post->post_type ) {
return str_replace( $post->post_name, '%postname%', get_permalink( $post ) );
}
if ( 'auto-draft' !== $post->post_status || 'post' !== $post->post_type ) {
$sample_permalink = get_sample_permalink( $post_id, null, null );
return isset( $sample_permalink[0] ) ? $sample_permalink[0] : home_url();
}
$post_temp = $post;
$post_temp->post_status = 'publish';
return get_permalink( $post_temp, true );
}
/**
* Tests to exclude on Homepage and Blog page.
*
* @since 1.0.43
*
* @return array Array of excluded tests.
*/
private function exclude_tests() {
if ( Admin_Helper::is_home_page() ) {
return [
'contentHasTOC' => true,
'keywordInPermalink' => true,
'lengthPermalink' => true,
'linksHasExternals' => true,
'linksNotAllExternals' => true,
'titleSentiment' => true,
'titleHasPowerWords' => true,
'titleHasNumber' => true,
];
}
return [
'contentHasTOC' => true,
'contentHasShortParagraphs' => true,
'keywordIn10Percent' => true,
'keywordInContent' => true,
'keywordInSubheadings' => true,
'keywordDensity' => true,
'lengthContent' => true,
'linksHasInternal' => true,
'linksHasExternals' => true,
'linksNotAllExternals' => true,
];
}
/**
* Enqueque scripts common for all builders.
*/
private function enqueue_commons() {
wp_register_style( 'rank-math-editor', rank_math()->plugin_url() . 'assets/admin/css/gutenberg.css', [], rank_math()->version );
}
/**
* Enqueue script to analyze custom fields data.
*/
private function enqueue_custom_fields() {
global $post;
$custom_fields = Str::to_arr_no_empty( Helper::get_settings( 'titles.pt_' . $post->post_type . '_analyze_fields' ) );
if ( empty( $custom_fields ) ) {
return;
}
$file = Helper::is_block_editor() ? 'glue-custom-fields.js' : 'custom-fields.js';
wp_enqueue_script( 'rank-math-custom-fields', rank_math()->plugin_url() . 'assets/admin/js/' . $file, [ 'wp-hooks', 'rank-math-analyzer' ], rank_math()->version, true );
Helper::add_json( 'analyzeFields', $custom_fields );
}
/**
* Enqueue scripts for gutenberg screen.
*/
private function enqueue_for_gutenberg() {
wp_enqueue_style( 'rank-math-editor' );
wp_enqueue_script( 'rank-math-formats' );
wp_enqueue_script(
'rank-math-editor',
rank_math()->plugin_url() . 'assets/admin/js/gutenberg.js',
[
'clipboard',
'wp-autop',
'wp-blocks',
'wp-components',
'wp-editor',
'wp-edit-post',
'wp-element',
'wp-i18n',
'wp-plugins',
'wp-wordcount',
'rank-math-analyzer',
'rank-math-app',
],
rank_math()->version,
true
);
}
/**
* Get current post type.
*
* @return string
*/
private function get_current_post_type() {
$post_type = get_post_type();
if ( function_exists( 'get_current_screen' ) ) {
$screen = get_current_screen();
$post_type = isset( $screen->post_type ) ? $screen->post_type : $post_type;
}
return $post_type;
}
/**
* Check if any TOC plugin detected
*
* @return bool
*/
private function has_toc_plugin() {
if ( \defined( 'ELEMENTOR_PRO_VERSION' ) ) {
return true;
}
$plugins_found = [];
$active_plugins = get_option( 'active_plugins' );
$active_plugins = is_multisite() ? array_merge( $active_plugins, array_keys( get_site_option( 'active_sitewide_plugins', [] ) ) ) : $active_plugins;
/**
* Allow developers to add plugins to the TOC list.
*
* @param array TOC plugins.
*/
$toc_plugins = $this->do_filter(
'researches/toc_plugins',
[
'wp-shortcode/wp-shortcode.php' => 'WP Shortcode by RankMath',
'wp-shortcode-pro/wp-shortcode-pro.php' => 'WP Shortcode Pro by RankMath',
]
);
foreach ( $toc_plugins as $plugin_slug => $plugin_name ) {
if ( in_array( $plugin_slug, $active_plugins, true ) !== false ) {
$plugins_found[ $plugin_slug ] = $plugin_name;
}
}
return empty( $plugins_found ) ? false : $plugins_found;
}
/**
* Plugin already reviewed.
*
* @return bool
*/
private function plugin_reviewed() {
return get_option( 'rank_math_already_reviewed' ) || current_time( 'timestamp' ) < get_option( 'rank_math_install_date' ) + ( 2 * WEEK_IN_SECONDS );
}
/**
* Get primary taxonomy.
*
* @return bool|array
*/
private function get_primary_taxonomy() {
if ( ! is_null( $this->primary_taxonomy ) ) {
return $this->primary_taxonomy;
}
$taxonomy = false;
$post_type = $this->get_current_post_type();
/**
* Filter: Allow disabling the primary term feature.
* 'rank_math/primary_term' is deprecated,
* use 'rank_math/admin/disable_primary_term' instead.
*
* @param bool $return True to disable.
*/
if ( false === apply_filters_deprecated( 'rank_math/primary_term', [ false ], '1.0.43', 'rank_math/admin/disable_primary_term' )
&& false === $this->do_filter( 'admin/disable_primary_term', false ) ) {
$taxonomy = Helper::get_settings( 'titles.pt_' . $post_type . '_primary_taxonomy', false );
}
if ( ! $taxonomy ) {
return false;
}
$taxonomy = get_taxonomy( $taxonomy );
if ( empty( $taxonomy ) ) {
return false;
}
$this->primary_taxonomy = [
'title' => $taxonomy->labels->singular_name,
'name' => $taxonomy->name,
'singularLabel' => $taxonomy->labels->singular_name,
'restBase' => ( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name,
];
return $this->primary_taxonomy;
}
/**
* Get primary term ID.
*
* @return int
*/
private function get_primary_term_id() {
$taxonomy = $this->get_primary_taxonomy();
if ( ! $taxonomy ) {
return 0;
}
$id = Helper::get_post_meta( 'primary_' . $taxonomy['name'], $this->get_object_id() );
return $id ? absint( $id ) : 0;
}
}

View File

@@ -0,0 +1,358 @@
<?php
/**
* Metabox localization methods.
*
* @since 1.0.33
* @package RankMath
* @subpackage RankMath\Admin\Metabox
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Metabox;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Traits\Meta;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Locale;
use RankMath\Admin\Admin_Helper;
use RankMath\Helpers\Url;
defined( 'ABSPATH' ) || exit;
/**
* Screen.
*/
class Screen implements IScreen {
use Meta;
use Hooker;
/**
* Current screen object.
*
* @var IScreen
*/
private $screen = null;
/**
* Class construct
*/
public function __construct() {
$this->load_screen();
}
/**
* Is creen loaded.
*
* @return bool
*/
public function is_loaded() {
return ! is_null( $this->screen );
}
/**
* Get object id
*
* @return int
*/
public function get_object_id() {
return $this->screen->get_object_id();
}
/**
* Get object type
*
* @return string
*/
public function get_object_type() {
return $this->screen->get_object_type();
}
/**
* Get object types to register metabox to
*
* @return array
*/
public function get_object_types() {
return $this->screen->get_object_types();
}
/**
* Enqueue Styles and Scripts required for screen.
*/
public function enqueue() {
$this->screen->enqueue();
}
/**
* Get analysis to run.
*
* @return array
*/
public function get_analysis() {
$analyses = $this->do_filter(
'researches/tests',
$this->screen->get_analysis(),
$this->screen->get_object_type()
);
return array_keys( $analyses );
}
/**
* Get values for localize.
*/
public function localize() {
$values = $this->get_values();
if ( empty( $values ) ) {
return;
}
foreach ( $values as $key => $value ) {
Helper::add_json( $key, $value );
}
}
/**
* Get common values.
*
* @return array
*/
public function get_values() {
$editor = Helper::get_current_editor();
$trends_link = KB::get( 'pro', 'CE General Tab Trends' );
if ( 'gutenberg' === $editor ) {
$trends_link = KB::get( 'pro', 'Gutenberg General Tab Trends' );
} elseif ( 'elementor' === $editor ) {
$trends_link = KB::get( 'pro', 'Elementor General Tab Trends' );
}
$values = array_merge_recursive(
$this->screen->get_values(),
[
'homeUrl' => home_url(),
'objectID' => $this->get_object_id(),
'objectType' => $this->get_object_type(),
'locale' => Locale::get_site_language(),
'localeFull' => get_locale(),
'overlayImages' => Helper::choices_overlay_images(),
'defautOgImage' => Helper::get_settings( 'titles.open_graph_image', rank_math()->plugin_url() . 'assets/admin/img/social-placeholder.jpg' ),
'customPermalinks' => (bool) get_option( 'permalink_structure', false ),
'isUserRegistered' => Helper::is_site_connected(),
'autoSuggestKeywords' => Helper::is_site_connected(),
'connectSiteUrl' => Admin_Helper::get_activate_url( Url::get_current_url() ),
'maxTags' => $this->do_filter( 'focus_keyword/maxtags', 5 ),
'trendsIcon' => Admin_Helper::get_trends_icon_svg(),
'showScore' => Helper::is_score_enabled(),
'siteFavIcon' => $this->get_site_icon(),
'canUser' => [
'general' => Helper::has_cap( 'onpage_general' ),
'advanced' => Helper::has_cap( 'onpage_advanced' ) && Helper::is_advanced_mode(),
'snippet' => Helper::has_cap( 'onpage_snippet' ),
'social' => Helper::has_cap( 'onpage_social' ),
'analysis' => Helper::has_cap( 'onpage_analysis' ),
'analytics' => Helper::has_cap( 'analytics' ),
'content_ai' => Helper::has_cap( 'content_ai' ),
],
'assessor' => [
'serpData' => $this->get_object_values(),
'powerWords' => $this->power_words(),
'diacritics' => $this->diacritics(),
'researchesTests' => $this->get_analysis(),
'hasRedirection' => Helper::is_module_active( 'redirections' ),
'hasBreadcrumb' => Helper::is_breadcrumbs_enabled(),
],
'isPro' => defined( 'RANK_MATH_PRO_FILE' ),
'is_front_page' => Admin_Helper::is_home_page(),
'trendsUpgradeLink' => esc_url_raw( $trends_link ),
'trendsUpgradeLabel' => esc_html__( 'Upgrade', 'rank-math' ),
'trendsPreviewImage' => esc_url( rank_math()->plugin_url() . 'assets/admin/img/trends-preview.jpg' ),
'currentEditor' => $editor,
]
);
$values = $this->do_filter( 'metabox/values', $values, $this );
return $this->do_filter( 'metabox/' . $this->get_object_type() . '/values', $values, $this );
}
/**
* Get object values for localize
*
* @return array
*/
public function get_object_values() {
$keys = $this->do_filter(
'metabox/' . $this->get_object_type() . '/meta_keys',
[
'title' => 'title',
'description' => 'description',
'focusKeywords' => 'focus_keyword',
'pillarContent' => 'pillar_content',
'canonicalUrl' => 'canonical_url',
'breadcrumbTitle' => 'breadcrumb_title',
'advancedRobots' => 'advanced_robots',
// Facebook.
'facebookTitle' => 'facebook_title',
'facebookDescription' => 'facebook_description',
'facebookImage' => 'facebook_image',
'facebookImageID' => 'facebook_image_id',
'facebookHasOverlay' => 'facebook_enable_image_overlay',
'facebookImageOverlay' => 'facebook_image_overlay',
'facebookAuthor' => 'facebook_author',
// Twitter.
'twitterCardType' => 'twitter_card_type',
'twitterUseFacebook' => 'twitter_use_facebook',
'twitterTitle' => 'twitter_title',
'twitterDescription' => 'twitter_description',
'twitterImage' => 'twitter_image',
'twitterImageID' => 'twitter_image_id',
'twitterHasOverlay' => 'twitter_enable_image_overlay',
'twitterImageOverlay' => 'twitter_image_overlay',
// Player.
'twitterPlayerUrl' => 'twitter_player_url',
'twitterPlayerSize' => 'twitter_player_size',
'twitterPlayerStream' => 'twitter_player_stream',
'twitterPlayerStreamCtype' => 'twitter_player_stream_ctype',
// App.
'twitterAppDescription' => 'twitter_app_description',
'twitterAppIphoneName' => 'twitter_app_iphone_name',
'twitterAppIphoneID' => 'twitter_app_iphone_id',
'twitterAppIphoneUrl' => 'twitter_app_iphone_url',
'twitterAppIpadName' => 'twitter_app_ipad_name',
'twitterAppIpadID' => 'twitter_app_ipad_id',
'twitterAppIpadUrl' => 'twitter_app_ipad_url',
'twitterAppGoogleplayName' => 'twitter_app_googleplay_name',
'twitterAppGoogleplayID' => 'twitter_app_googleplay_id',
'twitterAppGoogleplayUrl' => 'twitter_app_googleplay_url',
'twitterAppCountry' => 'twitter_app_country',
]
);
// Generate data.
$data = [];
$object_id = $this->get_object_id();
$object_type = $this->get_object_type();
foreach ( $keys as $id => $key ) {
$data[ $id ] = $this->get_meta( $object_type, $object_id, 'rank_math_' . $key );
}
// Robots.
$data['robots'] = $this->normalize_robots( $this->get_meta( $object_type, $object_id, 'rank_math_robots' ) );
// Advanced Robots.
$data['advancedRobots'] = $this->normalize_advanced_robots( $this->get_meta( $object_type, $object_id, 'rank_math_advanced_robots' ) );
$data['pillarContent'] = 'on' === $data['pillarContent'];
// Username, avatar & Name.
$twitter_username = Helper::get_settings( 'titles.twitter_author_names' );
$data['twitterAuthor'] = $twitter_username ? $twitter_username : esc_html__( 'username', 'rank-math' );
$data['twitterUseFacebook'] = 'off' === $data['twitterUseFacebook'] ? false : true;
$data['facebookHasOverlay'] = empty( $data['facebookHasOverlay'] ) || 'off' === $data['facebookHasOverlay'] ? false : true;
$data['twitterHasOverlay'] = empty( $data['twitterHasOverlay'] ) || 'off' === $data['twitterHasOverlay'] ? false : true;
return wp_parse_args( $this->screen->get_object_values(), $data );
}
/**
* Get site fav icon.
*
* @return string
*/
private function get_site_icon() {
$favicon = get_site_icon_url( 16 );
return ! empty( $favicon ) ? $favicon : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABs0lEQVR4AWL4//8/RRjO8Iucx+noO0MWUDo16FYABMGP6ZfUcRnWtm27jVPbtm3bttuH2t3eFPcY9pLz7NxiLjCyVd87pKnHyqXyxtCs8APd0rnyxiu4qSeA3QEDrAwBDrT1s1Rc/OrjLZwqVmOSu6+Lamcpp2KKMA9PH1BYXMe1mUP5qotvXTywsOEEYHXxrY+3cqk6TMkYpNr2FeoY3KIr0RPtn9wQ2unlA+GMkRw6+9TFw4YTwDUzx/JVvARj9KaedXRO8P5B1Du2S32smzqUrcKGEyA+uAgQjKX7zf0boWHGfn71jIKj2689gxp7OAGShNcBUmLMPVjZuiKcA2vuWHHDCQxMCz629kXAIU4ApY15QwggAFbfOP9DhgBJ+nWVJ1AZAfICAj1pAlY6hCADZnveQf7bQIwzVONGJonhLIlS9gr5mFg44Xd+4S3XHoGNPdJl1INIwKyEgHckEhgTe1bGiFY9GSFBYUwLh1IkiJUbY407E7syBSFxKTszEoiE/YdrgCEayDmtaJwCI9uu8TKMuZSVfSa4BpGgzvomBR/INhLGzrqDotp01ZR8pn/1L0JN9d9XNyx0AAAAAElFTkSuQmCC';
}
/**
* Normalize robots.
*
* @param array $robots Array to normalize.
*
* @return array
*/
private function normalize_robots( $robots ) {
if ( ! is_array( $robots ) || empty( $robots ) ) {
$robots = Helper::get_robots_defaults();
}
return array_fill_keys( $robots, true );
}
/**
* Normalize advanced robots.
*
* @param array $advanced_robots Array to normalize.
*
* @return array
*/
private function normalize_advanced_robots( $advanced_robots ) {
if ( ! empty( $advanced_robots ) ) {
return $advanced_robots;
}
return Helper::get_advanced_robots_defaults();
}
/**
* Return power words.
*
* @return array
*/
private function power_words() {
static $words;
$locale = Locale::get_site_language();
$file = rank_math()->plugin_dir() . 'assets/vendor/powerwords/' . $locale . '.php';
if ( ! file_exists( $file ) ) {
return $this->do_filter( 'metabox/power_words', [], $locale );
}
$words = $words ? $words : include $file;
return $this->do_filter( 'metabox/power_words', array_map( 'strtolower', $words ), $locale );
}
/**
* Get diacritics (accents).
*
* @return array
*/
private function diacritics() {
$locale = Locale::get_site_language();
$locale = in_array( $locale, [ 'en', 'de', 'ru' ], true ) ? $locale : 'en';
$file = rank_math()->plugin_dir() . 'assets/vendor/diacritics/' . $locale . '.php';
if ( ! file_exists( $file ) ) {
return false;
}
$diacritics = include_once $file;
return $this->do_filter( 'metabox/diacritics', $diacritics, $locale );
}
/**
* Load required screen.
*
* @param string $manual To load any screen manually.
*/
public function load_screen( $manual = '' ) {
if ( Admin_Helper::is_post_edit() || 'post' === $manual ) {
$this->screen = new Post_Screen();
return;
}
if ( Admin_Helper::is_term_edit() || 'term' === $manual ) {
$this->screen = new Taxonomy_Screen();
return;
}
if ( User_Screen::is_enable() || 'user' === $manual ) {
$this->screen = new User_Screen();
return;
}
}
}

View File

@@ -0,0 +1,183 @@
<?php
/**
* The metabox functionality of the plugin.
*
* @since 1.0.25
* @package RankMath
* @subpackage RankMath\Admin\Metabox
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Metabox;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Taxonomy metabox class.
*/
class Taxonomy_Screen implements IScreen {
use Hooker;
/**
* Class construct
*/
public function __construct() {
}
/**
* Get object ID.
*
* @return int
*/
public function get_object_id() {
return Param::request( 'tag_ID', 0, FILTER_VALIDATE_INT );
}
/**
* Get object type
*
* @return string
*/
public function get_object_type() {
return 'term';
}
/**
* Get object types to register metabox to
*
* @return array
*/
public function get_object_types() {
$object_types = [];
$taxonomies = Helper::get_allowed_taxonomies();
if ( is_array( $taxonomies ) && ! empty( $taxonomies ) ) {
$object_types[] = 'term';
$this->description_field_editor();
remove_filter( 'pre_term_description', 'wp_filter_kses' );
remove_filter( 'term_description', 'wp_kses_data' );
add_filter( 'pre_term_description', 'wp_kses_post' );
add_filter( 'term_description', 'wp_kses_post' );
}
return $object_types;
}
/**
* Enqueue Styles and Scripts required for screen.
*/
public function enqueue() {}
/**
* Get analysis to run.
*
* @return array
*/
public function get_analysis() {
return [
'keywordInTitle' => true,
'keywordInMetaDescription' => true,
'keywordInPermalink' => true,
'keywordNotUsed' => true,
'titleStartWithKeyword' => true,
];
}
/**
* Get values for localize.
*
* @return array
*/
public function get_values() {
$url = '';
if ( $this->get_object_id() ) {
$url = get_term_link( $this->get_object_id() );
$data = array_filter( explode( '/', $url ) );
$url = ! empty( $data ) ? str_replace( array_pop( $data ), '%term%', $url ) : '';
}
return [
'permalinkFormat' => $url ? $url : home_url(),
];
}
/**
* Get object values for localize
*
* @return array
*/
public function get_object_values() {
$taxonomy = $this->get_taxonomy();
return [
'titleTemplate' => Helper::get_settings( "titles.tax_{$taxonomy}_title", '%term% %sep% %sitename%' ),
'descriptionTemplate' => Helper::get_settings( "titles.tax_{$taxonomy}_description", '%term_description%' ),
];
}
/**
* Output the WordPress editor.
*
* @param object $term Current taxonomy term object.
*/
public function category_description_editor( $term ) {
?>
<tr class="form-field term-description-wrap rank-math-term-description-wrap">
<th scope="row"><label for="description"><?php esc_html_e( 'Description', 'rank-math' ); ?></label></th>
<td>
<?php
wp_editor(
html_entity_decode( $term->description, ENT_QUOTES, 'UTF-8' ),
'rank_math_description_editor',
[
'textarea_name' => 'description',
'textarea_rows' => 5,
]
);
?>
</td>
<script>
// Remove the non-html field
jQuery('textarea#description').closest('.form-field').remove();
</script>
</tr>
<?php
}
/**
* Add the description field to the edit taxonomy screen if the metabox is
* enabled for the current taxonomy.
*
* @return void
*/
private function description_field_editor() {
$taxonomy = $this->get_taxonomy();
if (
! Helper::get_settings( 'titles.tax_' . $taxonomy . '_add_meta_box' ) ||
$this->do_filter( 'admin/disable_rich_editor', false, $taxonomy )
) {
return;
}
$this->action( "{$taxonomy}_edit_form_fields", 'category_description_editor', 1 );
}
/**
* Get current taxonomy.
*
* @return {string} Taxonomy slug.
*/
private function get_taxonomy() {
$taxonomy = filter_input( INPUT_GET, 'taxonomy', FILTER_DEFAULT, [ 'options' => [ 'default' => '' ] ] );
$taxonomy_object = get_taxonomy( $taxonomy );
if ( empty( $taxonomy_object ) || empty( $taxonomy_object->public ) ) {
return;
}
return $taxonomy;
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* The metabox functionality of the plugin.
*
* @since 1.0.25
* @package RankMath
* @subpackage RankMath\Admin\Metabox
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Metabox;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* User metabox class.
*/
class User_Screen implements IScreen {
use Hooker;
/**
* Class construct
*/
public function __construct() {}
/**
* Get object ID.
*
* @return int
*/
public function get_object_id() {
global $user_id;
return $user_id;
}
/**
* Get object type
*
* @return string
*/
public function get_object_type() {
return 'user';
}
/**
* Get object types to register metabox to
*
* @return array
*/
public function get_object_types() {
return [ 'user' ];
}
/**
* Enqueue Styles and Scripts required for screen.
*/
public function enqueue() {
wp_enqueue_media();
}
/**
* Get analysis to run.
*
* @return array
*/
public function get_analysis() {
return [
'keywordInTitle' => true,
'keywordInMetaDescription' => true,
'keywordInPermalink' => true,
'keywordNotUsed' => true,
'titleStartWithKeyword' => true,
];
}
/**
* Get values for localize.
*
* @return array
*/
public function get_values() {
global $wp_rewrite;
return [
'permalinkFormat' => ! empty( $wp_rewrite->author_structure ) ? home_url( $wp_rewrite->author_structure ) : home_url(),
];
}
/**
* Get object values for localize
*
* @return array
*/
public function get_object_values() {
return [
'titleTemplate' => Helper::get_settings( 'titles.author_archive_title', '%name% %sep% %sitename% %page%' ),
'descriptionTemplate' => Helper::get_settings( 'titles.author_archive_description', '%user_description%' ),
];
}
/**
* Is user metabox enabled.
*
* @return bool
*/
public static function is_enable() {
return false === Helper::get_settings( 'titles.disable_author_archives' ) &&
Helper::get_settings( 'titles.author_add_meta_box' ) &&
Admin_Helper::is_user_edit();
}
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* An interface for getting values for screen.
*
* @since 1.0.33
* @package RankMath
* @subpackage RankMath\Admin\Metabox
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin\Metabox;
defined( 'ABSPATH' ) || exit;
/**
* Screen.
*/
interface IScreen {
/**
* Get object ID.
*
* @return int
*/
public function get_object_id();
/**
* Get object type
*
* @return string
*/
public function get_object_type();
/**
* Get object types to register metabox to
*
* @return array
*/
public function get_object_types();
/**
* Enqueue Styles and Scripts required for screen
*/
public function enqueue();
/**
* Get values for localize
*
* @return array
*/
public function get_values();
/**
* Get object values for localize
*
* @return array
*/
public function get_object_values();
/**
* Get analysis to run.
*
* @return array
*/
public function get_analysis();
}

View File

@@ -0,0 +1,357 @@
<?php
/**
* The Notification center handles notifications storage and display.
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Notifications;
/**
* Notification_Center class.
*/
class Notification_Center {
/**
* Option name to store notifications in.
*
* @var string
*/
private $storage_key = '';
/**
* Notifications.
*
* @var array
*/
private $notifications = [];
/**
* Stores whether we need to clear storage or not.
*
* @var array
*/
private $should_clear_storage = true;
/**
* Stores already displayed notice texts to avoid duplication.
*
* @var array
*/
private $displayed_notifications = [];
/**
* Internal flag for whether notifications have been retrieved from storage.
*
* @var bool
*/
private $retrieved = false;
/**
* Construct
*
* @param string $storage_key Option name to store notification in.
*/
public function __construct( $storage_key = 'mythemeshop_notifications' ) {
$this->storage_key = $storage_key;
add_action( 'plugins_loaded', [ $this, 'get_from_storage' ], 5 );
add_action( 'all_admin_notices', [ $this, 'display' ] );
add_action( 'shutdown', [ $this, 'update_storage' ] );
add_action( 'admin_footer', [ $this, 'print_javascript' ] );
add_action( 'wp_ajax_wp_helpers_notice_dismissible', [ $this, 'notice_dismissible' ] );
}
/**
* Retrieve the notifications from storage
*
* @codeCoverageIgnore
*
* @return array Notification[] Notifications
*/
public function get_from_storage() {
if ( $this->retrieved ) {
return;
}
$this->retrieved = true;
$notifications = get_option( $this->storage_key );
// Check if notifications are stored.
if ( empty( $notifications ) ) {
$this->should_clear_storage = false;
return;
}
if ( is_array( $notifications ) ) {
foreach ( $notifications as $notification ) {
$this->notifications[] = new Notification(
$notification['message'],
$notification['options']
);
}
}
}
/**
* Display the notifications.
*
* @codeCoverageIgnore
*/
public function display() {
// Never display notifications for network admin.
if ( $this->is_network_admin() ) {
return;
}
$notifications = $this->get_sorted_notifications();
if ( empty( $notifications ) ) {
return;
}
foreach ( $notifications as $notification ) {
if ( $notification->can_display() && ! in_array( (string) $notification, $this->displayed_notifications, true ) ) {
echo $notification;
$this->displayed_notifications[] = (string) $notification;
}
}
}
/**
* Print JS for dismissile.
*
* @codeCoverageIgnore
*/
public function print_javascript() {
?>
<script>
;(function($) {
$( '.wp-helpers-notice.is-dismissible' ).on( 'click', '.notice-dismiss', function() {
var notice = $( this ).parent()
$.ajax({
url: ajaxurl,
type: 'POST',
dataType: 'json',
data: {
action: 'wp_helpers_notice_dismissible',
security: notice.data( 'security' ),
notificationId: notice.attr( 'id' )
}
});
});
})(jQuery);
</script>
<?php
}
/**
* Save persistent or transactional notifications to storage.
*
* We need to be able to retrieve these so they can be dismissed at any time during the execution.
*
* @codeCoverageIgnore
*/
public function update_storage() {
$notifications = $this->get_notifications();
$notifications = array_filter( $notifications, [ $this, 'remove_notification' ] );
/**
* Filter: 'wp_helpers_notifications_before_storage' - Allows developer to filter notifications before saving them.
*
* @param Notification[] $notifications
*/
$notifications = apply_filters( 'wp_helpers_notifications_before_storage', $notifications );
// No notifications to store, clear storage.
if ( empty( $notifications ) && $this->should_clear_storage ) {
delete_option( $this->storage_key );
return;
}
$notifications = array_map( [ $this, 'notification_to_array' ], $notifications );
// Save the notifications to the storage.
update_option( $this->storage_key, $notifications );
}
/**
* Dismiss persistent notice.
*
* @codeCoverageIgnore
*/
public function notice_dismissible() {
$notification_id = filter_input( INPUT_POST, 'notificationId' );
check_ajax_referer( $notification_id, 'security' );
$notification = $this->remove_by_id( $notification_id );
/**
* Filter: 'wp_helpers_notification_dismissed' - Allows developer to perform action after dismissed.
*
* @param Notification[] $notifications
*/
do_action( 'wp_helpers_notification_dismissed', $notification_id, $notification );
}
/**
* Add notification
*
* @param string $message Message string.
* @param array $options Set of options.
*/
public function add( $message, $options = [] ) {
if ( isset( $options['id'] ) && ! is_null( $this->get_notification_by_id( $options['id'] ) ) ) {
return;
}
$this->notifications[] = new Notification(
$message,
$options
);
}
/**
* Provide a way to verify present notifications
*
* @return array|Notification[] Registered notifications.
*/
public function get_notifications() {
return $this->notifications;
}
/**
* Get the notification by ID
*
* @param string $notification_id The ID of the notification to search for.
* @return null|Notification
*/
public function get_notification_by_id( $notification_id ) {
foreach ( $this->notifications as $notification ) {
if ( $notification_id === $notification->args( 'id' ) ) {
return $notification;
}
}
return null;
}
/**
* Remove the notification by ID
*
* @codeCoverageIgnore
*
* @param string $notification_id The ID of the notification to search for.
* @return Notification Instance of delete notification.
*/
public function remove_by_id( $notification_id ) {
$notification = $this->get_notification_by_id( $notification_id );
if ( ! is_null( $notification ) ) {
$notification->dismiss();
}
return $notification;
}
/**
* Remove notification after it has been displayed.
*
* @codeCoverageIgnore
*
* @param Notification $notification Notification to remove.
*/
public function remove_notification( Notification $notification ) {
if ( ! $notification->is_displayed() ) {
return true;
}
if ( $notification->is_persistent() ) {
return true;
}
return false;
}
/**
* Return the notifications sorted on type and priority
*
* @codeCoverageIgnore
*
* @return array|Notification[] Sorted Notifications
*/
private function get_sorted_notifications() {
$notifications = $this->get_notifications();
if ( empty( $notifications ) ) {
return [];
}
// Sort by severity, error first.
usort( $notifications, [ $this, 'sort_notifications' ] );
return $notifications;
}
/**
* Sort on type then priority
*
* @codeCoverageIgnore
*
* @param Notification $first Compare with B.
* @param Notification $second Compare with A.
* @return int 1, 0 or -1 for sorting offset.
*/
private function sort_notifications( Notification $first, Notification $second ) {
if ( 'error' === $first->args( 'type' ) ) {
return -1;
}
if ( 'error' === $second->args( 'type' ) ) {
return 1;
}
return 0;
}
/**
* Convert Notification to array representation
*
* @codeCoverageIgnore
*
* @param Notification $notification Notification to convert.
* @return array
*/
private function notification_to_array( Notification $notification ) {
return $notification->to_array();
}
/**
* Check if is network admin.
*
* @codeCoverageIgnore
*
* @return bool
*/
private function is_network_admin() {
return function_exists( 'is_network_admin' ) && is_network_admin();
}
/**
* Check if a notification with the given ID exists.
*
* @param string $id Notification ID.
* @return boolean
*/
public function has_notification( $id ) {
$notifications = $this->get_notifications();
foreach ( $notifications as $notification ) {
if ( isset( $notification->options['id'] ) && $notification->options['id'] === $id ) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,244 @@
<?php
/**
* The Notification
*
* @since 1.0.0
* @package RankMath
* @subpackage RankMath
* @author RankMath <support@rankmath.com>
*/
namespace RankMath\Admin\Notifications;
use RankMath\Helpers\Str;
use RankMath\Helpers\HTML;
/**
* Notification class.
*/
class Notification {
/**
* Notification type.
*
* @var string
*/
const ERROR = 'error';
/**
* Notification type.
*
* @var string
*/
const SUCCESS = 'success';
/**
* Notification type.
*
* @var string
*/
const INFO = 'info';
/**
* Notification type.
*
* @var string
*/
const WARNING = 'warning';
/**
* Screen check.
*
* @var string
*/
const SCREEN_ANY = 'any';
/**
* User capability check.
*
* @var string
*/
const CAPABILITY_ANY = '';
/**
* The notification message.
*
* @var string
*/
public $message = '';
/**
* Contains optional arguments:
*
* - type: The notification type, i.e. 'updated' or 'error'
* - id: The ID of the notification
* - dismissal_key: Option name to save dismissal information in, ID will be used if not supplied.
* - screen: Only display on plugin page or on every page.
*
* @var array Options of this Notification.
*/
public $options = [];
/**
* Internal flag for whether notifications has been displayed.
*
* @var bool
*/
private $displayed = false;
/**
* Notification class constructor.
*
* @param string $message Message string.
* @param array $options Set of options.
*/
public function __construct( $message, $options = [] ) {
$this->message = $message;
$this->options = wp_parse_args(
$options,
[
'id' => '',
'classes' => '',
'type' => self::SUCCESS,
'screen' => self::SCREEN_ANY,
'capability' => self::CAPABILITY_ANY,
]
);
}
/**
* Adds string (view) behaviour to the Notification.
*
* @codeCoverageIgnore
*
* @return string
*/
public function __toString() {
return $this->render();
}
/**
* Return data from options.
*
* @param string $id Data to get.
* @return mixed
*/
public function args( $id ) {
return $this->options[ $id ];
}
/**
* Is this Notification persistent.
*
* @codeCoverageIgnore
*
* @return bool True if persistent, False if fire and forget.
*/
public function is_persistent() {
return ! empty( $this->args( 'id' ) );
}
/**
* Is this notification displayed.
*
* @codeCoverageIgnore
*
* @return bool
*/
public function is_displayed() {
return $this->displayed;
}
/**
* Can display on current screen.
*
* @codeCoverageIgnore
*
* @return bool
*/
public function can_display() {
// Removed.
if ( $this->displayed ) {
return false;
}
$screen = get_current_screen();
if ( self::SCREEN_ANY === $this->args( 'screen' ) || Str::contains( $this->args( 'screen' ), $screen->id ) ) {
$this->displayed = true;
}
if ( self::CAPABILITY_ANY !== $this->args( 'capability' ) && ! current_user_can( $this->args( 'capability' ) ) ) {
$this->displayed = false;
}
return $this->displayed;
}
/**
* Dismiss persisten notification.
*
* @codeCoverageIgnore
*/
public function dismiss() {
$this->displayed = true;
$this->options['id'] = '';
}
/**
* Return the object properties as an array.
*
* @codeCoverageIgnore
*
* @return array
*/
public function to_array() {
return [
'message' => $this->message,
'options' => $this->options,
];
}
/**
* Renders the notification as a string.
*
* @codeCoverageIgnore
*
* @return string The rendered notification.
*/
public function render() {
$attributes = [];
// Default notification classes.
$classes = [
'notice',
'notice-' . $this->args( 'type' ),
$this->args( 'classes' ),
];
// Maintain WordPress visualisation of alerts when they are not persistent.
if ( $this->is_persistent() ) {
$classes[] = 'is-dismissible';
$classes[] = 'wp-helpers-notice';
$attributes['id'] = $this->args( 'id' );
$attributes['data-security'] = wp_create_nonce( $this->args( 'id' ) );
}
if ( ! empty( $classes ) ) {
$attributes['class'] = implode( ' ', array_filter( $classes ) );
}
// Build the output DIV.
$output = '<div' . HTML::attributes_to_string( $attributes ) . '>' . wpautop( $this->message ) . '</div>' . PHP_EOL;
/**
* Filter: 'wp_helpers_notifications_render' - Allows developer to filter notifications before the output is finalized.
*
* @param string $output HTML output.
* @param array $message Notice message.
* @param array $options Notice args.
*/
$output = apply_filters( 'wp_helpers_notifications_render', $output, $this->message, $this->options );
return $output;
}
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* Dashboard help tab template.
*
* @package RankMath
* @subpackage RankMath\Admin
*/
use RankMath\KB;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( Helper::has_cap( 'general' ) ) {
include_once 'plugin-activation.php';
}
require_once 'plugin-activation.php'; ?>
<div class="two-col rank-math-box-help">
<div class="col rank-math-box">
<header>
<h3><?php esc_html_e( 'Next steps&hellip;', 'rank-math' ); ?></h3>
</header>
<div class="rank-math-box-content">
<ul class="rank-math-list-icon">
<li>
<?php if ( ! defined( 'RANK_MATH_PRO_FILE' ) ) { ?>
<a href="<?php KB::the( 'pro', 'Help Tab PRO Link' ); ?>" target="_blank">
<i class="rm-icon rm-icon-star-filled"></i>
<div>
<strong><?php esc_html_e( 'Upgrade to PRO', 'rank-math' ); ?></strong>
<p><?php esc_html_e( 'Advanced Schema, Analytics and much more...', 'rank-math' ); ?></p>
</div>
</a>
<?php } else { ?>
<a href="<?php KB::the( 'how-to-setup', 'Help Tab Setup KB' ); ?>" target="_blank">
<i class="rm-icon rm-icon-settings"></i>
<div>
<strong><?php esc_html_e( 'Setup Rank Math', 'rank-math' ); ?></strong>
<p><?php esc_html_e( 'How to Properly Setup Rank Math', 'rank-math' ); ?></p>
</div>
</a>
<?php } ?>
</li>
<li>
<a href="<?php KB::the( 'seo-import', 'Help Tab Import Data' ); ?>" target="_blank">
<i class="rm-icon rm-icon-import"></i>
<div>
<strong><?php esc_html_e( 'Import Data', 'rank-math' ); ?></strong>
<p><?php esc_html_e( 'How to Import Data from Your Previous SEO Plugin', 'rank-math' ); ?></p>
</div>
</a>
</li>
<li>
<a href="<?php KB::the( 'score-100', 'Help Tab Score KB' ); ?>" target="_blank">
<i class="rm-icon rm-icon-post"></i>
<div>
<strong><?php esc_html_e( 'Improve SEO Score', 'rank-math' ); ?></strong>
<p><?php esc_html_e( 'How to Make Your Posts Pass All the Tests', 'rank-math' ); ?></p>
</div>
</a>
</li>
</ul>
</div>
</div>
<div class="col rank-math-box">
<header>
<h3><?php esc_html_e( 'Product Support', 'rank-math' ); ?></h3>
</header>
<div class="rank-math-box-content">
<ul class="rank-math-list-icon">
<li>
<a href="<?php KB::the( 'kb-seo-suite', 'Help Tab KB Link' ); ?>" target="_blank">
<i class="rm-icon rm-icon-help"></i>
<div>
<strong><?php esc_html_e( 'Online Documentation', 'rank-math' ); ?></strong>
<p><?php esc_html_e( 'Understand all the capabilities of Rank Math', 'rank-math' ); ?></p>
</div>
</a>
</li>
<li>
<a href="<?php KB::the( 'support', 'Help Tab Ticket' ); ?>" target="_blank">
<i class="rm-icon rm-icon-support"></i>
<div>
<strong><?php esc_html_e( 'Ticket Support', 'rank-math' ); ?></strong>
<p><?php esc_html_e( 'Direct help from our qualified support team', 'rank-math' ); ?></p>
</div>
</a>
</li>
<li>
<a href="<?php KB::the( 'help-affiliate', 'Help Tab Aff Link' ); ?>" target="_blank">
<i class="rm-icon rm-icon-sitemap"></i>
<div>
<strong><?php esc_html_e( 'Affiliate Program', 'rank-math' ); ?></strong>
<p><?php esc_html_e( 'Earn flat 30% on every sale!', 'rank-math' ); ?></p>
</div>
</a>
</li>
</ul>
</div>
</div>
</div><!--.two-col-->
</div><!--.dashboard-wrapper-->

View File

@@ -0,0 +1,46 @@
<?php
/**
* Dashboard page template.
*
* @package RankMath
* @subpackage RankMath\Admin
*/
use RankMath\Helpers\Param;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
$is_network_admin = is_network_admin();
$is_network_active = RankMath\Helper::is_plugin_active_for_network();
$current_tab = $is_network_active && $is_network_admin ? 'help' : Param::get( 'view', 'modules' );
// Header.
rank_math()->admin->display_admin_header();
?>
<div class="wrap rank-math-wrap dashboard">
<span class="wp-header-end"></span>
<?php rank_math()->admin->display_dashboard_nav(); ?>
<?php
if ( $is_network_active && ! $is_network_admin && 'help' === $current_tab ) {
return;
}
// phpcs:disable
// Display modules activation and deactivation form.
if ( 'modules' === $current_tab ) {
rank_math()->manager->display_form();
// Others.
} else {
$file = apply_filters( 'rank_math/admin/dashboard_view', Admin_Helper::get_view( "dashboard-{$current_tab}" ), $current_tab );
if ( file_exists( $file ) ) {
include_once $file;
}
}
// phpcs:enable
?>
</div>

View File

@@ -0,0 +1,53 @@
<?php
/**
* Backup panel template.
*
* @package RankMath
* @subpackage RankMath\Admin
*/
defined( 'ABSPATH' ) || exit;
$backups = $this->get_backups();
?>
<button type="button" class="button button-primary alignright rank-math-action" data-action="createBackup"><?php esc_html_e( 'Create Backup', 'rank-math' ); ?></button>
<h3><?php esc_html_e( 'Settings Backup', 'rank-math' ); ?></h3>
<p class="description"><?php esc_html_e( 'Take a backup of your plugin settings in case you wish to restore them in future. Use it as backup before making substantial changes to Rank Math settings. For taking a backup of the SEO data of your content, use the XML Export option.', 'rank-math' ); ?></p>
<div class="rank-math-settings-backup-form cmb2-form">
<div class="list-table with-action">
<table class="form-table">
<tbody>
<?php foreach ( $backups as $key => $backup ) : ?>
<tr>
<th>
<?php
/* translators: Snapshot formatted date */
printf( esc_html__( 'Backup: %s', 'rank-math' ), date_i18n( 'M jS Y, H:i a', $key ) );
?>
</th>
<td style="width:195px;padding-left:0;">
<button type="button" class="button button-secondary button-small rank-math-action" data-action="restoreBackup" data-key="<?php echo esc_attr( $key ); ?>"><?php esc_html_e( 'Restore', 'rank-math' ); ?></button>
<button type="button" class="button button-link-delete button-small rank-math-action" data-action="deleteBackup" data-key="<?php echo esc_attr( $key ); ?>"><?php esc_html_e( 'Delete', 'rank-math' ); ?></button>
</td>
</tr>
<?php endforeach; ?>
<?php if ( empty( $backups ) ) : ?>
<tr class="hidden">
<th>
</th>
<td style="width:195px;padding-left:0;">
<button type="button" class="button button-primary rank-math-action" data-action="restoreBackup" data-key=""><?php esc_html_e( 'Restore', 'rank-math' ); ?></button>
<button type="button" class="button button-link-delete rank-math-action" data-action="deleteBackup" data-key=""><?php esc_html_e( 'Delete', 'rank-math' ); ?></button>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<p id="rank-math-no-backup-message"<?php echo ! empty( $backups ) ? ' class="hidden"' : ''; ?>><?php esc_html_e( 'There is no backup.', 'rank-math' ); ?></p>
</div>

View File

@@ -0,0 +1,74 @@
<?php
/**
* Import-Export Settings panel template.
*
* @package RankMath
* @subpackage RankMath\Admin
*/
use RankMath\KB;
defined( 'ABSPATH' ) || exit;
?>
<h2><?php esc_html_e( 'Plugin Settings', 'rank-math' ); ?></h2>
<p class="description">
<?php
/* translators: Link to learn about import export panel KB article */
printf( esc_html__( 'Import or export your Rank Math settings, This option is useful for replicating Rank Math settings across multiple websites. %s', 'rank-math' ), '<a href="' . KB::get( 'import-export-settings', 'Options Panel Import Export Page' ) . '" target="_blank">' . esc_html__( 'Learn more about the Import/Export options.', 'rank-math' ) . '</a>' );
?>
</p>
<div class="rank-math-box no-padding">
<div class="rank-math-box-tabs wp-clearfix">
<a href="#rank-math-import-form" class="active-tab">
<i class="rm-icon rm-icon-import"></i>
<span class="rank-math-tab-text"><?php esc_html_e( 'Import Settings', 'rank-math' ); ?></span>
</a>
<a href="#rank-math-export-form" class="">
<i class="rm-icon rm-icon-export"></i>
<span class="rank-math-tab-text"><?php esc_html_e( 'Export Settings', 'rank-math' ); ?></span>
</a>
</div>
<div class="rank-math-box-content">
<div class="rank-math-box-inner">
<form id="rank-math-import-form" class="rank-math-export-form cmb2-form active-tab" action="" method="post" enctype="multipart/form-data" accept-charset="<?php echo esc_attr( get_bloginfo( 'charset' ) ); ?>">
<p><label for="import-me"><strong><?php esc_html_e( 'Settings File', 'rank-math' ); ?></label></strong><p>
<input type="file" name="import-me" id="import-me" value="">
<br>
<span class="validation-message"><?php esc_html_e( 'Please select a file to import.', 'rank-math' ); ?></span>
<p class="description"><?php esc_html_e( 'Import settings by locating settings file and clicking "Import settings".', 'rank-math' ); ?></p>
<footer>
<?php wp_nonce_field( 'rank-math-import-settings' ); ?>
<input type="hidden" name="object_id" value="import-plz">
<input type="hidden" name="action" value="wp_handle_upload">
<button type="submit" class="button button-primary"><?php esc_html_e( 'Import', 'rank-math' ); ?></button>
</footer>
</form>
<form class="rank-math-export-form cmb2-form" id="rank-math-export-form" action="" method="post">
<ul class="cmb2-checkbox-list no-select-all cmb2-list">
<li><input type="checkbox" class="cmb2-option" name="panels[]" id="status1" value="general" checked="checked"> <label for="status1"><?php esc_html_e( 'General Settings', 'rank-math' ); ?></label></li>
<li><input type="checkbox" class="cmb2-option" name="panels[]" id="status2" value="titles" checked="checked"> <label for="status2"><?php esc_html_e( 'Titles &amp; Metas', 'rank-math' ); ?></label></li>
<li><input type="checkbox" class="cmb2-option" name="panels[]" id="status3" value="sitemap" checked="checked"> <label for="status3"><?php esc_html_e( 'Sitemap Settings', 'rank-math' ); ?></label></li>
<li><input type="checkbox" class="cmb2-option" name="panels[]" id="status4" value="role-manager" checked="checked"> <label for="status4"><?php esc_html_e( 'Role Manager Settings', 'rank-math' ); ?></label></li>
<li><input type="checkbox" class="cmb2-option" name="panels[]" id="status5" value="redirections" checked="checked"> <label for="status5"><?php esc_html_e( 'Redirections', 'rank-math' ); ?></label></li>
</ul>
<p class="description"><?php esc_html_e( 'Choose the panels to export.', 'rank-math' ); ?></p>
<footer>
<?php wp_nonce_field( 'rank-math-export-settings' ); ?>
<input type="hidden" name="object_id" value="export-plz">
<button type="submit" class="button button-primary"><?php esc_html_e( 'Export', 'rank-math' ); ?></button>
</footer>
</form>
</div>
</div>
</div>

View File

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

View File

@@ -0,0 +1,14 @@
<?php
/**
* Import/Export page template.
*
* @package RankMath
* @subpackage RankMath\Admin
*/
defined( 'ABSPATH' ) || exit;
?>
<div class="rank-math-import-export">
<?php $this->show_panels(); ?>
</div>

View File

@@ -0,0 +1,86 @@
<?php
/**
* Plugins panel template.
*
* @package RankMath
* @subpackage RankMath\Admin
*/
use RankMath\Admin\Importers\Detector;
use RankMath\KB;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
$detector = new Detector();
$plugins = $detector->detect();
$first = empty( $plugins ) ? '' : array_keys( $plugins )[0];
?>
<h2><?php esc_html_e( 'Other Plugins', 'rank-math' ); ?></h2>
<p class="description">
<?php
/* translators: Link to learn about import export panel KB article */
printf( esc_html__( 'If you were using another plugin to add important SEO information to your website before switching to Rank Math SEO, you can import the settings and data here. %s', 'rank-math' ), '<a href="' . KB::get( 'import-export-settings', 'Options Panel Import Export Page Other Plugins' ) . '" target="_blank">' . esc_html__( 'Learn more about the Import/Export options.', 'rank-math' ) . '</a>' );
?>
</p>
<form class="rank-math-box no-padding rank-math-export-form cmb2-form" action="" method="post">
<div class="with-action at-top">
<?php if ( empty( $plugins ) ) : ?>
<p class="empty-notice"><?php echo esc_html__( 'No plugin detected with importable data.', 'rank-math' ); ?></p>
<?php else : ?>
<div class="rank-math-box-tabs wp-clearfix">
<?php foreach ( $plugins as $slug => $importer ) : ?>
<a href="#import-plugin-<?php echo esc_attr( $slug ); ?>" class="<?php echo $slug === $first ? 'active-tab' : ''; ?>">
<i class="rm-icon rm-icon-import"></i>
<span class="rank-math-tab-text"><?php echo esc_html( $importer['name'] ); ?></span>
</a>
<?php endforeach; ?>
</div>
<div class="rank-math-box-content">
<div class="rank-math-box-inner">
<?php foreach ( $plugins as $slug => $importer ) : ?>
<div id="import-plugin-<?php echo esc_attr( $slug ); ?>" class="<?php echo $slug === $first ? ' active-tab' : ''; ?>">
<table class="form-table cmb2-wrap">
<tbody>
<tr class="choices">
<td colspan="2">
<ul class="cmb2-checkbox-list cmb2-list no-select-all">
<?php
foreach ( $importer['choices'] as $key => $label ) :
$id = "{$slug}_{$key}";
?>
<li>
<input type="checkbox" class="cmb2-option" name="<?php echo esc_attr( $slug ); ?>[]" id="<?php echo esc_attr( $id ); ?>" value="<?php echo esc_attr( $key ); ?>" checked="checked">
<label for="<?php echo esc_attr( $id ); ?>"><?php echo wp_kses_post( $label ); ?></label>
</li>
<?php endforeach; ?>
<?php if ( 'redirections' !== $slug ) : ?>
<li style="margin-top: 20px;">
<input type="checkbox" class="cmb2-option" name="<?php echo esc_attr( $slug ); ?>[]" id="<?php echo esc_attr( $slug ); ?>_recalculate" value="recalculate" checked="checked">
<label for="<?php echo esc_attr( $slug ); ?>_recalculate"><?php esc_html_e( 'Calculate SEO Scores', 'rank-math' ); ?></label>
</li>
<?php endif; ?>
</ul>
</td>
</tr>
</tbody>
</table>
<footer>
<button type="button" class="button button-primary rank-math-action" data-action="importPlugin" data-slug="<?php echo esc_attr( $slug ); ?>" data-active="<?php echo esc_attr( is_plugin_active( $importer['file'] ) ); ?>"><?php esc_html_e( 'Import', 'rank-math' ); ?></button>
<button type="button" class="button button-link-delete rank-math-action" data-action="cleanPlugin" data-slug="<?php echo esc_attr( $slug ); ?>"><?php esc_html_e( 'Clean', 'rank-math' ); ?></button>
</footer>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
</form>

View File

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

View File

@@ -0,0 +1,54 @@
<?php
/**
* Plugin activation template.
*
* @package RankMath
* @subpackage RankMath\Admin
*/
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
$is_registered = Helper::is_site_connected();
$class = $is_registered ? 'status-green' : 'status-red';
$activate_url = Admin_Helper::get_activate_url();
$site_url_valid = Admin_Helper::is_site_url_valid();
$button_class = 'button button-primary button-connect' . ( $site_url_valid ? ' button-animated' : ' disabled' );
?>
<div class="rank-math-ui dashboard-wrapper container help">
<div class="rank-math-box <?php echo esc_attr( $class ); ?>">
<header>
<h3><?php esc_html_e( 'Account', 'rank-math' ); ?></h3>
<span class="button button-large <?php echo esc_attr( $class ); ?>"><?php echo $is_registered ? '<i class="rm-icon rm-icon-tick"></i>' . esc_html__( 'Connected', 'rank-math' ) : '<i class="rm-icon rm-icon-cross"></i>' . esc_html__( 'Not Connected', 'rank-math' ); ?></span>
</header>
<div class="rank-math-box-content rank-math-ui">
<form method="post" action="">
<input type="hidden" name="registration-action" value="<?php echo $is_registered ? 'deregister' : 'register'; ?>">
<?php wp_nonce_field( 'rank_math_register_product' ); ?>
<?php if ( ! $is_registered ) : ?>
<?php // translators: variables used to wrap the text in the strong tag. ?>
<p><?php printf( wp_kses_post( __( 'The plugin is currently not connected with your Rank Math account. Click on the button below to login or register for FREE using your %1$sGoogle account, Facebook account%2$s or %1$syour email account%2$s.', 'rank-math' ) ), '<strong>', '</strong>' ); ?></p>
<?php Admin_Helper::maybe_show_invalid_siteurl_notice(); ?>
<a href="<?php echo esc_url( $activate_url ); ?>" class="<?php echo esc_attr( $button_class ); ?>" ><?php esc_html_e( 'Connect Now', 'rank-math' ); ?></a>
<?php else : ?>
<?php // translators: variables used to wrap the text in the strong tag. ?>
<p><?php printf( wp_kses_post( __( 'You have successfully activated Rank Math. If you find the plugin useful, %1$s feel free to recommend it to your friends or colleagues %2$s.', 'rank-math' ) ), '<strong>', '</strong>' ); ?><?php Admin_Helper::get_social_share(); ?></p>
<div class="frm-submit">
<button type="submit" class="button button-link-delete button-xlarge" name="button"><?php echo esc_html__( 'Disconnect Account', 'rank-math' ); ?></button>
</div>
<?php endif; ?>
</form>
</div>
</div>

View File

@@ -0,0 +1,287 @@
<?php
/**
* The conflicting plugin watcher.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Admin
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Admin;
use RankMath\Runner;
use RankMath\Traits\Hooker;
use RankMath\Helpers\Security;
use RankMath\Helpers\Param;
use RankMath\Helper as GlobalHelper;
defined( 'ABSPATH' ) || exit;
/**
* Watcher class.
*/
class Watcher implements Runner {
use Hooker;
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'init', 'maybe_deactivate_plugins' );
$this->action( 'activated_plugin', 'check_activated_plugin' );
$this->action( 'deactivated_plugin', 'check_deactivated_plugin' );
$this->filter( 'wp_helpers_notifications_render', 'deactivate_plugins_link', 10, 3 );
$this->action( 'update_option_blog_public', 'check_search_engine_visibility' );
}
/**
* Set/Deactivate conflicting SEO or Sitemap plugins.
*/
public function maybe_deactivate_plugins() {
if ( ! Param::get( 'rank_math_deactivate_plugins' ) ) {
return;
}
if ( ! current_user_can( 'deactivate_plugins' ) ) {
wp_die( esc_html__( 'Sorry, you are not allowed to deactivate plugins for this site.', 'rank-math' ) );
}
check_admin_referer( 'rank_math_deactivate_plugins' );
$type = Param::get( 'plugin_type', 'seo', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
$allowed = [ 'seo', 'sitemap' ];
if ( ! in_array( $type, $allowed, true ) ) {
return;
}
$this->deactivate_conflicting_plugins( $type );
}
/**
* Function to run when new plugin is activated.
*/
public static function check_activated_plugin() {
$set = [];
$plugins = get_option( 'active_plugins', [] );
foreach ( self::get_conflicting_plugins() as $plugin => $type ) {
if ( ! isset( $set[ $type ] ) && in_array( $plugin, $plugins, true ) ) {
$set[ $type ] = true;
self::set_notification( $type );
}
}
if ( in_array( 'wpml-string-translation/plugin.php', $plugins, true ) ) {
GlobalHelper::remove_notification( 'convert_wpml_settings' );
}
}
/**
* Function to run when plugin is deactivated.
*
* @param string $plugin Deactivated plugin path.
*/
public function check_deactivated_plugin( $plugin ) {
$plugins = self::get_conflicting_plugins();
if ( ! isset( $plugins[ $plugin ] ) ) {
return;
}
$this->remove_notification( $plugins[ $plugin ], $plugin );
}
/**
* Function to run when Module is enabled/disabled.
*
* @param string $module Module.
* @param string $state Module state.
*/
public static function module_changed( $module, $state ) {
if ( ! in_array( $module, [ 'sitemap', 'redirections', 'rich-snippet' ], true ) ) {
return;
}
if ( 'off' === $state ) {
$type = 'sitemap' === $module ? 'sitemap' : 'seo';
GlobalHelper::remove_notification( "conflicting_{$type}_plugins" );
}
self::check_activated_plugin();
}
/**
* Deactivate conflicting plugins.
*
* @param string $type Plugin type.
*/
private function deactivate_conflicting_plugins( $type ) {
foreach ( self::get_conflicting_plugins() as $plugin => $plugin_type ) {
if ( $type === $plugin_type && is_plugin_active( $plugin ) ) {
if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
$message = sprintf(
/* translators: plugin name */
esc_html__( 'You are not allowed to deactivate this plugin: %s.', 'rank-math' ),
esc_html( $plugin )
);
GlobalHelper::add_notification(
$message,
[
'type' => 'error',
'classes' => 'is-dismissible',
]
);
continue;
}
deactivate_plugins( $plugin );
}
}
GlobalHelper::redirect( Security::remove_query_arg_raw( [ 'rank_math_deactivate_plugins', 'plugin_type', '_wpnonce' ] ) );
}
/**
* Function to set conflict plugin notification.
*
* @param string $type Plugin type.
*/
private static function set_notification( $type ) {
$message = sprintf(
/* translators: deactivation link */
esc_html__( 'Please keep only one SEO plugin active, otherwise, you might lose your rankings and traffic. %s.', 'rank-math' ),
'<a href="###DEACTIVATE_SEO_PLUGINS###">' . __( 'Click here to Deactivate', 'rank-math' ) . '</a>'
);
if ( 'sitemap' === $type ) {
$message = sprintf(
/* translators: deactivation link */
esc_html__( 'Please keep only one Sitemap plugin active, otherwise, you might lose your rankings and traffic. %s.', 'rank-math' ),
'<a href="###DEACTIVATE_SITEMAP_PLUGINS###">' . __( 'Click here to Deactivate', 'rank-math' ) . '</a>'
);
}
GlobalHelper::add_notification(
$message,
[
'id' => "conflicting_{$type}_plugins",
'type' => 'error',
'classes' => 'is-dismissible',
]
);
}
/**
* Function to remove conflict plugin notification.
*
* @param string $type Plugin type.
* @param string $plugin Plugin name.
*/
private function remove_notification( $type, $plugin ) {
foreach ( self::get_conflicting_plugins() as $file => $plugin_type ) {
if ( $plugin !== $file && $type === $plugin_type && is_plugin_active( $file ) ) {
return;
}
}
GlobalHelper::remove_notification( "conflicting_{$type}_plugins" );
}
/**
* Function to get all conflicting plugins.
*
* @return array
*/
private static function get_conflicting_plugins() {
$plugins = [
'wordpress-seo/wp-seo.php' => 'seo',
'wordpress-seo-premium/wp-seo-premium.php' => 'seo',
'wpseo-local/local-seo.php' => 'seo',
'wpseo-news/wpseo-news.php' => 'seo',
'wpseo-video/video-seo.php' => 'seo',
'all-in-one-seo-pack/all_in_one_seo_pack.php' => 'seo',
'all-in-one-seo-pack-pro/all_in_one_seo_pack.php' => 'seo',
'wp-seopress/seopress.php' => 'seo',
'wp-seopress-pro/seopress-pro.php' => 'seo',
];
if ( GlobalHelper::is_module_active( 'redirections' ) ) {
$plugins['redirection/redirection.php'] = 'seo';
}
if ( GlobalHelper::is_module_active( 'sitemap' ) ) {
$plugins['google-sitemap-generator/sitemap.php'] = 'sitemap';
$plugins['xml-sitemap-feed/xml-sitemap.php'] = 'sitemap';
}
if ( GlobalHelper::is_module_active( 'rich-snippet' ) ) {
$plugins['wp-schema-pro/wp-schema-pro.php'] = 'seo';
$plugins['all-in-one-schemaorg-rich-snippets/index.php'] = 'seo';
}
return $plugins;
}
/**
* Replace link inside notice dynamically to avoid issues with the nonce.
*
* @param string $output Notice output.
* @param string $message Notice message.
* @param array $options Notice options.
*
* @return string
*/
public function deactivate_plugins_link( $output, $message, $options ) {
if ( ! isset( $options['id'] ) || ! preg_match( '/conflicting_.*_plugins/', $options['id'] ) ) {
return $output;
}
$deactivate_url = Security::add_query_arg(
[
'rank_math_deactivate_plugins' => '1',
'plugin_type' => 'seo',
'_wpnonce' => wp_create_nonce( 'rank_math_deactivate_plugins' ),
],
admin_url( 'plugins.php' )
);
$output = str_replace( '###DEACTIVATE_SEO_PLUGINS###', $deactivate_url, $output );
$deactivate_sitemap_plugins_url = Security::add_query_arg(
[
'rank_math_deactivate_plugins' => '1',
'plugin_type' => 'sitemap',
'_wpnonce' => wp_create_nonce( 'rank_math_deactivate_plugins' ),
],
admin_url( 'plugins.php' )
);
$output = str_replace( '###DEACTIVATE_SITEMAP_PLUGINS###', $deactivate_sitemap_plugins_url, $output );
return $output;
}
/**
* Check search visibility
*
* @param integer $value Setting value.
*/
public function check_search_engine_visibility( $value ) {
if ( ! $value ) {
GlobalHelper::remove_notification( 'search_engine_visibility' );
return;
}
GlobalHelper::add_notification(
sprintf(
// translators: %1$s: general reading settings URL.
__( '<strong>SEO Notice</strong>: Your site is set to No Index and will not appear in search engines. You can change the Search engine visibility <a href="%1$s">from here</a>.', 'rank-math' ),
admin_url( 'options-reading.php' )
),
[
'type' => 'warning',
'id' => 'search_engine_visibility',
'classes' => 'is-dismissible',
]
);
}
}

View File

@@ -0,0 +1,200 @@
<?php
/**
* The Compatibility wizard step.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Compatibility implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
include_once $wizard->get_view( 'compatibility' );
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$wizard->cmb->add_field(
[
'id' => 'setup_mode',
'name' => '',
'type' => 'radio',
'options' => [
/* translators: Option Description */
'easy' => '<div class="rank-math-mode-title">' . sprintf( __( 'Easy %s', 'rank-math' ), '</div><p>' . __( 'For websites where you only want to change the basics and let Rank Math do most of the heavy lifting. Most settings are set to default as per industry best practices. One just has to set it and forget it.', 'rank-math' ) . '</p>' ),
/* translators: Option Description */
'advanced' => '<div class="rank-math-mode-title">' . sprintf( __( 'Advanced %s', 'rank-math' ), '</div><p>' . __( 'For the advanced users who want to control every SEO aspect of the website. You are offered options to change everything and have full control over the websites SEO.', 'rank-math' ) . '</p>' ),
/* translators: Option Description */
'custom' => '<div class="rank-math-mode-title">' . sprintf( __( 'Custom Mode %s', 'rank-math' ), '</div><p class="rank-math-mode-description">' . __( 'Select this if you have a custom Rank Math settings file you want to use.', 'rank-math' ) . '</p>' ),
],
'default' => Helper::get_settings( 'general.setup_mode', 'advanced' ),
'classes' => ! defined( 'RANK_MATH_PRO_FILE' ) ? 'rank-math-setup-mode is-free' : 'rank-math-setup-mode',
'desc' => '<strong class="note">' . __( 'Note', 'rank-math' ) . '</strong>' . __( 'You can easily switch between modes at any point.', 'rank-math' ),
]
);
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
$settings = wp_parse_args(
rank_math()->settings->all_raw(),
[ 'general' => '' ]
);
$settings['general']['setup_mode'] = ! empty( $values['setup_mode'] ) ? $values['setup_mode'] : 'easy';
if ( 'custom' === $settings['general']['setup_mode'] ) {
// Don't change, use custom imported value.
return true;
}
Helper::update_all_settings( $settings['general'], null, null );
return true;
}
/**
* Get conflicting plugins.
*
* @return array
*/
private function get_conflicting_plugins() {
$plugins_found = [];
$active_plugins = get_option( 'active_plugins' );
$conflicting_plugins = $this->get_conflicting_plugins_list();
foreach ( $conflicting_plugins as $plugin_slug => $plugin_name ) {
if ( in_array( $plugin_slug, $active_plugins, true ) !== false ) {
$plugins_found[ $plugin_slug ] = $plugin_name;
}
}
return $plugins_found;
}
/**
* Return list of conflicting plugins.
*
* @return array List of plugins in path => name format.
*/
private function get_conflicting_plugins_list() {
$plugins = [
'2-click-socialmedia-buttons/2-click-socialmedia-buttons.php' => '2 Click Social Media Buttons.',
'add-link-to-facebook/add-link-to-facebook.php' => 'Add Link to Facebook.',
'extended-wp-reset/extended-wp-reset.php' => 'Extended WP Reset.',
'add-meta-tags/add-meta-tags.php' => 'Add Meta Tags.',
'all-in-one-seo-pack/all_in_one_seo_pack.php' => 'All In One SEO Pack',
'easy-facebook-share-thumbnails/esft.php' => 'Easy Facebook Share Thumbnail.',
'facebook/facebook.php' => 'Facebook (official plugin).',
'facebook-awd/AWD_facebook.php' => 'Facebook AWD All in one.',
'facebook-featured-image-and-open-graph-meta-tags/fb-featured-image.php' => 'Facebook Featured Image & OG Meta Tags.',
'facebook-meta-tags/facebook-metatags.php' => 'Facebook Meta Tags.',
'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php' => 'Facebook Open Graph Meta Tags for WordPress.',
'facebook-revised-open-graph-meta-tag/index.php' => 'Facebook Revised Open Graph Meta Tag.',
'facebook-thumb-fixer/_facebook-thumb-fixer.php' => 'Facebook Thumb Fixer.',
'facebook-and-digg-thumbnail-generator/facebook-and-digg-thumbnail-generator.php' => 'Fedmich\'s Facebook Open Graph Meta.',
'network-publisher/networkpub.php' => 'Network Publisher.',
'nextgen-facebook/nextgen-facebook.php' => 'NextGEN Facebook OG.',
'opengraph/opengraph.php' => 'Open Graph.',
'open-graph-protocol-framework/open-graph-protocol-framework.php' => 'Open Graph Protocol Framework.',
'seo-facebook-comments/seofacebook.php' => 'SEO Facebook Comments.',
'seo-ultimate/seo-ultimate.php' => 'SEO Ultimate.',
'sexybookmarks/sexy-bookmarks.php' => 'Shareaholic.',
'shareaholic/sexy-bookmarks.php' => 'Shareaholic.',
'sharepress/sharepress.php' => 'SharePress.',
'simple-facebook-connect/sfc.php' => 'Simple Facebook Connect.',
'social-discussions/social-discussions.php' => 'Social Discussions.',
'social-sharing-toolkit/social_sharing_toolkit.php' => 'Social Sharing Toolkit.',
'socialize/socialize.php' => 'Socialize.',
'only-tweet-like-share-and-google-1/tweet-like-plusone.php' => 'Tweet, Like, Google +1 and Share.',
'wordbooker/wordbooker.php' => 'Wordbooker.',
'wordpress-seo/wp-seo.php' => 'Yoast SEO',
'wordpress-seo-premium/wp-seo-premium.php' => 'Yoast SEO Premium',
'wp-seopress/seopress.php' => 'SEOPress',
'wp-seopress-pro/seopress-pro.php' => 'SEOPress Pro',
'wpsso/wpsso.php' => 'WordPress Social Sharing Optimization.',
'wp-caregiver/wp-caregiver.php' => 'WP Caregiver.',
'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php' => 'WP Facebook Like Send & Open Graph Meta.',
'wp-facebook-open-graph-protocol/wp-facebook-ogp.php' => 'WP Facebook Open Graph protocol.',
'wp-ogp/wp-ogp.php' => 'WP-OGP.',
'zoltonorg-social-plugin/zosp.php' => 'Zolton.org Social Plugin.',
'all-in-one-schemaorg-rich-snippets/index.php' => 'All In One Schema Rich Snippets.',
'wp-schema-pro/wp-schema-pro.php' => 'Schema Pro',
'no-category-base-wpml/no-category-base-wpml.php' => 'No Category Base (WPML)',
'all-404-redirect-to-homepage/all-404-redirect-to-homepage.php' => 'All 404 Redirect to Homepage',
'remove-category-url/remove-category-url.php' => 'Remove Category URL',
];
$plugins = Helper::is_module_active( 'redirections' ) ? array_merge( $plugins, $this->get_redirection_conflicting_plugins() ) : $plugins;
$plugins = Helper::is_module_active( 'sitemap' ) ? array_merge( $plugins, $this->get_sitemap_conflicting_plugins() ) : $plugins;
return $plugins;
}
/**
* Redirection: conflicting plugins.
*
* @return array
*/
private function get_redirection_conflicting_plugins() {
return [
'redirection/redirection.php' => 'Redirection',
];
}
/**
* Sitemap: conflicting plugins.
*
* @return array
*/
private function get_sitemap_conflicting_plugins() {
return [
'google-sitemap-plugin/google-sitemap-plugin.php' => 'Google Sitemap (BestWebSoft).',
'xml-sitemaps/xml-sitemaps.php' => 'XML Sitemaps (Denis de Bernardy and Mike Koepke).',
'bwp-google-xml-sitemaps/bwp-simple-gxs.php' => 'Better WordPress Google XML Sitemaps (Khang Minh).',
'google-sitemap-generator/sitemap.php' => 'Google XML Sitemaps (Arne Brachhold).',
'xml-sitemap-feed/xml-sitemap.php' => 'XML Sitemap & Google News feeds (RavanH).',
'google-monthly-xml-sitemap/monthly-xml-sitemap.php' => 'Google Monthly XML Sitemap (Andrea Pernici).',
'simple-google-sitemap-xml/simple-google-sitemap-xml.php' => 'Simple Google Sitemap XML (iTx Technologies).',
'another-simple-xml-sitemap/another-simple-xml-sitemap.php' => 'Another Simple XML Sitemap.',
'xml-maps/google-sitemap.php' => 'Xml Sitemap (Jason Martens).',
'google-xml-sitemap-generator-by-anton-dachauer/adachauer-google-xml-sitemap.php' => 'Google XML Sitemap Generator by Anton Dachauer (Anton Dachauer).',
'wp-xml-sitemap/wp-xml-sitemap.php' => 'WP XML Sitemap (Team Vivacity).',
'sitemap-generator-for-webmasters/sitemap.php' => 'Sitemap Generator for Webmasters (iwebslogtech).',
'xml-sitemap-xml-sitemapcouk/xmls.php' => 'XML Sitemap - XML-Sitemap.co.uk (Simon Hancox).',
'sewn-in-xml-sitemap/sewn-xml-sitemap.php' => 'Sewn In XML Sitemap (jcow).',
'rps-sitemap-generator/rps-sitemap-generator.php' => 'RPS Sitemap Generator (redpixelstudios).',
];
}
}

View File

@@ -0,0 +1,198 @@
<?php
/**
* The Import wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\KB;
use RankMath\Admin\Importers\Detector;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Import implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
?>
<header>
<h1><?php esc_html_e( 'Import SEO Settings', 'rank-math' ); ?></h1>
<p><?php esc_html_e( 'You can import SEO settings from the following plugins:', 'rank-math' ); ?></p>
</header>
<?php $wizard->cmb->show_form(); ?>
<div id="import-progress-bar">
<div id="importProgress">
<div id="importBar"></div>
</div>
<span class="left"><strong><?php echo esc_html__( 'Importing: ', 'rank-math' ); ?></strong><span class="plugin-from"></span> </span>
<span class="right"><span class="number">0</span>% <?php echo esc_html__( 'Completed', 'rank-math' ); ?></span>
</div>
<textarea id="import-progress" class="import-progress-area large-text" disabled="disabled" rows="8"></textarea>
<footer class="form-footer wp-core-ui rank-math-ui">
<button type="submit" class="button button-secondary button-deactivate-plugins" data-deactivate-message="<?php esc_html_e( 'Deactivating Plugins...', 'rank-math' ); ?>"><?php esc_html_e( 'Skip, Don\'t Import Now', 'rank-math' ); ?></button>
<button type="submit" class="button button-primary button-continue" style="display:none"><?php esc_html_e( 'Continue', 'rank-math' ); ?></button>
<button type="submit" class="button button-primary button-import"><?php esc_html_e( 'Start Import', 'rank-math' ); ?></button>
</footer>
<?php
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$detector = new Detector();
$plugins = $detector->detect();
$plugins = $this->set_priority( $plugins );
$count = 0;
foreach ( $plugins as $slug => $plugin ) {
$checked = 'checked';
$multi_checked = 'multicheck-checked';
$choices = array_keys( $plugin['choices'] );
if ( isset( $plugin['checked'] ) && false === $plugin['checked'] ) {
$checked = '';
$multi_checked = '';
$choices = [];
}
$field_args = [
'id' => 'import_from_' . $slug,
'type' => 'group',
'description' => '<input type="checkbox" class="import-data" name="import[]" value="' . $slug . '" ' . $checked . ' data-plugin="' . $plugin['name'] . '" />',
'before_group' => 0 === $count ? '<h3 class="import-label">' . esc_html__( 'Input Data From:', 'rank-math' ) . '</h3>' : '',
'repeatable' => false,
'options' => [
'group_title' => $plugin['name'],
'sortable' => false,
'closed' => true,
],
];
$group_id = $wizard->cmb->add_field( $field_args );
$is_active = is_plugin_active( $plugin['file'] );
$wizard->cmb->add_group_field(
$group_id,
[
'id' => $slug . '_meta',
'type' => 'multicheck',
'repeatable' => false,
'desc' => $this->get_choice_description( $slug, $plugin, $is_active ),
'options' => $plugin['choices'],
'default' => $choices,
'dep' => [ [ 'import_from', $slug ] ],
'classes' => 'nob nopb cmb-multicheck-inline with-description ' . $multi_checked,
'attributes' => [ 'data-active' => $is_active ],
]
);
$count++;
// Add checkbox field to Recalculate SEO Scores.
// But not for Redirections.
if ( 'redirections' === $slug ) {
continue;
}
$wizard->cmb->add_group_field(
$group_id,
[
'id' => $slug . '_recalculate',
'type' => 'checkbox',
'repeatable' => false,
'desc' => esc_html__( 'Recalculate SEO Scores', 'rank-math' ),
'value' => 'recalculate',
'default' => 'recalculate',
'dep' => [ [ 'import_from', $slug ] ],
'classes' => 'nob nopb recalculate-scores',
'attributes' => [
'data-active' => $is_active,
'value' => 'recalculate',
],
]
);
}
}
/**
* Set plugins priority.
*
* @param array $plugins Array of detected plugins.
*
* @return array
*/
private function set_priority( $plugins ) {
$checked = false;
$priority = array_intersect( [ 'seopress', 'yoast', 'yoast-premium', 'aioseo' ], array_keys( $plugins ) );
foreach ( $priority as $slug ) {
if ( ! $checked ) {
$checked = true;
$plugins[ $slug ]['checked'] = true;
continue;
}
$plugins[ $slug ]['checked'] = false;
}
return $plugins;
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
delete_option( 'rank_math_yoast_block_posts' );
return true;
}
/**
* Get description for choice field.
*
* @param string $slug Plugin slug.
* @param array $plugin Plugin info array.
* @param boolean $is_active Is plugin active.
*
* @return string
*/
private function get_choice_description( $slug, $plugin, $is_active ) {
/* translators: 1 is plugin name */
$desc = 'aio-rich-snippet' === $slug ? esc_html__( 'Import meta data from the %1$s plugin.', 'rank-math' ) : esc_html__( 'Import settings and meta data from the %1$s plugin.', 'rank-math' );
/* translators: 2 is link to Knowledge Base article */
$desc .= ' ' . __( 'The process may take a few minutes if you have a large number of posts or pages <a href="%2$s" target="_blank">Learn more about the import process here.</a>', 'rank-math' );
if ( $is_active ) {
/* translators: 1 is plugin name */
$desc .= '<br>' . __( ' %1$s plugin will be disabled automatically moving forward to avoid conflicts. <strong>It is thus recommended to import the data you need now.</strong>', 'rank-math' );
}
return sprintf( wp_kses_post( $desc ), $plugin['name'], KB::get( 'seo-import', 'SW Import Step' ) );
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* The Monitor Redirection wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\KB;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Monitor_Redirection implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
?>
<?php $wizard->cmb->show_form(); ?>
<footer class="form-footer wp-core-ui">
<?php $wizard->get_skip_link(); ?>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save and Continue', 'rank-math' ); ?></button>
</footer>
<?php
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
// 404 Monitor Title.
$wizard->cmb->add_field(
[
'id' => '404_monitor_title',
'type' => 'raw',
'content' => sprintf( '<div class="cmb-row monitor-header text-center"><h1>%1$s</h1><div class="monitor-desc text-center">%2$s</div>', esc_html__( '404 Monitor', 'rank-math' ), esc_html__( 'Set default values for the 404 error monitor here.', 'rank-math' ) . '</div>' ),
]
);
// 404 Monitor.
$wizard->cmb->add_field(
[
'id' => '404_monitor',
'type' => 'toggle',
'name' => esc_html__( '404 Monitor', 'rank-math' ),
/* translators: Link to kb article */
'desc' => __( 'The 404 monitor will let you see if visitors or search engines bump into any <code>404 Not Found</code> error while browsing your site.', 'rank-math' ),
'default' => Helper::is_module_active( '404-monitor' ) ? 'on' : 'off',
]
);
// Redirections.
$wizard->cmb->add_field(
[
'id' => 'redirection_title',
'type' => 'raw',
'content' => sprintf( '<br><div class="cmb-row redirections-header text-center" style="border-top:0;"><h1>%1$s</h1><div class="redirections-desc text-center">%2$s %3$s</div>', esc_html__( 'Redirections', 'rank-math' ), esc_html__( 'Set default values for the redirection module from here.', 'rank-math' ), '<a href="' . KB::get( 'redirections', 'SW Redirection Step' ) . '" target="_blank">' . esc_html__( 'Learn more about Redirections.', 'rank-math' ) . '</a></div>' ),
]
);
$wizard->cmb->add_field(
[
'id' => 'redirections',
'type' => 'toggle',
'name' => esc_html__( 'Redirections', 'rank-math' ),
'desc' => esc_html__( 'Set up temporary or permanent redirections. Combined with the 404 monitor, you can easily redirect faulty URLs on your site, or add custom redirections.', 'rank-math' ),
'default' => Helper::is_module_active( 'redirections' ) ? 'on' : 'off',
]
);
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
Helper::update_modules(
[
'404-monitor' => $values['404_monitor'],
'redirections' => $values['redirections'],
]
);
return true;
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* The Optimization wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\KB;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Optimization implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
?>
<header>
<h1><?php esc_html_e( 'SEO Tweaks', 'rank-math' ); ?> </h1>
<p>
<?php
/* translators: Link to How to Optimization KB article */
printf( esc_html__( 'Automate some of your SEO tasks like making external links nofollow, redirecting attachment pages, etc. %s', 'rank-math' ), '<a href="' . esc_url( KB::get( 'seo-tweaks', 'SW Optimization Step' ) ) . '" target="_blank">' . esc_html__( 'Learn More', 'rank-math' ) . '</a>' );
?>
</p>
</header>
<?php $wizard->cmb->show_form(); ?>
<footer class="form-footer wp-core-ui rank-math-ui">
<?php $wizard->get_skip_link(); ?>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save and Continue', 'rank-math' ); ?></button>
</footer>
<?php
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$wizard->cmb->add_field(
[
'id' => 'noindex_empty_taxonomies',
'type' => 'toggle',
'name' => esc_html__( 'Noindex Empty Category and Tag Archives', 'rank-math' ),
'desc' => wp_kses_post( __( 'Setting empty archives to <code>noindex</code> is useful for avoiding indexation of thin content pages and dilution of page rank. As soon as a post is added, the page is updated to <code>index</code>.', 'rank-math' ) ),
'default' => Helper::get_settings( 'titles.noindex_empty_taxonomies' ) ? 'on' : 'off',
'classes' => 'rank-math-advanced-option',
]
);
$wizard->cmb->add_field(
[
'id' => 'nofollow_external_links',
'type' => 'toggle',
'name' => esc_html__( 'Nofollow External Links', 'rank-math' ),
'desc' => wp_kses_post( __( 'Automatically add <code>rel="nofollow"</code> attribute for external links appearing in your posts, pages, and other post types. The attribute is dynamically applied when the content is displayed, and the stored content is not changed.', 'rank-math' ) ),
'default' => Helper::get_settings( 'general.nofollow_external_links' ) ? 'on' : 'off',
'classes' => 'rank-math-advanced-option',
]
);
$wizard->cmb->add_field(
[
'id' => 'new_window_external_links',
'type' => 'toggle',
'name' => esc_html__( 'Open External Links in New Tab/Window', 'rank-math' ),
'desc' => wp_kses_post( __( 'Automatically add a <code>target="_blank"</code> attribute to external links appearing in your posts, pages, and other post types. The attributes are applied when the content is displayed, which does not change the stored content.', 'rank-math' ) ),
'default' => Helper::get_settings( 'general.new_window_external_links' ) ? 'on' : 'off',
]
);
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
$settings = rank_math()->settings->all_raw();
$settings['titles']['noindex_empty_taxonomies'] = $values['noindex_empty_taxonomies'];
if ( isset( $values['attachment_redirect_urls'] ) && 'on' === $values['attachment_redirect_urls'] ) {
$settings['general']['attachment_redirect_urls'] = $values['attachment_redirect_urls'];
$settings['general']['attachment_redirect_default'] = $values['attachment_redirect_default'];
}
$settings['general']['nofollow_external_links'] = isset( $values['nofollow_external_links'] ) ? $values['nofollow_external_links'] : 'off';
$settings['general']['new_window_external_links'] = $values['new_window_external_links'];
Helper::update_all_settings( $settings['general'], $settings['titles'], null );
Helper::schedule_flush_rewrite();
return true;
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* The Ready wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Ready implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
include_once $wizard->get_view( 'ready' );
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
Helper::is_configured( true );
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
return true;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* The Role wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\Helper;
use RankMath\Role_Manager\Capability_Manager;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Role implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
?>
<header>
<h1><?php esc_html_e( 'Role Manager', 'rank-math' ); ?></h1>
<p><?php esc_html_e( 'Set capabilities here.', 'rank-math' ); ?></p>
</header>
<?php $wizard->cmb->show_form(); ?>
<footer class="form-footer wp-core-ui">
<?php $wizard->get_skip_link(); ?>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save and Continue', 'rank-math' ); ?></button>
</footer>
<?php
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$wizard->cmb->add_field(
[
'id' => 'role_manager',
'type' => 'toggle',
'name' => esc_html__( 'Role Manager', 'rank-math' ),
/* translators: Link to kb article */
'desc' => __( 'The Role Manager allows you to use WordPress roles to control which of your site users can have edit or view access to Rank Math\'s settings.', 'rank-math' ),
'default' => Helper::is_module_active( 'role-manager' ) ? 'on' : 'off',
]
);
$defaults = Helper::get_roles_capabilities();
$caps = Capability_Manager::get()->get_capabilities();
$cap_count = count( $caps );
foreach ( Helper::get_roles() as $role => $label ) {
$default = isset( $defaults[ $role ] ) ? $defaults[ $role ] : [];
$wizard->cmb->add_field(
[
'id' => esc_attr( $role ),
'type' => 'multicheck_inline',
'name' => translate_user_role( $label ),
'options' => $caps,
'default' => $default,
'classes' => 'cmb-big-labels' . ( count( $default ) === $cap_count ? ' multicheck-checked' : '' ),
'dep' => [ [ 'role_manager', 'on' ] ],
]
);
}
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
if ( empty( $values ) ) {
return false;
}
Helper::update_modules( [ 'role-manager' => $values['role_manager'] ] );
Helper::set_capabilities( $values );
return true;
}
}

View File

@@ -0,0 +1,191 @@
<?php
/**
* The Schema_Markup wizard step
*
* @since 1.0.32
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\KB;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Schema_Markup implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
?>
<header>
<h1><?php esc_html_e( 'Schema Markup ', 'rank-math' ); ?> </h1>
<p><?php esc_html_e( 'Schema adds metadata to your website, resulting in rich search results and more traffic.', 'rank-math' ); ?></p>
</header>
<?php $wizard->cmb->show_form(); ?>
<footer class="form-footer wp-core-ui rank-math-ui">
<a href="<?php echo esc_url( Helper::get_admin_url() ); ?>" class="button button-secondary button-skip"><?php esc_html_e( 'Skip Step', 'rank-math' ); ?></a>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save and Continue', 'rank-math' ); ?></button>
</footer>
<?php
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$wizard->cmb->add_field(
[
'id' => 'rich_snippet',
'type' => 'toggle',
'name' => esc_html__( 'Schema Type', 'rank-math' ),
'desc' => esc_html__( 'Use automatic structured data to mark up content, to help Google better understand your content\'s context for display in Search. You can set different defaults for your posts here.', 'rank-math' ),
'default' => Helper::is_module_active( 'rich-snippet' ) ? 'on' : 'off',
]
);
foreach ( Helper::get_accessible_post_types() as $post_type ) {
if ( 'attachment' === $post_type ) {
continue;
}
$wizard->cmb->add_field( $this->get_field_args( $post_type ) );
// Article fields.
$article_dep = [ 'relation' => 'and' ] + [ [ 'rich_snippet', 'on' ] ];
$article_dep[] = [ 'pt_' . $post_type . '_default_rich_snippet', 'article' ];
/* translators: Google article snippet doc link */
$article_desc = 'person' === Helper::get_settings( 'titles.knowledgegraph_type' ) ? '<div class="notice notice-warning inline rank-math-notice" style="margin-left:0;"><p>' . sprintf( __( 'Google does not allow Person as the Publisher for articles. Organization will be used instead. You can read more about this <a href="%s" target="_blank">here</a>.', 'rank-math' ), KB::get( 'google-article-schema' ) ) . '</p></div>' : '';
$wizard->cmb->add_field(
[
'id' => 'pt_' . $post_type . '_default_article_type',
'type' => 'radio_inline',
'name' => esc_html__( 'Article Type', 'rank-math' ),
'options' => [
'Article' => esc_html__( 'Article', 'rank-math' ),
'BlogPosting' => esc_html__( 'Blog Post', 'rank-math' ),
'NewsArticle' => esc_html__( 'News Article', 'rank-math' ),
],
'default' => Helper::get_settings( 'titles.pt_' . $post_type . '_default_article_type', 'post' === $post_type ? 'BlogPosting' : 'Article' ),
'dep' => $article_dep,
'desc' => $article_desc,
]
);
}
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
$settings = rank_math()->settings->all_raw();
Helper::update_modules( [ 'rich-snippet' => $values['rich_snippet'] ] );
// Schema.
if ( 'on' === $values['rich_snippet'] ) {
$this->save_rich_snippet( $settings, $values );
}
Helper::update_all_settings( $settings['general'], $settings['titles'], null );
return Helper::get_admin_url();
}
/**
* Save rich snippet values for post type.
*
* @param array $settings Array of setting.
* @param array $values Values to save.
*/
private function save_rich_snippet( &$settings, $values ) {
foreach ( Helper::get_accessible_post_types() as $post_type ) {
if ( 'attachment' === $post_type ) {
continue;
}
$id = 'pt_' . $post_type . '_default_rich_snippet';
$article_type = 'pt_' . $post_type . '_default_article_type';
$settings['titles'][ $id ] = $values[ $id ];
$settings['titles'][ $article_type ] = $values[ $article_type ];
}
}
/**
* Get field arguments.
*
* @param string $post_type Post type.
*
* @return array
*/
private function get_field_args( $post_type ) {
$object = get_post_type_object( $post_type );
$field_id = 'pt_' . $post_type . '_default_rich_snippet';
/* translators: Post type name */
$field_name = sprintf( esc_html__( 'Schema Type for %s', 'rank-math' ), $object->label );
$richsnp_default = [
'post' => 'article',
'product' => 'product',
];
if ( 'product' === $post_type ) {
return [
'id' => $field_id,
'type' => 'radio_inline',
'name' => $field_name,
'desc' => __( 'Default rich snippet selected when creating a new product.', 'rank-math' ),
'options' => [
'off' => esc_html__( 'None', 'rank-math' ),
'product' => esc_html__( 'Product', 'rank-math' ),
],
'default' => Helper::get_settings( 'titles.pt_' . $post_type . '_default_rich_snippet', ( isset( $richsnp_default[ $post_type ] ) ? $richsnp_default[ $post_type ] : 'product' ) ),
];
}
$schema_types = Helper::choices_rich_snippet_types( esc_html__( 'None (Click here to set one)', 'rank-math' ), $post_type );
$type = 'select';
$attributes = [ 'data-s2' => '' ];
$default = isset( $richsnp_default[ $post_type ] ) ? $richsnp_default[ $post_type ] : 'off';
if ( 2 === count( $schema_types ) ) {
$type = 'radio_inline';
$attributes = '';
$default = array_key_last( $schema_types );
}
$default = Helper::get_settings( 'titles.pt_' . $post_type . '_default_rich_snippet', $default );
return [
'id' => $field_id,
'type' => $type,
'name' => $field_name,
'desc' => esc_html__( 'Default rich snippet selected when creating a new post of this type. ', 'rank-math' ),
'options' => $schema_types,
'dep' => [ [ 'rich_snippet', 'on' ] ],
'default' => $default ? $default : 'off',
'attributes' => $attributes,
];
}
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* The Search Console wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Search_Console implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
?>
<header>
<h1><?php esc_html_e( 'Connect Google&trade; Services', 'rank-math' ); ?> </h1>
<p>
<?php
/* translators: Link to How to Setup Google Search Console KB article */
printf( esc_html__( 'Rank Math automates everything, use below button to connect your site with Google Search Console and Google Analytics. It will verify your site and submit sitemaps automatically. %s', 'rank-math' ), '<a href="' . esc_url( KB::get( 'help-analytics', 'SW Analytics Step Description' ) ) . '" target="_blank">' . esc_html__( 'Read more about it here.', 'rank-math' ) . '</a>' );
?>
</p>
</header>
<?php $wizard->cmb->show_form(); ?>
<footer class="form-footer wp-core-ui rank-math-ui">
<?php $wizard->get_skip_link(); ?>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save and Continue', 'rank-math' ); ?></button>
</footer>
<?php
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$wizard->cmb->add_field(
[
'id' => 'search_console_ui',
'type' => 'raw',
'file' => __DIR__ . '/views/search-console-ui.php',
]
);
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
$settings = rank_math()->settings->all_raw();
$settings['general']['console_email_reports'] = Param::post( 'console_email_reports' );
Helper::update_all_settings( $settings['general'], null, null );
// For Search console.
$value = [
'country' => Param::post( 'site-console-country' ),
'profile' => Param::post( 'site-console-profile' ),
'enable_index_status' => Param::post( 'enable-index-status' ),
];
update_option( 'rank_math_google_analytic_profile', $value );
// For Analytics.
$analytic_value = [
'adsense_id' => Param::post( 'site-adsense-account' ),
'account_id' => Param::post( 'site-analytics-account' ),
'property_id' => Param::post( 'site-analytics-property' ),
'view_id' => Param::post( 'site-analytics-view' ),
'measurement_id' => Param::post( 'measurementID' ),
'stream_name' => Param::post( 'streamName' ),
'country' => Param::post( 'site-analytics-country' ),
'install_code' => 'on' === Param::post( 'install-code' ) ? true : false,
'anonymize_ip' => 'on' === Param::post( 'anonymize-ip' ) ? true : false,
'local_ga_js' => 'on' === Param::post( 'local-ga-js' ) ? true : false,
'exclude_loggedin' => 'on' === Param::post( 'exclude-loggedin' ) ? true : false,
];
update_option( 'rank_math_google_analytic_options', $analytic_value );
return true;
}
}

View File

@@ -0,0 +1,222 @@
<?php
/**
* The Sitemap wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\KB;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Sitemap implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
?>
<header>
<h1><?php esc_html_e( 'Sitemap', 'rank-math' ); ?> </h1>
<p>
<?php
/* translators: Link to How to Setup Sitemap KB article */
printf( esc_html__( 'Choose your Sitemap configuration and select which type of posts or pages you want to include in your Sitemaps. %s', 'rank-math' ), '<a href="' . KB::get( 'configure-sitemaps', 'SW Sitemap Step' ) . '" target="_blank">' . esc_html__( 'Learn more.', 'rank-math' ) . '</a>' );
?>
</p>
</header>
<?php $wizard->cmb->show_form(); ?>
<footer class="form-footer wp-core-ui rank-math-ui">
<?php $wizard->get_skip_link(); ?>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save and Continue', 'rank-math' ); ?></button>
</footer>
<?php
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$wizard->cmb->add_field(
[
'id' => 'sitemap',
'type' => 'toggle',
'name' => esc_html__( 'Sitemaps', 'rank-math' ),
'desc' => esc_html__( 'XML Sitemaps help search engines index your website&#039;s content more effectively.', 'rank-math' ),
'default' => Helper::is_module_active( 'sitemap' ) ? 'on' : 'off',
]
);
$wizard->cmb->add_field(
[
'id' => 'include_images',
'type' => 'toggle',
'name' => esc_html__( 'Include Images', 'rank-math' ),
'desc' => esc_html__( 'Include reference to images from the post content in sitemaps. This helps search engines index your images better.', 'rank-math' ),
'default' => Helper::get_settings( 'sitemap.include_images' ) ? 'on' : 'off',
'classes' => 'features-child',
'dep' => [ [ 'sitemap', 'on' ] ],
]
);
// Post Types.
$post_types = $this->get_post_types();
$wizard->cmb->add_field(
[
'id' => 'sitemap_post_types',
'type' => 'multicheck',
'name' => esc_html__( 'Public Post Types', 'rank-math' ),
'desc' => esc_html__( 'Select post types to enable SEO options for them and include them in the sitemap.', 'rank-math' ),
'options' => $post_types['post_types'],
'default' => $post_types['defaults'],
'classes' => 'features-child cmb-multicheck-inline' . ( count( $post_types['post_types'] ) === count( $post_types['defaults'] ) ? ' multicheck-checked' : '' ),
'dep' => [ [ 'sitemap', 'on' ] ],
]
);
// Taxonomies.
$taxonomies = $this->get_taxonomies();
$wizard->cmb->add_field(
[
'id' => 'sitemap_taxonomies',
'type' => 'multicheck',
'name' => esc_html__( 'Public Taxonomies', 'rank-math' ),
'desc' => esc_html__( 'Select taxonomies to enable SEO options for them and include them in the sitemap.', 'rank-math' ),
'options' => $taxonomies['taxonomies'],
'default' => $taxonomies['defaults'],
'classes' => 'features-child cmb-multicheck-inline' . ( count( $taxonomies['taxonomies'] ) === count( $taxonomies['defaults'] ) ? ' multicheck-checked' : '' ),
'dep' => [ [ 'sitemap', 'on' ] ],
]
);
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
$settings = rank_math()->settings->all_raw();
Helper::update_modules( [ 'sitemap' => $values['sitemap'] ] );
if ( 'on' === $values['sitemap'] ) {
$settings['sitemap']['include_images'] = $values['include_images'];
$settings = $this->save_post_types( $settings, $values );
$settings = $this->save_taxonomies( $settings, $values );
Helper::update_all_settings( null, null, $settings['sitemap'] );
}
Helper::schedule_flush_rewrite();
return true;
}
/**
* Get post type data.
*
* @return array
*/
private function get_post_types() {
$p_defaults = [];
$post_types = Helper::choices_post_types();
unset( $post_types['attachment'] );
foreach ( $post_types as $post_type => $object ) {
if ( true === Helper::get_settings( "sitemap.pt_{$post_type}_sitemap" ) ) {
$p_defaults[] = $post_type;
}
}
return [
'defaults' => $p_defaults,
'post_types' => $post_types,
];
}
/**
* Get taxonomies data.
*
* @return array
*/
private function get_taxonomies() {
$t_defaults = [];
$taxonomies = Helper::get_accessible_taxonomies();
unset( $taxonomies['post_tag'], $taxonomies['post_format'], $taxonomies['product_tag'] );
$taxonomies = wp_list_pluck( $taxonomies, 'label', 'name' );
foreach ( $taxonomies as $taxonomy => $label ) {
if ( true === Helper::get_settings( "sitemap.tax_{$taxonomy}_sitemap" ) ) {
$t_defaults[] = $taxonomy;
}
}
return [
'defaults' => $t_defaults,
'taxonomies' => $taxonomies,
];
}
/**
* Save Post Types
*
* @param array $settings Array of all settings.
* @param array $values Array of posted values.
*
* @return array
*/
private function save_post_types( $settings, $values ) {
$post_types = Helper::choices_post_types();
if ( ! isset( $values['sitemap_post_types'] ) ) {
$values['sitemap_post_types'] = [];
}
foreach ( $post_types as $post_type => $object ) {
$settings['sitemap'][ "pt_{$post_type}_sitemap" ] = in_array( $post_type, $values['sitemap_post_types'], true ) ? 'on' : 'off';
}
return $settings;
}
/**
* Save Taxonomies
*
* @param array $settings Array of all settings.
* @param array $values Array of posted values.
*
* @return array
*/
private function save_taxonomies( $settings, $values ) {
$taxonomies = Helper::get_accessible_taxonomies();
$taxonomies = wp_list_pluck( $taxonomies, 'label', 'name' );
if ( ! isset( $values['sitemap_taxonomies'] ) ) {
$values['sitemap_taxonomies'] = [];
}
foreach ( $taxonomies as $taxonomy => $label ) {
$settings['sitemap'][ "tax_{$taxonomy}_sitemap" ] = in_array( $taxonomy, $values['sitemap_taxonomies'], true ) ? 'on' : 'off';
}
return $settings;
}
}

View File

@@ -0,0 +1,350 @@
<?php
/**
* The Your Site wizard step
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Step class.
*/
class Your_Site implements Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard ) {
include_once $wizard->get_view( 'your-site' );
}
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard ) {
$displayname = $this->get_site_display_name();
$wizard->cmb->add_field(
[
'id' => 'site_type',
'type' => 'select',
/* translators: sitename */
'name' => sprintf( esc_html__( '%1$s is a&hellip;', 'rank-math' ), $displayname ),
'options' => $this->get_type_choices(),
'default' => $this->get_default_site_type(),
]
);
$wizard->cmb->add_field(
[
'id' => 'business_type',
'type' => 'select',
'name' => esc_html__( 'Business Type', 'rank-math' ),
'desc' => esc_html__( 'Select the type that best describes your business. If you can\'t find one that applies exactly, use the generic "Organization" or "Local Business" types.', 'rank-math' ),
'options' => Helper::choices_business_types(),
'attributes' => [
'data-s2' => '',
'data-default' => Helper::get_settings( 'titles.local_business_type' ) ? '0' : '1',
],
'default' => Helper::get_settings( 'titles.local_business_type' ),
'dep' => $this->get_type_dependency(),
]
);
$wizard->cmb->add_field(
[
'id' => 'website_name',
'type' => 'text',
'name' => esc_html__( 'Website Name', 'rank-math' ),
'default' => Helper::get_settings( 'titles.website_name', $displayname ),
'desc' => esc_html__( 'Enter the name of your site to appear in search results.', 'rank-math' ),
]
);
$wizard->cmb->add_field(
[
'id' => 'website_alternate_name',
'type' => 'text',
'default' => Helper::get_settings( 'titles.website_alternate_name' ),
'name' => esc_html__( 'Website Alternate Name', 'rank-math' ),
'desc' => esc_html__( 'An alternate version of your site name (for example, an acronym or shorter name).', 'rank-math' ),
]
);
$wizard->cmb->add_field(
[
'id' => 'company_name',
'type' => 'text',
'name' => esc_html__( 'Person/Organization Name', 'rank-math' ),
'desc' => esc_html__( 'Your name or company name intended to feature in Google\'s Knowledge Panel.', 'rank-math' ),
'default' => Helper::get_settings( 'titles.knowledgegraph_name', $displayname ),
]
);
$wizard->cmb->add_field(
[
'id' => 'company_logo',
'type' => 'file',
'name' => esc_html__( 'Logo for Google', 'rank-math' ),
'default' => $this->get_default_logo(),
'desc' => __( '<strong>Min Size: 112Χ112px</strong>.<br />A squared image is preferred by the search engines.', 'rank-math' ),
'options' => [ 'url' => false ],
]
);
$wizard->cmb->add_field(
[
'id' => 'open_graph_image',
'type' => 'file',
'name' => esc_html__( 'Default Social Share Image', 'rank-math' ),
'desc' => __( 'When a featured image or an OpenGraph Image is not set for individual posts/pages/CPTs, this image will be used as a fallback thumbnail when your post is shared on Facebook. <strong>The recommended image size is 1200 x 630 pixels.</strong>', 'rank-math' ),
'options' => [ 'url' => false ],
'default' => Helper::get_settings( 'titles.open_graph_image' ),
]
);
}
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard ) {
$settings = wp_parse_args(
rank_math()->settings->all_raw(),
[
'titles' => '',
'sitemap' => '',
]
);
$values = wp_parse_args(
$values,
[
'company_name' => '',
'company_logo' => '',
'company_logo_id' => '',
'open_graph_image' => '',
'open_graph_image_id' => '',
]
);
// Save these settings.
$functions = [ 'save_local_seo', 'save_open_graph', 'save_post_types', 'save_taxonomies' ];
foreach ( $functions as $function ) {
$settings = $this->$function( $settings, $values );
}
$business_type = [ 'news', 'business', 'webshop', 'otherbusiness' ];
$modules = [ 'local-seo' => in_array( $values['site_type'], $business_type, true ) ? 'on' : 'off' ];
$users = get_users( [ 'role__in' => [ 'administrator', 'editor', 'author', 'contributor' ] ] );
if ( count( $users ) > 1 && ! is_plugin_active( 'members/members.php' ) ) {
$modules['role-manager'] = 'on';
}
set_transient( '_rank_math_site_type', $values['site_type'] );
Helper::update_modules( $modules );
Helper::update_all_settings( null, $settings['titles'], null );
return true;
}
/**
* Save Local Seo
*
* @param array $settings Array of all settings.
* @param array $values Array of posted values.
*
* @return array
*/
private function save_local_seo( $settings, $values ) {
switch ( $values['site_type'] ) {
case 'blog':
case 'portfolio':
$settings['titles']['knowledgegraph_type'] = 'person';
$settings['titles']['knowledgegraph_name'] = $values['company_name'];
$settings['titles']['knowledgegraph_logo'] = $values['company_logo'];
$settings['titles']['knowledgegraph_logo_id'] = $values['company_logo_id'];
break;
case 'news':
case 'webshop':
case 'business':
case 'otherbusiness':
$settings['titles']['knowledgegraph_type'] = 'company';
$settings['titles']['knowledgegraph_name'] = $values['company_name'];
$settings['titles']['knowledgegraph_logo'] = $values['company_logo'];
$settings['titles']['local_business_type'] = $values['business_type'];
$settings['titles']['knowledgegraph_logo_id'] = $values['company_logo_id'];
break;
case 'otherpersonal':
$settings['titles']['knowledgegraph_type'] = 'person';
$settings['titles']['knowledgegraph_name'] = $values['company_name'];
break;
}
foreach ( [ 'website_name', 'website_alternate_name' ] as $key ) {
if ( empty( $values[ $key ] ) ) {
continue;
}
$settings['titles'][ $key ] = $values[ $key ];
}
return $settings;
}
/**
* Save Open Graph
*
* @param array $settings Array of all settings.
* @param array $values Array of posted values.
*
* @return array
*/
private function save_open_graph( $settings, $values ) {
if ( ! empty( $values['open_graph_image_id'] ) ) {
$settings['titles']['open_graph_image'] = $values['open_graph_image'];
$settings['titles']['open_graph_image_id'] = $values['open_graph_image_id'];
}
if ( empty( $values['company_logo_id'] ) ) {
unset( $settings['titles']['knowledgegraph_logo'] );
unset( $settings['titles']['knowledgegraph_logo_id'] );
}
return $settings;
}
/**
* Save Post Types
*
* @param array $settings Array of all settings.
* @param array $values Array of posted values.
*
* @return array
*/
private function save_post_types( $settings, $values ) {
foreach ( Helper::get_accessible_post_types() as $post_type => $label ) {
if ( 'attachment' === $post_type ) {
continue;
}
$settings['titles'][ "pt_{$post_type}_add_meta_box" ] = 'on';
}
return $settings;
}
/**
* Save Taxonomies
*
* @param array $settings Array of all settings.
* @param array $values Array of posted values.
*
* @return array
*/
private function save_taxonomies( $settings, $values ) {
$taxonomies = Admin_Helper::get_taxonomies_options();
array_shift( $taxonomies );
foreach ( $taxonomies as $taxonomy => $label ) {
$settings['titles'][ "tax_{$taxonomy}_add_meta_box" ] = 'on';
}
return $settings;
}
/**
* Get site display name.
*
* @return string
*/
protected function get_site_display_name() {
$siteurl = get_bloginfo( 'url' );
$sitename = get_bloginfo( 'title' );
return $sitename ? $sitename : $siteurl;
}
/**
* Get default logo.
*
* @return string
*/
private function get_default_logo() {
if ( defined( 'MTS_THEME_NAME' ) && MTS_THEME_NAME ) {
$theme_options = get_option( MTS_THEME_NAME );
if ( isset( $theme_options['mts_logo'] ) ) {
return wp_get_attachment_url( $theme_options['mts_logo'] );
}
}
if ( current_theme_supports( 'custom-logo' ) && ! empty( get_theme_mod( 'custom_logo' ) ) ) {
return wp_get_attachment_url( get_theme_mod( 'custom_logo' ) );
}
return Helper::get_settings( 'titles.knowledgegraph_logo' );
}
/**
* Get default site type.
*
* @return string
*/
private function get_default_site_type() {
$default_type = get_transient( '_rank_math_site_type' );
return $default_type ? $default_type : ( class_exists( 'Easy_Digital_Downloads' ) || class_exists( 'WooCommerce' ) ? 'webshop' : 'blog' );
}
/**
* Get type dependecy.
*
* @return array
*/
private function get_type_dependency() {
return [
[ 'site_type', 'news' ],
[ 'site_type', 'business' ],
[ 'site_type', 'webshop' ],
[ 'site_type', 'otherbusiness' ],
];
}
/**
* Get type choices.
*
* @return array
*/
private function get_type_choices() {
return [
'blog' => esc_html__( 'Personal Blog', 'rank-math' ),
'news' => esc_html__( 'Community Blog/News Site', 'rank-math' ),
'portfolio' => esc_html__( 'Personal Portfolio', 'rank-math' ),
'business' => esc_html__( 'Small Business Site', 'rank-math' ),
'webshop' => esc_html__( 'Webshop', 'rank-math' ),
'otherpersonal' => esc_html__( 'Other Personal Website', 'rank-math' ),
'otherbusiness' => esc_html__( 'Other Business Website', 'rank-math' ),
];
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* The wizard step contract.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Wizard
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Wizard;
defined( 'ABSPATH' ) || exit;
/**
* Wizard step contract.
*/
interface Wizard_Step {
/**
* Render step body.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function render( $wizard );
/**
* Render form for step.
*
* @param object $wizard Wizard class instance.
*
* @return void
*/
public function form( $wizard );
/**
* Save handler for step.
*
* @param array $values Values to save.
* @param object $wizard Wizard class instance.
*
* @return bool
*/
public function save( $values, $wizard );
}

View File

@@ -0,0 +1,178 @@
<?php
/**
* Setup wizard compatibility step.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\Helper;
use RankMath\KB;
defined( 'ABSPATH' ) || exit;
global $wp_version;
update_option( 'rank_math_wizard_completed', true );
$php_version = phpversion();
$php_version_ok = version_compare( $php_version, rank_math()->php_version, '>' );
$php_version_recommend = version_compare( $php_version, '7.4', '<' );
$dom_ext = extension_loaded( 'dom' );
$simplexml_ext = extension_loaded( 'SimpleXML' );
$image_ext = extension_loaded( 'gd' ) || extension_loaded( 'imagick' );
$mb_string = extension_loaded( 'mbstring' );
$openssl = extension_loaded( 'openssl' );
$base64_func = function_exists( 'base64_encode' ) && function_exists( 'base64_decode' ) && (bool) base64_decode( base64_encode( '1' ) );
$all_good = $php_version_ok && $dom_ext && $simplexml_ext && $image_ext && $mb_string && $openssl && $base64_func;
?>
<?php $wizard->cmb->show_form(); ?>
<?php
if ( $all_good ) :
?>
<br>
<h2 class="text-center compatibility-check">
<i class="dashicons <?php echo $php_version_recommend ? 'dashicons-warning' : 'dashicons-yes'; ?>"></i> <?php esc_html_e( 'Your website is compatible to run Rank Math SEO', 'rank-math' ); ?>
<a href="#" data-target="rank-math-compatibility-collapsible" class="rank-math-collapsible-trigger">
<span class="dashicons dashicons-arrow-down-alt2"><span><?php esc_html_e( 'More', 'rank-math' ); ?></span></span>
<span class="dashicons dashicons-arrow-up-alt2"><span><?php esc_html_e( 'Less', 'rank-math' ); ?></span></span>
</a>
</h2>
<div id="rank-math-compatibility-collapsible" class="rank-math-collapsible-content">
<?php endif; ?>
<table class="form-table">
<tr class="check-<?php echo $php_version_ok ? 'yes' : 'no'; ?>">
<th>
<?php
if ( $php_version_ok ) {
/* translators: php version */
printf( esc_html__( 'Your PHP Version: %s', 'rank-math' ), $php_version );
if ( $php_version_recommend ) {
?>
<?php echo ' | ' . esc_html__( 'Recommended: PHP 7.4 or later', 'rank-math' ); ?>
<p class="description">
<?php
echo ( ! Helper::is_whitelabel() ) ?
esc_html__( 'Rank Math is compatible with your PHP version but we recommend updating to PHP 7.4 for increased speed and security.', 'rank-math' ) . ' <a href="' . KB::get( 'requirements', 'Setup wizard compatibility step' ) . '" target="_blank">' . esc_html__( 'More information', 'rank-math' ) . '</a>' :
esc_html__( 'This plugin is compatible with your PHP version but we recommend updating to PHP 7.4 for increased speed and security.', 'rank-math' );
?>
</p>
<?php
}
} else {
/* translators: php version */
printf( esc_html__( 'Your PHP Version: %s | Recommended version: 7.4 | Minimal required: 7.2', 'rank-math' ), $php_version );
}
?>
</th>
<td><span class="dashicons dashicons-<?php echo $php_version_ok ? ( $php_version_recommend ? 'warning' : 'yes' ) : 'no'; ?>"></span></td>
</tr>
<tr class="check-yes">
<th>
<?php
echo esc_html__( 'You are using the recommended WordPress version.', 'rank-math' );
?>
</th>
<td><span class="dashicons dashicons-yes"></span></td>
</tr>
<tr class="check-<?php echo $dom_ext ? 'yes' : 'no'; ?>">
<th>
<?php echo $dom_ext ? esc_html__( 'PHP DOM Extension installed', 'rank-math' ) : esc_html__( 'PHP DOM Extension missing', 'rank-math' ); ?>
</th>
<td><span class="dashicons dashicons-<?php echo $dom_ext ? 'yes' : 'no'; ?>"></span></td>
</tr>
<tr class="check-<?php echo $simplexml_ext ? 'yes' : 'no'; ?>">
<th>
<?php echo $simplexml_ext ? esc_html__( 'PHP SimpleXML Extension installed', 'rank-math' ) : esc_html__( 'PHP SimpleXML Extension missing', 'rank-math' ); ?>
</th>
<td><span class="dashicons dashicons-<?php echo $simplexml_ext ? 'yes' : 'no'; ?>"></span></td>
</tr>
<tr class="check-<?php echo $image_ext ? 'yes' : 'no'; ?>">
<th>
<?php echo $image_ext ? esc_html__( 'PHP GD or Imagick Extension installed', 'rank-math' ) : esc_html__( 'PHP GD or Imagick Extension missing', 'rank-math' ); ?>
</th>
<td><span class="dashicons dashicons-<?php echo $image_ext ? 'yes' : 'no'; ?>"></span></td>
</tr>
<tr class="check-<?php echo $mb_string ? 'yes' : 'no'; ?>">
<th>
<?php echo $mb_string ? esc_html__( 'PHP MBstring Extension installed', 'rank-math' ) : esc_html__( 'PHP MBstring Extension missing', 'rank-math' ); ?>
</th>
<td><span class="dashicons dashicons-<?php echo $mb_string ? 'yes' : 'no'; ?>"></span></td>
</tr>
<tr class="check-<?php echo $openssl ? 'yes' : 'no'; ?>">
<th>
<?php echo $openssl ? esc_html__( 'PHP OpenSSL Extension installed', 'rank-math' ) : esc_html__( 'PHP OpenSSL Extension missing', 'rank-math' ); ?>
</th>
<td><span class="dashicons dashicons-<?php echo $mb_string ? 'yes' : 'no'; ?>"></span></td>
</tr>
<tr class="check-<?php echo $base64_func ? 'yes' : 'no'; ?>">
<th>
<?php echo $base64_func ? esc_html__( 'Base64 encode &amp; decode functions available', 'rank-math' ) : esc_html__( 'Base64 encode &amp; decode functions missing', 'rank-math' ); ?>
</th>
<td><span class="dashicons dashicons-<?php echo $base64_func ? 'yes' : 'no'; ?>"></span></td>
</tr>
</table>
<?php if ( $all_good ) { ?>
<p class="description checklist-ok">
<?php
echo ( ! Helper::is_whitelabel() ) ?
esc_html__( 'Your server is correctly configured to use Rank Math.', 'rank-math' ) :
esc_html__( 'Your server is correctly configured to use this plugin.', 'rank-math' );
?>
</p>
<?php } else { ?>
<p class="description checklist-not-ok">
<?php
echo ( ! Helper::is_whitelabel() ) ?
esc_html__( 'Please resolve the issues above to be able to use all features of Rank Math plugin. If you are not sure how to do it, please contact your hosting provider.', 'rank-math' ) :
esc_html__( 'Please resolve the issues above to be able to use all SEO features. If you are not sure how to do it, please contact your hosting provider.', 'rank-math' );
?>
</p>
<?php } ?>
<?php
//
// PLUGINS.
//
$conflicting_plugins = $this->get_conflicting_plugins();
?>
<?php if ( $conflicting_plugins ) : ?>
<p class="conflict-text">
<?php
echo ( ! Helper::is_whitelabel() ) ?
esc_html__( 'The following active plugins on your site may cause conflict issues when used alongside Rank Math: ', 'rank-math' ) :
esc_html__( 'The following active plugins on your site may cause conflict issues when used alongside this plugin: ', 'rank-math' );
?>
</p>
<table class="form-table wp-core-ui wizard-conflicts">
<?php foreach ( $conflicting_plugins as $pk => $plugin ) { ?>
<tr>
<td><span class="dashicons dashicons-warning"></span></td>
<td><?php echo $plugin . ( in_array( $pk, [ 'all-in-one-schemaorg-rich-snippets/index.php', 'wordpress-seo/wp-seo.php', 'wordpress-seo-premium/wp-seo-premium.php', 'all-in-one-seo-pack/all_in_one_seo_pack.php' ], true ) ? '<span class="import-info">' . esc_html__( 'You can import settings in the next step.', 'rank-math' ) . '</span>' : '' ); ?></td>
<td><a href="#" class="button button-small wizard-deactivate-plugin" data-plugin="<?php echo esc_attr( $pk ); ?>"><?php esc_html_e( 'Deactivate Plugin', 'rank-math' ); ?></a></td>
</tr>
<?php } ?>
</table>
<?php
set_transient( '_rank_math_conflicting_plugins', array_keys( $conflicting_plugins ) );
else :
delete_transient( '_rank_math_conflicting_plugins' );
?>
<p class="conflict-text noconflict"><?php esc_html_e( 'No known conflicting plugins found.', 'rank-math' ); ?></p>
<?php endif; ?>
<?php if ( $all_good ) : ?>
</div> <!-- /collapsible -->
<?php endif; ?>
<footer class="form-footer rank-math-custom wp-core-ui rank-math-ui text-center">
<?php if ( $all_good ) : ?>
<button type="submit" class="button button-primary button-animated"><?php esc_html_e( 'Start Wizard', 'rank-math' ); ?> <i class="dashicons dashicons-arrow-right-alt2"></i></button>
<?php endif; ?>
</footer>

View File

@@ -0,0 +1,44 @@
<?php
/**
* Setup wizard content template.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\KB;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
?>
<div class="header">
<div class="logo text-center">
<a href="<?php KB::the( 'logo', 'SW Logo' ); ?>" target="_blank"><img src="<?php echo esc_url( rank_math()->plugin_url() . 'assets/admin/img/logo.svg' ); ?>" width="245"></a>
</div>
<?php require_once $this->get_view( 'navigation' ); ?>
</div>
<div class="wrapper">
<div class="main-content wizard-content--<?php echo esc_attr( $this->step_slug ); ?>">
<form class="cmb-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
<input type="hidden" name="action" value="<?php echo 'rank-math-registration' === $this->slug ? 'rank_math_save_registration' : 'rank_math_save_wizard'; ?>">
<input type="hidden" name="step" value="<?php echo esc_attr( $this->step ); ?>">
<?php wp_nonce_field( 'rank-math-wizard', 'security' ); ?>
<?php $this->body(); ?>
</form>
</div>
</div>
<?php
if ( ! in_array( $this->step_slug, [ 'register', 'ready' ], true ) ) :
echo sprintf( '<div class="return-to-dashboard"><a href="%s">%s</a></div>', esc_url( 'rank-math-registration' === Param::get( 'page' ) ? admin_url( '/' ) : RankMath\Helper::get_dashboard_url() ), esc_html__( 'Return to dashboard', 'rank-math' ) );
endif;
?>

View File

@@ -0,0 +1,22 @@
<?php
/**
* Setup wizard footer template.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
defined( 'ABSPATH' ) || exit;
echo '</body>' . "\n";
CMB2_JS::enqueue();
rank_math()->json->output();
if ( function_exists( 'wp_print_media_templates' ) ) {
wp_print_media_templates();
}
wp_print_footer_scripts();
wp_print_scripts( 'rank-math-wizard' );
wp_print_scripts( 'cmb2-scripts' );
echo '</html>';

View File

@@ -0,0 +1,40 @@
<?php
/**
* Search console ui.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\KB;
use RankMath\Google\Authentication;
defined( 'ABSPATH' ) || exit;
// phpcs:disable
$is_authorized = Authentication::is_authorized();
$authorize = ! $is_authorized ? ( '<div class="connect-wrap" style="margin-top: 30px;"><a href="' . esc_url( Authentication::get_auth_url() ) . '" class="button button-primary button-animated rank-math-authorize-account">' . esc_html__( 'Connect Google Services', 'rank-math' ) . '</a></div>' ) : '';
$deauthorize = $is_authorized ? '<button class="button button-primary rank-math-deauthorize-account">' . esc_html__( 'Disconnect Account', 'rank-math' ) . '</button>' : '';
echo $authorize . $deauthorize;
?>
<div id="rank-math-pro-cta" class="analytics">
<div class="rank-math-cta-box width-100 no-shadow no-padding no-border">
<h3><?php echo esc_attr__( 'Benefits of Connecting Google Account', 'rank-math' ); ?></h3>
<ul>
<li><?php echo esc_attr__( 'Verify site ownership on Google Search Console in a single click', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Track page and keyword rankings with the Advanced Analytics module', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Easily set up Google Analytics without using another 3rd party plugin', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Automatically submit sitemaps to the Google Search Console', 'rank-math' ); ?></li>
<li><a href="<?php echo KB::get( 'help-analytics', 'SW Analytics Step Benefits' ); ?>" target="_blank"><?php echo esc_html__( 'Learn more about the benefits of connecting your account here.', 'rank-math' ); ?></a></li>
</ul>
</div>
</div>
<div id="rank-math-pro-cta" class="rank-math-privacy-box">
<div class="rank-math-cta-table">
<div class="rank-math-cta-body less-padding">
<i class="dashicons dashicons-lock"></i>
<p><?php printf( esc_html__( 'We do not store any of the data from your Google account on our servers, everything is processed & stored on your server. We take your privacy extremely seriously and ensure it is never misused. %s', 'rank-math' ), '<a href="' . KB::get( 'usage-policy', 'Analytics Privacy Notice' ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Learn more.', 'rank-math' ) . '</a>' ); ?></p>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
<?php
/**
* Setup wizard header template.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta name="viewport" content="width=device-width"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title><?php esc_html_e( 'Setup Wizard - Rank Math', 'rank-math' ); ?></title>
<?php wp_print_head_scripts(); ?>
<?php wp_print_styles( 'rank-math-wizard' ); ?>
</head>
<body class="rank-math-wizard rank-math-page rank-math-wizard-body--<?php echo sanitize_html_class( $this->step_slug ); ?><?php echo is_rtl() ? ' rtl' : ''; ?><?php echo Helper::is_advanced_mode() ? ' rank-math-mode-advanced' : ' rank-math-mode-basic'; ?>">

View File

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

View File

@@ -0,0 +1,39 @@
<?php
/**
* Setup wizard navigation template.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
defined( 'ABSPATH' ) || exit;
$output_steps = $this->steps;
$array_keys = array_keys( $this->steps );
$current_step = array_search( $this->step, $array_keys, true );
?>
<div class="wizard-navigation">
<a class="step step-label" href="<?php echo esc_url( apply_filters( 'rank_math/wizard/step/label_url', \RankMath\Helper::get_admin_url( 'wizard' ) ) ); ?>" title="<?php echo apply_filters( 'rank_math/wizard/step/label', esc_html__( 'Getting Started', 'rank-math' ) ); ?>"></a>
<?php
foreach ( $output_steps as $step_key => $step ) :
if ( $this->is_nav_item_hidden( $step_key ) ) {
continue;
}
$class_attr = '';
if ( $step_key === $this->step ) {
$class_attr = 'active';
} elseif ( $current_step > array_search( $step_key, $array_keys, true ) ) {
$class_attr = 'done';
}
?>
<a class="<?php echo esc_attr( $class_attr ); ?>" href="<?php echo esc_url( $this->get_step_link( $step_key ) ); ?>" title="<?php echo esc_attr( $step['name'] ); ?>"><span></span></a>
<?php endforeach; ?>
</div>

View File

@@ -0,0 +1,13 @@
<?php
/**
* Setup wizard no navigation template.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
defined( 'ABSPATH' ) || exit;
?>
<br>
<br>

View File

@@ -0,0 +1,53 @@
<?php
/**
* Search console ui.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\KB;
use RankMath\Helpers\Param;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
$page = Param::get( 'page', '', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_STRIP_BACKTICK );
$page = in_array( $page, [ 'rank-math-options-general', 'rank-math-analytics' ], true ) ? 'rank-math-options-general' : 'rank-math-wizard&step=analytics';
$url = Admin_Helper::get_activate_url( admin_url( 'admin.php?analytics=1&page=' . $page ) );
$site_url_valid = Admin_Helper::is_site_url_valid();
$button_class = 'button button-primary button-connect' . ( $site_url_valid ? ' button-animated' : ' disabled' );
?>
<?php Admin_Helper::maybe_show_invalid_siteurl_notice(); ?>
<div class="wp-core-ui rank-math-ui connect-wrap" style="margin-top: 30px;">
<a href="<?php echo esc_url( $url ); ?>" class="<?php echo esc_attr( $button_class ); ?>" name="rank_math_activate"><?php echo esc_attr__( 'Connect Your Rank Math Account', 'rank-math' ); ?></a>
</div>
<div id="rank-math-pro-cta" class="analytics">
<div class="rank-math-cta-box width-100 no-shadow no-padding no-border">
<h3><?php echo esc_attr__( 'Benefits of Connecting Rank Math Account', 'rank-math' ); ?></h3>
<ul>
<li><?php echo esc_attr__( 'Verify site ownership on Google Search Console in a single click', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Track page and keyword rankings with the Advanced Analytics module', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Easily set up Google Analytics without using another 3rd party plugin', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Automatically submit sitemaps to the Google Search Console', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Free keyword suggestions when entering a focus keyword', 'rank-math' ); ?></li>
<li><?php echo esc_attr__( 'Use our revolutionary SEO Analyzer to scan your website for SEO errors', 'rank-math' ); ?></li>
<li><a href="<?php echo esc_url( KB::get( 'free-account-benefits', 'SW Analytics Step' ) ); ?>" target="_blank"><?php echo esc_html__( 'Learn more about the benefits of connecting your account here.', 'rank-math' ); ?></a></li>
</ul>
</div>
</div>
<div id="rank-math-pro-cta" class="rank-math-privacy-box">
<div class="rank-math-cta-table">
<div class="rank-math-cta-body less-padding">
<i class="dashicons dashicons-lock"></i>
<p>
<?php
// Translators: placeholder is the KB link.
printf( esc_html__( 'We do not store any of the data from your Google account on our servers, everything is processed & stored on your server. We take your privacy extremely seriously and ensure it is never misused. %s', 'rank-math' ), '<a href="' . esc_url( KB::get( 'usage-policy', 'Analytics Privacy Notice' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Learn more.', 'rank-math' ) . '</a>' );
?>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,79 @@
<?php
/**
* Setup wizard ready step.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\KB;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
?>
<header>
<h1>
<i class="dashicons dashicons-yes"></i> <?php esc_html_e( 'Your site is ready!', 'rank-math' ); ?>
<?php \RankMath\Admin\Admin_Helper::get_social_share(); ?>
</h1>
</header>
<div class="rank-math-additional-options">
<div class="rank-math-auto-update-wrapper">
<h3><?php esc_html_e( 'Enable auto update of the plugin', 'rank-math' ); ?></h3>
<span class="cmb2-toggle">
<input type="checkbox" class="rank-math-modules" id="auto-update" value="" <?php checked( Helper::get_auto_update_setting() ); ?> data-key="enable_auto_update" />
<label for="auto-update" class="cmb2-slider">
<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
</label>
</span>
</div>
</div>
<br class="clear">
<?php if ( ! Helper::is_whitelabel() ) : ?>
<div class="wizard-next-steps wp-clearfix">
<div class="score-100">
<a href="<?php KB::the( 'score-100', 'SW Ready Score Image' ); ?>" target="_blank">
<img src="<?php echo esc_url( rank_math()->plugin_url() ); ?>/assets/admin/img/score-100.png">
</a>
</div>
<div class="learn-more">
<h2><?php esc_html_e( 'Learn more', 'rank-math' ); ?></h2>
<ul>
<li>
<?php if ( ! defined( 'RANK_MATH_PRO_FILE' ) ) { ?>
<span class="dashicons dashicons-star-filled pro"></span><a href="<?php KB::the( 'pro', 'SW Ready Step Upgrade' ); ?>" target="_blank"><strong class="pro-label"><?php esc_html_e( 'Know more about the PRO version', 'rank-math' ); ?></strong></a>
<?php } else { ?>
<span class="dashicons dashicons-video-alt3"></span><a href="<?php KB::the( 'yt-link', 'SW Ready Step Upgrade' ); ?>" target="_blank"><?php esc_html_e( 'Subscribe to Our YouTube Channel', 'rank-math' ); ?></a>
<?php } ?>
</li>
<li>
<span class="dashicons dashicons-facebook"></span><a href="<?php KB::the( 'fb-group', 'SW Ready Step Upgrade' ); ?>" target="_blank"><?php esc_html_e( 'Join FREE Facebook Group', 'rank-math' ); ?></a>
</li>
<li>
<span class="dashicons dashicons-welcome-learn-more"></span><a href="<?php KB::the( 'kb-seo-suite', 'SW Ready Step KB' ); ?>" target="_blank"><?php esc_html_e( 'Rank Math Knowledge Base', 'rank-math' ); ?></a>
</li>
<li>
<span class="dashicons dashicons-sos"></span><a href="<?php KB::the( 'support', 'SW Ready Step Support' ); ?>" target="_blank"><?php esc_html_e( 'Get 24x7 Support', 'rank-math' ); ?></a>
</li>
</ul>
</div>
</div>
<footer class="form-footer wp-core-ui rank-math-ui">
<a href="<?php echo esc_url( Helper::get_dashboard_url() ); ?>" class="button button-secondary rank-math-return-dashboard"><?php esc_html_e( 'Return to dashboard', 'rank-math' ); ?></a>
<a href="<?php echo esc_url( Helper::get_admin_url( '', 'view=help' ) ); ?>" class="button button-secondary"><?php esc_html_e( 'Proceed to Help Page', 'rank-math' ); ?></a>
<a href="<?php echo esc_url( $wizard->step_next_link() ); ?>" class="button button-primary rank-math-advanced-option"><?php esc_html_e( 'Setup Advanced Options', 'rank-math' ); ?></a>
<?php do_action( 'rank_math/wizard/ready_footer', $wizard ); ?>
</footer>
<?php else : ?>
<p><?php esc_html_e( 'Your site is now optimized.', 'rank-math' ); ?></p>
<footer class="form-footer wp-core-ui rank-math-ui">
<a href="<?php echo esc_url( Helper::get_admin_url( 'options-general' ) ); ?>" class="button button-primary"><?php esc_html_e( 'Proceed to Settings', 'rank-math' ); ?></a>
</footer>
<?php
endif;

View File

@@ -0,0 +1,412 @@
<?php
/**
* Search console UI.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\KB;
use RankMath\Helper;
use RankMath\Google\Authentication;
use RankMath\Google\Permissions;
use RankMath\Analytics\Url_Inspection;
use RankMath\Helpers\Str;
use RankMath\Google\Analytics;
use RankMath\Google\Console;
defined( 'ABSPATH' ) || exit;
// phpcs:disable
if ( ! Helper::is_site_connected() ) {
require_once 'rank-math-connect.php';
return;
}
$is_authorized = Authentication::is_authorized();
if ( ! $is_authorized ) {
require_once 'google-connect.php';
return;
}
$profile = wp_parse_args(
get_option( 'rank_math_google_analytic_profile' ),
[
'profile' => '',
'country' => 'all',
]
);
$analytics = wp_parse_args(
get_option( 'rank_math_google_analytic_options' ),
[
'adsense_id' => '',
'account_id' => '',
'property_id' => '',
'view_id' => '',
'measurement_id' => '',
'stream_name' => '',
'country' => 'all',
'install_code' => false,
'anonymize_ip' => false,
'local_ga_js' => false,
'exclude_loggedin' => false,
]
);
$is_profile_connected = Console::is_console_connected();
$is_adsense_connected = ! empty( $analytics['adsense_id'] );
$is_analytics_connected = Analytics::is_analytics_connected();
$is_index_status_enabled = Url_Inspection::is_enabled() || ! $is_profile_connected;
$all_services = get_option( 'rank_math_analytics_all_services', [
'isVerified' => '',
'inSearchConsole' => '',
'hasSitemap' => '',
'hasAnalytics' => '',
'hasAnalyticsProperty' => '',
'homeUrl' => '',
'sites' => '',
'accounts' => [],
'adsenseAccounts' => [],
] );
$is_pro_active = defined( 'RANK_MATH_PRO_FILE' );
$is_ga4 = ! Str::starts_with( 'UA-', $analytics['property_id'] );
?>
<input type="hidden" class="cmb2-id-check-all-services" value="<?php echo $is_profile_connected && $is_analytics_connected ? '1' : '0'; ?>" />
<?php
$actions = [
'reconnect' => [
'link' => wp_nonce_url( admin_url( 'admin.php?reconnect=google' ), 'rank_math_reconnect_google' ),
'class' => 'rank-math-reconnect-google',
'text' => esc_html__( 'Reconnect', 'rank-math' ),
],
'disconnect' => [
'link' => '#',
'class' => 'rank-math-disconnect-google',
'text' => esc_html__( 'Disconnect', 'rank-math' ),
],
];
if ( Helper::is_advanced_mode() && ( $is_profile_connected || $is_adsense_connected || $is_analytics_connected ) ) {
$actions['test-connections'] = [
'link' => '#',
'class' => 'rank-math-test-connection-google',
'text' => esc_html__( 'Test Connections', 'rank-math' ),
];
}
$actions = apply_filters( 'rank_math/analytics/connect_actions', $actions );
?>
<div class="connect-actions">
<?php foreach( $actions as $action ) { ?>
<a href="<?php echo esc_attr( $action['link'] ); ?>" class="button button-link <?php echo esc_attr( $action['class'] ); ?>"><?php echo esc_html( $action['text'] ); ?></a>
<?php } ?>
</div>
<?php
$console_classes = Helper::classnames(
'rank-math-box no-padding rank-math-accordion rank-math-connect-search-console',
[
'connected' => $is_profile_connected,
'disconnected' => ! $is_profile_connected,
'disabled' => ! Permissions::has_console(),
]
);
$console_status_classes = Helper::classnames(
'rank-math-connection-status',
[
'rank-math-connection-status-success' => $is_profile_connected,
'rank-math-connection-status-error' => ! $is_profile_connected,
]
);
$console_status = $is_profile_connected ? 'Connected' : 'Not Connected';
?>
<div class="<?php echo esc_attr( $console_classes ); ?>" tabindex="0">
<header>
<h3><span class="rank-math-connection-status-wrap"><span class="<?php echo esc_attr( $console_status_classes ); ?>" title="<?php echo esc_attr( $console_status ); ?>"></span></span> <?php esc_html_e( 'Search Console', 'rank-math' ); ?></h3>
</header>
<div class="rank-math-accordion-content">
<?php
if ( ! Permissions::has_console() ) {
Permissions::print_warning();
} ?>
<div class="cmb-row cmb-type-select">
<div class="cmb-row-col">
<label for="site-console-profile"><?php esc_html_e( 'Site', 'rank-math' ); ?></label>
<select class="cmb2_select site-console-profile notrack" name="site-console-profile" id="site-console-profile" data-selected="<?php echo $profile['profile']; ?>" disabled="disabled">
<?php if ( $is_profile_connected ) : ?>
<option value="<?php echo $profile['profile']; ?>"><?php echo $profile['profile']; ?></option>
<?php endif; ?>
</select>
</div>
<?php do_action( 'rank_math/analytics/options/console' ); ?>
</div>
<div class="cmb-row cmb-type-toggle">
<div class="cmb-td">
<label class="cmb2-toggle">
<input type="checkbox" class="regular-text notrack" name="enable-index-status" id="enable-index-status" value="on"<?php checked( $is_index_status_enabled ); ?> <?php echo disabled( ! $is_profile_connected ) ?>>
<span class="cmb2-slider">
<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
</span>
</label>
<label for="enable-index-status"><?php esc_html_e( 'Enable the Index Status tab', 'rank-math' ); ?></label>
<div class="cmb2-metabox-description"><?php esc_html_e( 'Enable this option to show the Index Status tab in the Analytics module.', 'rank-math' ); ?> <a href="<?php echo KB::get( 'url-inspection-api', 'SW Analytics Index Status Option' ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Learn more.', 'rank-math' ); ?></a></div>
</div>
</div>
</div>
</div>
<?php
$analytic_classes = Helper::classnames(
'rank-math-box no-padding rank-math-accordion rank-math-connect-analytics',
[
'connected' => $is_analytics_connected,
'disconnected' => ! $is_analytics_connected,
'disabled' => ! Permissions::has_analytics(),
]
);
$analytic_status_classes = Helper::classnames(
'rank-math-connection-status',
[
'rank-math-connection-status-success' => $is_analytics_connected,
'rank-math-connection-status-error' => ! $is_analytics_connected,
]
);
$analytic_status = $is_analytics_connected ? 'Connected' : 'Not Connected';
?>
<div class="<?php echo esc_attr( $analytic_classes ); ?>" tabindex="0">
<header>
<h3><span class="rank-math-connection-status-wrap"><span class="<?php echo esc_attr( $analytic_status_classes ); ?>" title="<?php echo esc_attr( $analytic_status ); ?>"></span></span><?php esc_html_e( 'Analytics', 'rank-math' ); ?></h3>
</header>
<div class="rank-math-accordion-content rank-math-analytics-content">
<?php
if ( ! Permissions::has_analytics() ) {
Permissions::print_warning();
} ?>
<p class="warning yellow">
<strong class="note"><?php echo esc_attr( 'Note', 'rank-math' ); ?></strong>
<?php
/* translators: GA4 KB link */
echo sprintf(
esc_html__( 'Ready to switch to Google Analytics 4? %s', 'rank-math' ),
'<a href="'. KB::get( 'using-ga4', 'Analytics GA4 KB' ) . '" target="_blank">' . esc_html__( 'Click here to know how', 'rank-math' ) . '</a>.'
);
?>
</p>
<div class="cmb-row cmb-type-select">
<div class="cmb-row-col">
<label for="site-analytics-account"><?php esc_html_e( 'Account', 'rank-math' ); ?></label>
<select class="cmb2_select site-analytics-account notrack" name="site-analytics-account" id="site-analytics-account" data-selected="<?php echo esc_attr( $analytics['account_id'] ); ?>" disabled="disabled">
<?php
if ( $is_analytics_connected ) :
$analytic_account = $all_services['accounts'][ $analytics['account_id'] ];
?>
<option value="<?php echo $analytics['account_id']; ?>"><?php echo $analytic_account['name']; ?></option>
<?php endif; ?>
</select>
</div>
<div class="cmb-row-col">
<label for="site-analytics-property"><?php esc_html_e( 'Property', 'rank-math' ); ?></label>
<select class="cmb2_select site-analytics-property notrack" name="site-analytics-property" id="site-analytics-property" data-selected="<?php echo esc_attr( $analytics['property_id'] ); ?>" disabled="disabled">
<?php
if ( $is_analytics_connected ) :
$analytic_property = $all_services['accounts'][ $analytics['account_id'] ]['properties'][ $analytics['property_id'] ]['name'];
?>
<option value="<?php echo $analytics['property_id']; ?>"><?php echo $analytic_property; ?></option>
<?php endif; ?>
</select>
</div>
<div class="cmb-row-col">
<label for="site-analytics-view">
<?php echo $is_ga4 ? esc_html__( 'Data Stream', 'rank-math' ) : esc_html__( 'View', 'rank-math' ); ?>
</label>
<select class="cmb2_select site-analytics-view notrack" name="site-analytics-view" id="site-analytics-view" data-selected="<?php echo esc_attr( $analytics['view_id'] ); ?>" disabled="disabled">
<?php
if ( $is_analytics_connected ) :
$analytic_view = $is_ga4 ? $analytics['stream_name'] : $all_services['accounts'][ $analytics['account_id'] ]['properties'][ $analytics['property_id'] ]['profiles'][ $analytics['view_id'] ]['name'];
$analytic_view = $is_ga4 && ! $analytic_view && ! empty( $analytics['view_id'] ) ? 'Website' : $analytic_view;
?>
<option value="<?php echo esc_attr( $analytics['view_id'] ); ?>"><?php echo esc_attr( $analytic_view ); ?></option>
<?php
endif;
?>
</select>
</div>
<input type="hidden" id="rank-math-analytics-measurement-id" name="measurementID" value="<?php echo esc_attr( $analytics['measurement_id'] ) ?>" />
<input type="hidden" id="rank-math-analytics-stream-name" name="streamName" value="<?php echo esc_attr( $analytics['stream_name'] ) ?>" />
<?php do_action( 'rank_math/analytics/options/analytics' ); ?>
</div>
<div class="cmb-row cmb-type-toggle">
<div class="cmb-td">
<label class="cmb2-toggle">
<input type="checkbox" class="regular-text notrack" name="install-code" id="install-code" value="on"<?php checked( $analytics['install_code'] ); ?>>
<span class="cmb2-slider">
<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
</span>
</label>
<label for="install-code"><?php esc_html_e( 'Install analytics code', 'rank-math' ); ?></label>
<div class="cmb2-metabox-description"><?php esc_html_e( 'Enable this option only if you are not using any other plugin/theme to install Google Analytics code.', 'rank-math' ); ?></div>
</div>
</div>
<div class="cmb-row cmb-type-toggle <?php echo ! $is_pro_active ? 'cmb-redirector-element' : ''; ?>" <?php echo ! $is_pro_active ? 'data-url="' . KB::the( 'free-vs-pro', 'Anonymize IP' ) .'"' : ''; ?>>
<div class="cmb-td">
<label class="cmb2-toggle">
<input type="checkbox" class="regular-text notrack" name="anonymize-ip" id="anonymize-ip" value="on"<?php checked( $analytics['anonymize_ip'] ); ?><?php disabled( ! $is_pro_active ); ?>>
<span class="cmb2-slider<?php echo ! $is_pro_active ? ' disabled' : ''; ?> ">
<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
</span>
</label>
<label for="anonymize-ip">
<?php esc_html_e( 'Anonymize IP addresses', 'rank-math' ); ?>
<?php if ( ! $is_pro_active ) : ?>
<span class="rank-math-pro-badge">
<a href="<?php KB::the( 'pro', 'Anonymize IP' ); ?>" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'PRO', 'rank-math' ); ?>
</a>
</span>
<?php endif; ?>
</label>
<div class="rank-math-cmb-dependency hidden" data-relation="or">
<span class="hidden" data-field="install-code" data-comparison="=" data-value="on"></span>
</div>
</div>
</div>
<div class="cmb-row cmb-type-toggle <?php echo ! $is_pro_active ? 'cmb-redirector-element' : ''; ?>" <?php echo ! $is_pro_active ? 'data-url="' . KB::the( 'pro', 'Localjs IP' ) . '"' : ''; ?>>
<div class="cmb-td">
<label class="cmb2-toggle">
<input type="checkbox" class="regular-text notrack" name="local-ga-js" id="local-ga-js" value="on"<?php checked( $analytics['local_ga_js'] ); ?><?php disabled( ! $is_pro_active ); ?>>
<span class="cmb2-slider<?php echo ! $is_pro_active ? ' disabled' : ''; ?> ">
<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
</span>
</label>
<label for="local-ga-js">
<?php esc_html_e( 'Self-Hosted Analytics JS File', 'rank-math' ); ?>
<?php if ( ! $is_pro_active ) : ?>
<span class="rank-math-pro-badge">
<a href="<?php KB::the( 'pro', 'Localjs IP' ); ?>" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'PRO', 'rank-math' ); ?>
</a>
</span>
<?php endif; ?>
</label>
<div class="rank-math-cmb-dependency hidden" data-relation="or">
<span class="hidden" data-field="install-code" data-comparison="=" data-value="on"></span>
</div>
</div>
</div>
<div class="cmb-row cmb-type-toggle">
<div class="cmb-td">
<label class="cmb2-toggle">
<input type="checkbox" class="regular-text notrack" name="exclude-loggedin" id="exclude-loggedin" value="on"<?php checked( $analytics['exclude_loggedin'] ); ?>>
<span class="cmb2-slider">
<svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
<svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
</span>
</label>
<label for="exclude-loggedin"><?php esc_html_e( 'Exclude Logged-in users', 'rank-math' ); ?></label>
<div class="rank-math-cmb-dependency hidden" data-relation="or">
<span class="hidden" data-field="install-code" data-comparison="=" data-value="on"></span>
</div>
</div>
</div>
</div>
</div>
<?php
$adsense_classes = Helper::classnames(
'rank-math-box no-padding rank-math-accordion rank-math-connect-adsense',
[
'connected' => $is_adsense_connected,
'disconnected' => ! $is_adsense_connected,
'disabled' => ! Permissions::has_adsense(),
]
);
$adsense_status_classes = Helper::classnames(
'rank-math-connection-status',
[
'rank-math-connection-status-success' => Permissions::has_adsense() && $is_adsense_connected,
'rank-math-connection-status-error' => Permissions::has_adsense() && ! $is_adsense_connected,
]
);
$adsense_status = $is_adsense_connected ? 'Connected' : 'Not Connected';
?>
<div class="<?php echo esc_attr( $adsense_classes ); ?>" tabindex="0">
<header>
<h3><span class="rank-math-connection-status-wrap"><span class="<?php echo esc_attr( $adsense_status_classes ); ?>" title="<?php echo esc_attr( $adsense_status ); ?>"></span></span><?php esc_html_e( 'AdSense', 'rank-math' ); ?></h3>
</header>
<div class="rank-math-accordion-content">
<?php
if ( defined( 'RANK_MATH_PRO_FILE' ) && ! Permissions::has_adsense() ) {
Permissions::print_warning();
} ?>
<div class="cmb-row cmb-type-select">
<div class="cmb-row-col">
<label for="site-adsense-account"><?php esc_html_e( 'Account', 'rank-math' ); ?></label>
<select class="cmb2_select site-adsense-account notrack" name="site-adsense-account" id="site-adsense-account" data-selected="<?php echo esc_attr( $analytics['adsense_id'] ); ?>" disabled="disabled">
<?php
if ( $is_adsense_connected ) :
$adsense = $all_services['adsenseAccounts'][ $analytics['adsense_id'] ];
?>
<option value="<?php echo $analytics['adsense_id']; ?>"><?php echo $adsense['name']; ?></option>
<?php endif; ?>
</select>
</div>
</div>
<?php if ( ! $is_pro_active ) : ?>
<div id="rank-math-pro-cta" class="no-margin">
<div class="rank-math-cta-text">
<span class="rank-math-pro-badge"><a href="<?php KB::the( 'pro', 'AdSense Toggle' ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'PRO', 'rank-math' ); ?></a></span> <?php esc_html_e( "Google AdSense support is only available in Rank Math Pro's Advanced Analytics module.", 'rank-math' ); ?>
</div>
</div>
<?php endif; ?>
</div>
</div>
<div id="rank-math-pro-cta" class="rank-math-privacy-box width-100">
<div class="rank-math-cta-table">
<div class="rank-math-cta-body less-padding">
<i class="dashicons dashicons-lock"></i>
<p><?php printf( esc_html__( 'We do not store any of the data from your Google account on our servers, everything is processed & stored on your server. We take your privacy extremely seriously and ensure it is never misused. %s', 'rank-math' ), '<a href="' . KB::get( 'usage-policy', 'Analytics Privacy Notice' ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Learn more.', 'rank-math' ) . '</a>' ); ?></p>
</div>
</div>
</div>
<?php
// phpcs:enable
if ( Helper::is_wizard() && ! RankMath\Analytics\Email_Reports::are_fields_hidden() ) {
?>
<div class="cmb-row email-reports-header text-center" style="border-top:0;">
<h1><?php esc_html_e( 'Email Reports', 'rank-math' ); ?></h1>
<div class="email-reports-desc text-center"><?php esc_html_e( 'Receive Analytics reports periodically in email.', 'rank-math' ); ?> <a href="#" target="_blank"><?php esc_html_e( 'Learn more about Email Reports.', 'rank-math' ); ?></a></div>
</div>
<div class="cmb-row cmb-type-toggle cmb2-id-console-email-reports" data-fieldtype="toggle">
<div class="cmb-th">
<label for="console_email_reports"><?php esc_html_e( 'Email Reports', 'rank-math' ); ?></label>
</div>
<div class="cmb-td">
<label class="cmb2-toggle"><input type="checkbox" class="regular-text" name="console_email_reports" id="console_email_reports" value="on" <?php checked( Helper::get_settings( 'general.console_email_reports' ) ); ?> data-hash="7e0rimtbvig0"><span class="cmb2-slider"><svg width="3" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" class="toggle_on" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg><svg width="8" height="8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" class="toggle_off" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg></span></label>
</div>
</div>
<?php
do_action( 'rank_math/analytics/options/wizard_after_email_report' );
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* Setup wizard your site step.
*
* @package RankMath
* @subpackage RankMath\Admin\Wizard
*/
use RankMath\Helper;
use RankMath\KB;
defined( 'ABSPATH' ) || exit;
?>
<header>
<h1>
<?php
/* translators: sitename */
printf( esc_html__( 'Your Website: %s', 'rank-math' ), esc_attr( $this->get_site_display_name() ) );
?>
</h1>
<p><?php esc_html_e( 'Let us know a few things about your site&hellip;', 'rank-math' ); ?></p>
</header>
<?php if ( ! Helper::is_whitelabel() ) : ?>
<div class="rank-math-wizard-tutorial">
<header>
<?php
printf(
/* translators: help link */
esc_html__( 'If you are new to Rank Math, %s to learn more.', 'rank-math' ),
'<a href="#" data-target="rank-math-wizard-tabs" class="rank-math-collapsible-trigger">' . esc_html__( 'click here', 'rank-math' ) . '</a>'
);
?>
</header>
<div id="rank-math-wizard-tabs" class="rank-math-collapsible-content rank-math-tabs">
<div class="rank-math-tabs-navigation rank-math-custom wp-clearfix">
<a href="#help-panel-video" class="active"><span class="rm-icon rm-icon-video"></span><?php esc_html_e( 'Setup Tutorial', 'rank-math' ); ?></a>
<a href="#help-panel-knowledge"><span class="rm-icon rm-icon-post"></span><?php esc_html_e( 'Knowledge Base', 'rank-math' ); ?></a>
</div>
<div class="rank-math-tabs-content rank-math-custom">
<div id="help-panel-video" class="rank-math-tab">
<a href="<?php KB::the( 'how-to-setup-your-site', 'SW Your Site Setup KB' ); ?>" target="_blank" style="font-size: 15px; border-bottom: 1px dashed;">
<?php echo esc_html_e( 'Click here to learn how to setup Rank Math properly', 'rank-math' ); ?>
</a>
</div>
<div id="help-panel-knowledge" class="rank-math-tab">
<div class="search-form wp-core-ui rank-math-ui">
<label for="rank-math-search-input"><?php esc_html_e( 'Search the Knowledge Base for answers to your questions:', 'rank-math' ); ?></label>
<input type="text" class="regular-text" id="rank-math-search-input" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" placeholder="<?php esc_attr_e( 'Type here to search...', 'rank-math' ); ?>" value="">
<a data-href="<?php KB::the( 'kb-search', 'SW Your Site Search' ); ?>&s=&lang=<?php echo get_locale(); ?>" target="_blank" class="button button-primary"><?php esc_html_e( 'Search', 'rank-math' ); ?></a>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php $wizard->cmb->show_form(); ?>
<footer class="form-footer wp-core-ui rank-math-ui">
<?php $wizard->get_skip_link(); ?>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save and Continue', 'rank-math' ); ?></button>
</footer>

View File

@@ -0,0 +1,97 @@
<?php
/**
* Global functionality of the plugin.
*
* Defines the functionality loaded both on admin and frontend.
*
* @since 0.9.0
* @package RankMath
* @subpackage RankMath\Core
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath;
use RankMath\Traits\Hooker;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Common class.
*/
class Auto_Updater {
use Hooker;
/**
* Constructor method.
*/
public function __construct() {
$this->filter( 'auto_update_plugin', 'auto_update_plugin', 20, 2 );
$this->filter( 'plugin_auto_update_setting_html', 'plugin_auto_update_setting_html', 10, 3 );
}
/**
* 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_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_update( $item ) {
return isset( $item->slug ) &&
'seo-by-rank-math' === $item->slug &&
isset( $item->new_version );
}
/**
* Check if given version is beta.
*
* @param string $item Update object.
* @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.
*
* @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/rank-math.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;
}
}

Some files were not shown because too many files have changed in this diff Show More