*/
namespace RankMath\Admin;
use CMB2_hookup;
use RankMath\KB;
use RankMath\CMB2;
use RankMath\Helper;
use RankMath\Runner;
use RankMath\Replace_Vars;
use RankMath\Traits\Hooker;
use MyThemeShop\Helpers\Str;
use MyThemeShop\Helpers\Url;
use MyThemeShop\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Metabox class.
*/
class Metabox implements Runner {
use Hooker;
/**
* Metabox id.
*
* @var string
*/
private $metabox_id = 'rank_math_metabox';
/**
* Register hooks.
*/
public function hooks() {
$this->action( 'rank_math/admin/enqueue_scripts', 'enqueue' );
$this->action( 'cmb2_admin_init', 'add_main_metabox', 30 );
$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() {
// Early bail if we're not on the valid screens or if it's WPBakery's Frontend editor.
$screen = get_current_screen();
if (
! in_array( $screen->base, array( 'post', 'term', 'profile', 'user-edit' ), true ) ||
( class_exists( 'Vc_Manager' ) && \MyThemeShop\Helpers\Param::get( 'vc_action' ) )
) {
return;
}
// Styles.
CMB2_hookup::enqueue_cmb_css();
Replace_Vars::setup_json();
wp_enqueue_style( 'rank-math-metabox', rank_math()->plugin_url() . '/assets/admin/css/metabox.css', [ 'rank-math-common', 'rank-math-cmb2' ], rank_math()->version );
// JSON data.
Helper::add_json( 'locale', substr( get_locale(), 0, 2 ) );
Helper::add_json( 'overlayImages', Helper::choices_overlay_images() );
Helper::add_json( 'customPermalinks', (bool) get_option( 'permalink_structure', false ) );
Helper::add_json( 'defautOgImage', Helper::get_settings( 'titles.open_graph_image', '' ) );
Helper::add_json(
'postSettings',
[
'linkSuggestions' => Helper::get_settings( 'titles.pt_' . $screen->post_type . '_link_suggestions' ),
'useFocusKeyword' => 'focus_keywords' === Helper::get_settings( 'titles.pt_' . $screen->post_type . '_ls_use_fk' ),
]
);
$js = rank_math()->plugin_url() . 'assets/admin/js/';
wp_enqueue_script( 'jquery-caret', rank_math()->plugin_url() . 'assets/vendor/jquery.caret.min.js', [ 'jquery' ], '1.3.3', true );
wp_enqueue_script( 'jquery-tag-editor', $js . 'jquery.tag-editor.js', [ 'jquery-ui-autocomplete', 'jquery-caret' ], '1.0.21', true );
wp_enqueue_script( 'rank-math-assessor', $js . 'assessor.js', null, rank_math()->version, true );
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( 'lodash', 'registered' ) ) {
wp_register_script( 'lodash', rank_math()->plugin_url() . 'assets/vendor/lodash.js', [], rank_math()->version );
}
if ( Admin_Helper::is_post_edit() ) {
global $post;
Helper::add_json( 'objectID', $post->ID );
Helper::add_json( 'objectType', 'post' );
Helper::add_json( 'parentDomain', Url::get_domain( home_url() ) );
Helper::add_json( 'noFollowDomains', Str::to_arr_no_empty( Helper::get_settings( 'general.nofollow_domains' ) ) );
Helper::add_json( 'noFollowExcludeDomains', Str::to_arr_no_empty( Helper::get_settings( 'general.nofollow_exclude_domains' ) ) );
Helper::add_json( 'noFollowExternalLinks', Helper::get_settings( 'general.nofollow_external_links' ) );
Helper::add_json( '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' ) );
wp_enqueue_script( 'rank-math-post-metabox', $js . 'post-metabox.js', [ 'lodash', 'clipboard', 'rank-math-common', 'rank-math-assessor', 'jquery-tag-editor', 'rank-math-validate', 'wp-hooks' ], rank_math()->version, true );
}
if ( Admin_Helper::is_term_edit() ) {
Helper::add_json( 'objectID', Param::request( 'tag_ID', 0, FILTER_VALIDATE_INT ) );
Helper::add_json( 'objectType', 'term' );
wp_enqueue_script( 'rank-math-term-metabox', $js . 'term-metabox.js', [ 'lodash', 'rank-math-common', 'rank-math-assessor', 'jquery-tag-editor', 'wp-hooks' ], rank_math()->version, true );
}
if ( $this->is_user_metabox() ) {
global $user_id;
Helper::add_json( 'objectID', $user_id );
Helper::add_json( 'objectType', 'user' );
wp_enqueue_script( 'rank-math-user-metabox', $js . 'user-metabox.js', [ 'lodash', 'rank-math-common', 'rank-math-assessor', 'jquery-tag-editor', 'wp-hooks' ], rank_math()->version, true );
}
$this->assessor();
}
/**
* Add main metabox.
*/
public function add_main_metabox() {
if ( $this->can_add_metabox() ) {
return;
}
$cmb = new_cmb2_box(
[
'id' => $this->metabox_id,
'title' => esc_html__( 'Rank Math SEO', 'rank-math' ),
'object_types' => $this->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' : '' ),
]
);
$tabs = $this->get_tabs();
$cmb->add_field(
[
'id' => 'setting-panel-container-' . $this->metabox_id,
'type' => 'meta_tab_container_open',
'tabs' => $tabs,
]
);
foreach ( $tabs as $id => $tab ) {
if ( ! Helper::has_cap( $tab['capability'] ) ) {
continue;
}
$cmb->add_field(
[
'id' => 'setting-panel-' . $id,
'type' => 'tab_open',
]
);
include_once $tab['file'];
/**
* Add setting into specific tab of main metabox.
*
* The dynamic part of the hook name. $id, is the tab id.
*
* @param CMB2 $cmb CMB2 object.
*/
$this->do_action( 'metabox/settings/' . $id, $cmb );
$cmb->add_field(
[
'id' => 'setting-panel-' . $id . '-close',
'type' => 'tab_close',
]
);
}
$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' => '
' . 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' ) ) . '
',
]
);
$cmb->add_field(
[
'id' => 'rank_math_social_tabs',
'type' => 'raw',
'file' => rank_math()->includes_dir() . 'metaboxes/link-suggestions.php',
'not_found' => '' . 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' ) . ' ',
]
);
CMB2::pre_init( $cmb );
}
/**
* Output the WordPress editor for term SEO description.
*
* @param object $term Current taxonomy term object.
*/
public function category_description_editor( $term ) {
?>
description, ENT_QUOTES, 'UTF-8' ),
'rank_math_description',
[
'textarea_name' => 'description',
'textarea_rows' => 5,
'quicktags' => true,
]
);
?>
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,
],
]
);
}
/**
* Get object types to register metaboxes to.
*
* @return array
*/
private function get_object_types() {
$taxonomies = Helper::get_allowed_taxonomies();
$object_types = Helper::get_allowed_post_types();
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' );
}
if ( $this->is_user_metabox() ) {
$object_types[] = 'user';
}
return $object_types;
}
/**
* Get metabox priority.
*
* @return string
*/
private function get_priority() {
$post_type = Param::get(
'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 );
}
/**
* Adds custom category description editor.
*
* @return {void}
*/
private function description_field_editor() {
$taxonomy = filter_input( INPUT_GET, 'taxonomy', FILTER_DEFAULT, [ 'options' => [ 'default' => '' ] ] );
$taxonomy_object = get_taxonomy( $taxonomy );
if ( empty( $taxonomy_object ) || empty( $taxonomy_object->public ) ) {
return;
}
if ( ! Helper::get_settings( 'titles.tax_' . $taxonomy . '_add_meta_box' ) ) {
return;
}
$this->action( "{$taxonomy}_edit_form_fields", 'category_description_editor', 1 );
}
/**
* Check if user has the necessary capabilities for seeing the meta box.
*
* @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' );
}
/**
* Check if user meta box is enabled.
*
* @return bool
*/
private function is_user_metabox() {
return false === Helper::get_settings( 'titles.disable_author_archives' ) &&
Helper::get_settings( 'titles.author_add_meta_box' ) &&
Admin_Helper::is_user_edit();
}
/**
* Get metabox tabs.
*
* @return array
*/
private function get_tabs() {
$tabs = [
'general' => [
'icon' => 'dashicons dashicons-admin-generic',
'title' => esc_html__( 'General', 'rank-math' ),
'desc' => esc_html__( 'This tab contains general options.', 'rank-math' ),
'file' => rank_math()->includes_dir() . 'metaboxes/general.php',
'capability' => 'onpage_general',
],
'advanced' => [
'icon' => 'dashicons dashicons-admin-tools',
'title' => esc_html__( 'Advanced', 'rank-math' ),
'desc' => esc_html__( 'This tab contains advance options.', 'rank-math' ),
'file' => rank_math()->includes_dir() . 'metaboxes/advanced.php',
'capability' => 'onpage_advanced',
],
'social' => [
'icon' => 'dashicons dashicons-share',
'title' => esc_html__( 'Social', 'rank-math' ),
'desc' => esc_html__( 'This tab contains social options.', 'rank-math' ),
'file' => rank_math()->includes_dir() . 'metaboxes/social.php',
'capability' => 'onpage_social',
],
];
/**
* Allow developers to add new tabs in the main metabox.
*
* @param array $tabs Array of tabs.
*/
return $this->do_filter( 'metabox/tabs', $tabs );
}
/**
* Assessor data.
*/
private function assessor() {
$data = [
'powerWords' => $this->power_words(),
'hasTOCPlugin' => $this->has_toc_plugin(),
'mtsConnected' => Helper::is_site_connected(),
'tocKbLink' => KB::get( 'toc' ),
'sentimentKbLink' => KB::get( 'sentiments' ),
'focusKeywordLink' => admin_url( 'edit.php?focus_keyword=%focus_keyword%&post_type=%post_type%' ),
'researchesTests' => [],
];
Helper::add_json( 'assessor', $data );
Helper::add_json( 'isUserRegistered', Helper::is_site_connected() );
}
/**
* Return power words.
*
* @return array
*/
private function power_words() {
$words = include_once rank_math()->plugin_dir() . 'assets/vendor/powerwords.php';
return $this->do_filter( 'metabox/power_words', $words );
}
/**
* Check if any TOC plugin is installed.
*
* @return bool
*/
private function has_toc_plugin() {
$plugins_found = [];
$active_plugins = get_option( 'active_plugins' );
/**
* Allow developers to add plugins to the TOC list.
*
* @param array TOC plugins.
*/
$toc_plugins = $this->do_filter( 'researches/toc_plugins', [
'cm-table-of-content/cm-table-of-content.php' => 'CM Table Of Contents',
'easy-table-of-contents/easy-table-of-contents.php' => 'Easy Table of Contents',
'fx-toc/fx-toc.php' => 'f(x) TOC',
'hm-content-toc/hm-content-toc.php' => 'HM Content TOC',
'shortcodes-ultimate/shortcodes-ultimate.php' => 'Shortcodes Ultimate',
'bainternet-simple-toc/simple-toc.php' => 'Simple TOC',
'content-table/content-table.php' => 'Table of content',
'table-of-contents-plus/toc.php' => 'Table of Contents Plus',
'wp-shortcode/wp-shortcode.php' => 'WP Shortcode by MyThemeShop',
'wp-shortcode-pro/wp-shortcode-pro.php' => 'WP Shortcode Pro by MyThemeShop',
'thrive-visual-editor/thrive-visual-editor.php' => 'Thrive Architect',
'fixed-toc/fixed-toc.php' => 'Fixed TOC',
] );
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;
}
}