Commit inicial - WordPress Análisis de Precios Unitarios

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

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

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

View File

@@ -0,0 +1,456 @@
<?php
/**
* The Global functionality of the plugin.
*
* Defines the functionality loaded on admin.
*
* @since 1.0.15
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Controller;
use RankMath\Helper;
use RankMath\Traits\Hooker;
use RankMath\Traits\Meta;
use RankMath\Role_Manager\Capability_Manager;
use RankMath\Redirections\Redirection;
defined( 'ABSPATH' ) || exit;
/**
* Admin class.
*/
class Admin extends WP_REST_Controller {
use Meta;
use Hooker;
/**
* Constructor.
*/
public function __construct() {
$this->namespace = \RankMath\Rest\Rest_Helper::BASE;
}
/**
* Registers the routes for the objects of the controller.
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/saveModule',
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'save_module' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
'args' => $this->get_save_module_args(),
]
);
register_rest_route(
$this->namespace,
'/toolsAction',
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'tools_actions' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
'args' => $this->get_tools_action_args(),
]
);
register_rest_route(
$this->namespace,
'/updateMode',
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'update_mode' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
'args' => $this->get_update_mode_args(),
]
);
register_rest_route(
$this->namespace,
'/dashboardWidget',
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ $this, 'dashboard_widget_items' ],
'permission_callback' => function () {
return current_user_can( 'read' );
},
]
);
register_rest_route(
$this->namespace,
'/updateSeoScore',
[
'methods' => \WP_REST_Server::EDITABLE,
'callback' => [ $this, 'update_seo_score' ],
'permission_callback' => [ $this, 'can_edit_posts' ],
'args' => $this->get_update_seo_score_args(),
]
);
register_rest_route(
$this->namespace,
'/updateSettings',
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'update_settings' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_settings' ],
]
);
register_rest_route(
$this->namespace,
'/searchPage',
[
'methods' => WP_REST_Server::ALLMETHODS,
'callback' => [ $this, 'search_page' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
]
);
}
/**
* Save module state.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function save_module( WP_REST_Request $request ) {
$module = $request->get_param( 'module' );
$state = $request->get_param( 'state' );
if ( $module === 'react-settings' ) {
update_option( 'rank_math_react_settings_ui', $state );
do_action( 'rank_math/module_changed', $module, $state );
return true;
}
Helper::update_modules( [ $module => $state ] );
$this->maybe_delete_rewrite_rules( $module );
do_action( 'rank_math/module_changed', $module, $state );
return true;
}
/**
* Function to get the dashboard widget content.
*/
public function dashboard_widget_items() {
ob_start();
$this->do_action( 'dashboard/widget' );
return ob_get_clean();
}
/**
* Tools actions.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function tools_actions( WP_REST_Request $request ) {
$action = $request->get_param( 'action' );
return apply_filters( 'rank_math/tools/' . $action, 'Something went wrong.' );
}
/**
* Rest route to update the seo score.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_seo_score( WP_REST_Request $request ) {
$post_scores = $request->get_param( 'postScores' );
if ( empty( $post_scores ) ) {
return 0;
}
foreach ( $post_scores as $post_id => $score ) {
$post = get_post( $post_id );
if ( ! $post ) {
continue;
}
$score = (int) $score;
if ( $score < 0 || $score > 100 ) {
continue;
}
update_post_meta( $post_id, 'rank_math_seo_score', $score );
}
return 1;
}
/**
* Update Setup Mode.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_mode( WP_REST_Request $request ) {
$settings = wp_parse_args(
rank_math()->settings->all_raw(),
[ 'general' => '' ]
);
$settings['general']['setup_mode'] = $request->get_param( 'mode' );
Helper::update_all_settings( $settings['general'], null, null );
return true;
}
/**
* Check if user can edit post.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return bool
*/
public function can_edit_posts( WP_REST_Request $request ) {
$post_scores = $request->get_param( 'postScores' );
if ( empty( $post_scores ) ) {
return false;
}
foreach ( $post_scores as $post_id => $score ) {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return false;
}
}
return true;
}
/**
* Update Settings.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_settings( WP_REST_Request $request ) {
$settings = $request->get_param( 'settings' );
$type = $request->get_param( 'type' );
$is_reset = $request->get_param( 'isReset' );
if ( $type === 'roleCapabilities' ) {
$is_reset ? Capability_Manager::get()->reset_capabilities() : Helper::set_capabilities( $settings );
return [
'settings' => Helper::get_roles_capabilities(),
];
}
if ( $type === 'redirections' ) {
$redirection = Redirection::from(
[
'id' => isset( $settings['id'] ) ? $settings['id'] : '',
'sources' => $settings['sources'],
'url_to' => isset( $settings['url_to'] ) ? $settings['url_to'] : '',
'header_code' => $settings['header_code'],
'status' => $settings['status'],
]
);
if ( $redirection->is_infinite_loop() ) {
if ( ! $redirection->get_id() ) {
$redirection->set_status( 'inactive' );
return rest_ensure_response(
[
'error' => __( 'The redirection you are trying to create may cause an infinite loop. Please check the source and destination URLs. The redirection has been deactivated.', 'rank-math' ),
]
);
}
return rest_ensure_response(
[
'error' => __( 'The redirection you are trying to update may cause an infinite loop. Please check the source and destination URLs.', 'rank-math' ),
]
);
}
if ( false === $redirection->save() ) {
return __( 'Please add at least one valid source URL.', 'rank-math' );
}
$this->do_action( 'redirection/saved', $redirection, $settings );
return true;
}
if ( $type === 'instant-indexing' ) {
$key = 'rank-math-options-instant-indexing';
$org_settings = get_option( $key );
if ( $is_reset ) {
if ( isset( $org_settings['bing_post_types'] ) ) {
unset( $org_settings['bing_post_types'] );
}
}
$org_settings['bing_post_types'] = isset( $settings['bing_post_types'] ) ? array_map( 'sanitize_text_field', $settings['bing_post_types'] ) : [];
update_option( $key, $org_settings, false );
return [
'settings' => $org_settings,
];
}
if ( ! in_array( $type, [ 'general', 'titles', 'sitemap' ], true ) ) {
return __( 'Invalid type.', 'rank-math' );
}
return \RankMath\Admin\Option_Center::save_settings(
$type,
$settings,
$request->get_param( 'fieldTypes' ),
$request->get_param( 'updated' ),
$is_reset
);
}
/**
* Update Settings.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function search_page( WP_REST_Request $request ) {
$term = sanitize_text_field( $request->get_param( 'searchedTerm' ) );
if ( empty( $term ) ) {
return rest_ensure_response( [ 'results' => [] ] );
}
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 = array_map(
function ( $page ) {
return [
'id' => (int) $page['ID'],
'text' => $page['post_title'],
'url' => get_permalink( $page['ID'] ),
];
},
$pages
);
return rest_ensure_response( [ 'results' => $data ] );
}
/**
* Get save module endpoint arguments.
*
* @return array
*/
private function get_save_module_args() {
return [
'module' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Module slug', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => function ( $param, $request, $key ) {
$modules = array_keys( rank_math()->manager->modules );
if ( ! in_array( $param, $modules, true ) ) {
return new WP_Error( 'invalid_module', esc_html__( 'Invalid module', 'rank-math' ), [ 'status' => 400 ] );
}
return rest_validate_request_arg( $param, $request, $key );
},
],
'state' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Module state either on or off', 'rank-math' ),
'enum' => [ 'on', 'off' ],
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
];
}
/**
* Get update seo score endpoint arguments.
*
* @return array
*/
private function get_update_seo_score_args() {
return [
'postScores' => [
'type' => 'object',
'required' => true,
'description' => esc_html__( 'Post scores', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
];
}
/**
* Get tools action endpoint arguments.
*
* @return array
*/
private function get_tools_action_args() {
return [
'action' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Action to perform', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
];
}
/**
* Get update mode endpoint arguments.
*
* @return array
*/
private function get_update_mode_args() {
return [
'mode' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Mode to set', 'rank-math' ),
'enum' => [ 'easy', 'advanced', 'custom' ],
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
];
}
/**
* Maybe update(delete) rewrite rules.
*
* @param string $module The module name.
*
* @return void
*/
private function maybe_delete_rewrite_rules( $module ) {
if ( in_array( $module, [ 'sitemap', 'llms-txt' ], true ) ) {
delete_option( 'rewrite_rules' );
}
}
}

View File

@@ -0,0 +1,193 @@
<?php
/**
* The Global functionality of the plugin.
*
* Defines the functionality loaded both on frontend.
*
* @since 1.0.15
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Controller;
use RankMath\Admin\Admin_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Front class.
*/
class Front extends WP_REST_Controller {
/**
* Constructor.
*/
public function __construct() {
$this->namespace = \RankMath\Rest\Rest_Helper::BASE;
}
/**
* Registers the routes for the objects of the controller.
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/disconnectSite',
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'disconnect_site' ],
'permission_callback' => [ $this, 'check_api_key' ],
'args' => $this->get_disconnect_site_args(),
]
);
register_rest_route(
$this->namespace,
'/getFeaturedImageId',
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'get_featured_image_id' ],
'permission_callback' => function () {
return \RankMath\Helper::has_cap( 'onpage_general' );
},
'args' => $this->get_featured_image_id_args(),
]
);
}
/**
* Check API key in request.
*
* @param WP_REST_Request $request Full details about the request.
* @return bool Whether the API key matches or not.
*/
public function check_api_key( WP_REST_Request $request ) {
$token = $request->get_param( 'token' );
$data = Admin_Helper::get_registration_data();
return isset( $data['api_key'] ) && $token === $data['api_key'];
}
/**
* Disconnect website.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function disconnect_site( WP_REST_Request $request ) {
Admin_Helper::get_registration_data( false );
return [
'code' => 'site_disconnected',
'message' => esc_html__( 'Site disconnected successfully.', 'rank-math' ),
];
}
/**
* Get featured image ID.
*
* @param WP_REST_Request $request Should include a postId parameter.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_featured_image_id( WP_REST_Request $request ) {
$resp = new WP_REST_Response();
if ( ! current_theme_supports( 'post-thumbnails' ) ) {
$resp->set_status( 200 );
$resp->set_data(
[
'success' => false,
'message' => esc_html__( 'The current theme does not have "post-thumbnails" support.', 'rank-math' ),
'featImgId' => 0,
]
);
return $resp;
}
$post_id = $request->get_param( 'postId' );
// Checks whether the current has permission to edit post.
$post_type_obj = get_post_type_object( get_post_type( $post_id ) );
if (
is_null( $post_type_obj ) ||
(
! current_user_can( $post_type_obj->cap->edit_post, $post_id ) &&
! current_user_can( $post_type_obj->cap->edit_others_posts )
)
) {
$resp->set_status( 401 );
$resp->set_data(
[
'success' => false,
'message' => esc_html__( 'Sorry, you don\'t have the required permissions to access this page.', 'rank-math' ),
'featImgId' => false,
]
);
return $resp->as_error();
}
$feat_img_id = get_post_thumbnail_id( $post_id ? $post_id : null );
if ( false === $feat_img_id ) {
$resp->set_status( 404 );
$resp->set_data(
[
'success' => false,
'message' => esc_html__( 'The post could not be found.', 'rank-math' ),
'featImgId' => false,
]
);
return $resp->as_error();
}
$resp->set_status( 200 );
$resp->set_data(
[
'success' => true,
'featImgId' => $feat_img_id,
]
);
return $resp;
}
/**
* Get featured image ID endpoint arguments.
*
* @return array
*/
private function get_featured_image_id_args() {
return [
'postId' => [
'type' => 'integer',
'required' => true,
'description' => esc_html__( 'Post ID', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
];
}
/**
* Get disconnect site endpoint arguments.
*
* @return array
*/
private function get_disconnect_site_args() {
return [
'token' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Site token', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
];
}
}

View File

@@ -0,0 +1,195 @@
<?php
/**
* Add support for headless WP.
*
* @since 1.0.15
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Controller;
use RankMath\Helpers\Url;
use RankMath\Helper;
use RankMath\Frontend\Frontend;
defined( 'ABSPATH' ) || exit;
/**
* Front class.
*/
class Headless extends WP_REST_Controller {
/**
* Whether the request is for the homepage.
*
* @var boolean
*/
public $is_home = false;
/**
* Constructor.
*/
public function __construct() {
$this->namespace = \RankMath\Rest\Rest_Helper::BASE;
}
/**
* Registers the routes for the objects of the controller.
*/
public function register_routes() {
if ( ! Helper::get_settings( 'general.headless_support' ) ) {
return;
}
register_rest_route(
$this->namespace,
'/getHead',
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_head' ],
'permission_callback' => '__return_true',
'args' => [
'url' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'URL to get HTML tags for.', 'rank-math' ),
'validate_callback' => [ $this, 'is_valid_url' ],
],
],
]
);
}
/**
* Get all tags that go in the <head>. Useful for headless WP installations.
*
* @param WP_REST_Request $request Request object, should include the "url" parameter.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_head( WP_REST_Request $request ) {
$resp = new WP_REST_Response();
$url = $request->get_param( 'url' );
$html = $this->get_html_head( $url );
$resp->set_status( 200 );
$resp->set_data(
[
'success' => true,
'head' => $html,
]
);
return $resp;
}
/**
* Return Rank Math head HTML output for the given URL.
*
* @param string $url Request URL.
*
* @return string
*/
private function get_html_head( $url ) {
$this->setup_post_head( $url );
ob_start();
do_action( 'wp' );
do_action( 'rank_math/head' );
return ob_get_clean();
}
/**
* Prepare head output for a URL.
*
* @param string $url Request URL.
*
* @return void
*/
private function setup_post_head( $url ) {
// Setup WordPress.
$_SERVER['REQUEST_URI'] = $this->generate_request_uri( $url );
remove_all_actions( 'wp' );
remove_all_actions( 'parse_request' );
wp();
if ( $this->is_home ) {
$GLOBALS['wp_query']->is_home = true;
}
remove_filter( 'option_rewrite_rules', [ $this, 'fix_query_notice' ] );
header( 'Content-Type: application/json; charset=UTF-8' );
// Setup Rank Math.
rank_math()->variables->setup();
rank_math()->manager->load_modules();
new Frontend();
}
/**
* Generate $_SERVER['REQUEST_URI'] value based on input URL.
*
* @param string $url Input URL.
* @return string
*/
public function generate_request_uri( $url ) {
$quoted = preg_quote( rtrim( home_url(), '/' ), '/' );
$request_uri = preg_replace( sprintf( '/^%s/i', $quoted ), '', rtrim( $url, '/' ) );
if ( empty( $request_uri ) ) {
$request_uri = '/';
$this->is_home = true;
$front_page_id = get_option( 'page_on_front' );
if ( 'page' === get_option( 'show_on_front' ) && $front_page_id ) {
$this->is_home = false;
$request_uri = get_post_field( 'post_name', $front_page_id );
}
add_filter( 'option_rewrite_rules', [ $this, 'fix_query_notice' ] );
}
return $request_uri;
}
/**
* Filter rewrite_rules to avoid a PHP notice.
*
* @param array $rules Original rules.
* @return array
*/
public function fix_query_notice( $rules ) {
if ( ! is_array( $rules ) || isset( $rules['$'] ) ) {
return $rules;
}
global $wp_rewrite;
$rules['$'] = $wp_rewrite->index;
return $rules;
}
/**
* Check if provided URL is valid and internal.
*
* @param string $url URL.
*
* @return boolean
*/
public function is_valid_url( $url ) {
$url = preg_replace_callback(
'/[^\x20-\x7f]/',
function ( $matcher ) {
return rawurlencode( $matcher[0] );
},
$url
);
return Url::is_url( $url ) && ! Url::is_external( $url );
}
}

View File

@@ -0,0 +1,192 @@
<?php
/**
* The routes for post related functionality
*
* Defines the functionality loaded on admin.
*
* @since 1.0.15
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Controller;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Post class.
*/
class Post extends WP_REST_Controller {
/**
* Constructor.
*/
public function __construct() {
$this->namespace = \RankMath\Rest\Rest_Helper::BASE;
}
/**
* Registers the routes for the objects of the controller.
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/updateMetaBulk',
[
'methods' => WP_REST_Server::CREATABLE,
'permission_callback' => function () {
return \RankMath\Helper::has_cap( 'onpage_general' );
},
'callback' => [ $this, 'update_bulk_meta' ],
'args' => $this->get_update_bulk_meta_args(),
]
);
if ( Helper::is_site_editor() ) {
register_rest_field(
'page',
'rankMath',
[
'get_callback' => [ $this, 'get_post_screen_meta' ],
'schema' => null,
'permission_callback' => function () {
return current_user_can( 'read' );
},
]
);
}
}
/**
* Update bulk metadata.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_bulk_meta( WP_REST_Request $request ) {
$rows = $request->get_param( 'rows' );
$object_type = $request->get_param( 'objectType' );
foreach ( $rows as $object_id => $data ) {
$object_id = absint( $object_id );
if ( ! $this->can_process( $object_id, $object_type ) ) {
continue;
}
$this->save_row( $object_id, $object_type, $data );
}
return [ 'success' => true ];
}
/**
* Whether to process current object.
*
* @param int $object_id Object ID.
* @param string $object_type Object type.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
private function can_process( $object_id, $object_type ) {
if ( ! $object_id ) {
return false;
}
if ( $object_type === 'term' ) {
$taxonomy = get_term( $object_id )->taxonomy;
return in_array( $taxonomy, Helper::get_allowed_taxonomies(), true );
}
$post_type = get_post_type( $object_id );
if ( ! Helper::is_post_type_accessible( $post_type ) && 'attachment' !== $post_type ) {
return false;
}
// Checks whether the current has permission to edit post.
$post_type_obj = get_post_type_object( $post_type );
if (
is_null( $post_type_obj ) ||
(
! current_user_can( $post_type_obj->cap->edit_post, $object_id ) &&
! current_user_can( $post_type_obj->cap->edit_others_posts )
)
) {
return false;
}
return true;
}
/**
* Save single row.
*
* @param int $object_id Object ID.
* @param string $object_type Object type.
* @param array $data Object data.
*/
private function save_row( $object_id, $object_type, $data ) {
foreach ( $data as $key => $value ) {
$this->save_column( $object_id, $object_type, $key, $value );
}
}
/**
* Save row columns.
*
* @param int $object_id Object ID.
* @param string $object_type Object type.
* @param string $column Column name.
* @param string $value Column value.
*/
private function save_column( $object_id, $object_type, $column, $value ) {
if ( ! in_array( $column, [ 'focus_keyword', 'title', 'description', 'image_alt', 'image_title' ], true ) ) {
return;
}
$sanitizer = Sanitize::get();
if ( 'image_title' === $column ) {
wp_update_post(
[
'ID' => $object_id,
'post_title' => $sanitizer->sanitize( 'image_title', $value ),
]
);
return;
}
if ( 'focus_keyword' === $column ) {
$focus_keyword = get_post_meta( $object_id, 'rank_math_' . $column, true );
$focus_keyword = explode( ',', $focus_keyword );
$focus_keyword[0] = $value;
$value = implode( ',', $focus_keyword );
}
$column = 'image_alt' === $column ? '_wp_attachment_image_alt' : 'rank_math_' . $column;
$method = $object_type === 'term' ? 'update_term_meta' : 'update_post_meta';
$method( $object_id, $column, $sanitizer->sanitize( $column, $value ) );
}
/**
* Get update metadta endpoint arguments.
*
* @return array
*/
private function get_update_bulk_meta_args() {
return [
'rows' => [
'required' => true,
'description' => esc_html__( 'Selected posts to update the data for.', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
];
}
}

View File

@@ -0,0 +1,294 @@
<?php
/**
* REST api helper.
*
* @since 1.0.15
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use WP_Error;
use RankMath\Helper;
use RankMath\Helpers\DB as DB_Helper;
defined( 'ABSPATH' ) || exit;
/**
* Rest_Helper class.
*/
class Rest_Helper {
/**
* REST namespace.
*
* @var string
*/
const BASE = 'rankmath/v1';
/**
* Determines if the current user can manage options.
*
* @return true
*/
public static function can_manage_options() {
return current_user_can( 'manage_options' );
}
/**
* Checks whether a given request has permission to update redirection.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function get_redirection_permissions_check() {
if ( ! Helper::is_module_active( 'redirections' ) || ! Helper::has_cap( 'redirections' ) ) {
return new WP_Error(
'rest_cannot_edit',
__( 'Sorry, you are not allowed to create/update redirection.', 'rank-math' ),
[ 'status' => rest_authorization_required_code() ]
);
}
return true;
}
/**
* Checks whether a given request has permission to update schema.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function get_schema_permissions_check( $request ) {
if ( ! Helper::is_module_active( 'rich-snippet' ) || ! Helper::has_cap( 'onpage_snippet' ) ) {
return new WP_Error(
'rest_cannot_edit',
__( 'Sorry, you are not allowed to create/update schema.', 'rank-math' ),
[ 'status' => rest_authorization_required_code() ]
);
}
return self::get_object_permissions_check( $request );
}
/**
* Checks whether a given request has permission to read types.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function get_object_permissions_check( $request ) {
$object_id = $request->get_param( 'objectID' );
$object_type = $request->get_param( 'objectType' );
if ( in_array( $object_type, [ 'post', 'term', 'user' ], true ) ) {
$method = "get_{$object_type}_permissions_check";
return self::$method( $request );
}
return false;
}
/**
* Checks whether a given request has permission to read post.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function get_post_permissions_check( $request ) {
$object_id = $request->get_param( 'objectID' );
if ( $object_id === 0 ) {
return true;
}
$post = self::get_post( $object_id );
if ( is_wp_error( $post ) ) {
return $post;
}
if ( ! Helper::is_post_type_accessible( $post->post_type ) && 'rank_math_schema' !== $post->post_type ) {
return new WP_Error(
'rest_cannot_edit',
__( 'Sorry, you are not allowed to edit this post type.', 'rank-math' ),
[ 'status' => rest_authorization_required_code() ]
);
}
$post_type = get_post_type_object( $post->post_type );
if (
current_user_can( $post_type->cap->edit_post, $post->ID ) ||
current_user_can( $post_type->cap->edit_others_posts )
) {
return true;
}
return new WP_Error(
'rest_cannot_edit',
__( 'Sorry, you are not allowed to edit this post.', 'rank-math' ),
[ 'status' => rest_authorization_required_code() ]
);
}
/**
* Get the post, if the ID is valid.
*
* @param int $id Supplied ID.
*
* @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
*/
public static function get_post( $id ) {
$error = new WP_Error(
'rest_post_invalid_id',
__( 'Invalid post ID.', 'rank-math' ),
[ 'status' => 404 ]
);
if ( (int) $id <= 0 ) {
return $error;
}
$post = get_post( (int) $id );
if ( empty( $post ) || empty( $post->ID ) ) {
return $error;
}
return $post;
}
/**
* Checks whether a given request has permission to read term.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function get_term_permissions_check( $request ) {
$term_id = $request->get_param( 'objectID' );
$term = self::get_term( $term_id );
if ( is_wp_error( $term ) ) {
return $term;
}
if (
! in_array( $term->taxonomy, array_keys( Helper::get_accessible_taxonomies() ), true ) ||
! current_user_can( get_taxonomy( $term->taxonomy )->cap->edit_terms, $term_id )
) {
return new WP_Error(
'rest_cannot_edit',
__( 'Sorry, you are not allowed to edit this term.', 'rank-math' ),
[ 'status' => rest_authorization_required_code() ]
);
}
return true;
}
/**
* Get the term, if the ID is valid.
*
* @param int $id Supplied ID.
*
* @return WP_Term|WP_Error Term object if ID is valid, WP_Error otherwise.
*/
public static function get_term( $id ) {
$error = new WP_Error(
'rest_term_invalid_id',
__( 'Invalid term ID.', 'rank-math' ),
[ 'status' => 404 ]
);
if ( (int) $id <= 0 ) {
return $error;
}
global $wpdb;
$term = DB_Helper::get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->term_taxonomy AS t WHERE t.term_id = %d LIMIT 1", $id ) );
if ( empty( $term ) || empty( $term->term_id ) ) {
return $error;
}
return $term;
}
/**
* Checks whether a given request has permission to read user.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function get_user_permissions_check( $request ) {
$user_id = $request->get_param( 'objectID' );
return current_user_can( 'edit_user', $user_id ) && Helper::get_settings( 'titles.author_add_meta_box' );
}
/**
* Param emptiness validate callback.
*
* @param mixed $param Param to validate.
*
* @return boolean
*/
public static function is_param_empty( $param ) {
if ( empty( $param ) ) {
return new WP_Error(
'param_value_empty',
esc_html__( 'Sorry, field is empty which is not allowed.', 'rank-math' )
);
}
return true;
}
/**
* Checks whether a given request has permission to update settings.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
*/
public static function can_manage_settings( $request ) {
$type = $request->get_param( 'type' );
$type = $type === 'instant-indexing' ? 'general' : $type;
return $type === 'roleCapabilities' ? current_user_can( 'rank_math_role_manager' ) : current_user_can( "rank_math_$type" );
}
/**
* Param emptiness validate callback.
*
* @param mixed $param Param to validate.
*
* @return boolean
*/
public static function is_valid_string( $param ) {
if ( empty( $param ) ) {
return new WP_Error(
'param_value_empty',
esc_html__( 'Sorry, field is empty which is not allowed.', 'rank-math' )
);
}
return self::is_alphanumerical( $param );
}
/**
* Check the alphanumerical string.
*
* @param mixed $param Param to validate.
*
* @return boolean
*/
public static function is_alphanumerical( $param ) {
if ( ! preg_match( '/^[a-zA-Z0-9]+$/', $param ) ) {
return new WP_Error(
'param_value_empty',
esc_html__( 'Sorry, the field contains invalid characters.', 'rank-math' )
);
}
return true;
}
}

View File

@@ -0,0 +1,156 @@
<?php
/**
* The Global functionality of the plugin.
*
* Defines the functionality loaded on admin.
*
* @since 1.0.15
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use RankMath\CMB2;
defined( 'ABSPATH' ) || exit;
/**
* Admin class.
*/
class Sanitize {
/**
* Main instance
*
* Ensure only one instance is loaded or can be loaded.
*
* @return Sanitize
*/
public static function get() {
static $instance;
if ( is_null( $instance ) && ! ( $instance instanceof Sanitize ) ) {
$instance = new Sanitize();
}
return $instance;
}
/**
* Sanitize value
*
* @param string $field_id Field id to sanitize.
* @param mixed $value Field value.
*
* @return mixed Sanitized value.
*/
public function sanitize( $field_id, $value ) {
$sanitized_value = '';
switch ( $field_id ) {
case 'rank_math_title':
case 'rank_math_description':
case 'rank_math_snippet_name':
case 'rank_math_snippet_desc':
case 'rank_math_facebook_title':
case 'rank_math_facebook_description':
case 'rank_math_twitter_title':
case 'rank_math_twitter_description':
$sanitized_value = wp_filter_nohtml_kses( $value );
break;
case 'rank_math_snippet_recipe_ingredients':
case 'rank_math_snippet_recipe_instructions':
case 'rank_math_snippet_recipe_single_instructions':
$sanitized_value = $this->sanitize_textarea( $field_id, $value );
break;
case 'rank_math_canonical_url':
$sanitized_value = esc_url_raw( $value );
break;
case 'rank_math_snippet_job_description':
$sanitized_value = wp_kses(
$value,
[
'br' => [],
'p' => [],
'ul' => [],
'li' => [],
]
);
break;
case 'rank_math_snippet_answer':
$sanitized_value = wp_kses(
$value,
[
'h1' => [],
'h2' => [],
'h3' => [],
'h4' => [],
'h5' => [],
'h6' => [],
'br' => [],
'ol' => [],
'ul' => [],
'li' => [],
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
'p' => [],
'b' => [],
'i' => [],
'div' => [],
'strong' => [],
'em' => [],
]
);
break;
default:
$sanitized_value = is_array( $value ) ? $this->loop_sanitize( $value ) : CMB2::sanitize_textfield( $value );
}
return $sanitized_value;
}
/**
* Sanitize Textarea field
*
* @param string $field_id Field id to sanitize.
* @param mixed $value Field value.
*
* @return mixed Sanitized value.
*/
public function sanitize_textarea( $field_id, $value ) {
return is_array( $value ) ? $this->loop_sanitize( $value, 'sanitize_textarea' ) : sanitize_textarea_field( $value );
}
/**
* Sanitize array
*
* @param array $values Field value.
* @param array $method Sanitize Method.
*
* @return mixed Sanitized value.
*/
public function loop_sanitize( $values, $method = 'sanitize' ) {
$sanitized_value = [];
$type = $values['@type'] ?? '';
foreach ( $values as $key => $value ) {
$field_id = $key;
if ( 'Answer' === $type && 'text' === $key ) {
$field_id = 'rank_math_snippet_answer';
}
if ( 'JobPosting' === $type && 'description' === $key ) {
$field_id = 'rank_math_snippet_job_description';
}
$sanitized_value[ CMB2::sanitize_textfield( $key ) ] = is_array( $value ) ? $this->loop_sanitize( $value, $method ) : $this->$method( $field_id, $value );
}
return $sanitized_value;
}
}

View File

@@ -0,0 +1,170 @@
<?php
/**
* The Rest endpoints used in the Setup Wizard page.
*
* Defines the functionality loaded on admin.
*
* @since 1.0.245
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use WP_REST_Request;
use WP_REST_Controller;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
/**
* Setup_Wizard class.
*/
class Setup_Wizard extends WP_REST_Controller {
/**
* Constructor.
*/
public function __construct() {
$this->namespace = \RankMath\Rest\Rest_Helper::BASE . '/setupWizard';
}
/**
* Registers the routes for the objects of the controller.
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/getStepData',
[
'methods' => 'POST',
'callback' => [ $this, 'get_step_data' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
'args' => $this->get_step_args(),
]
);
register_rest_route(
$this->namespace,
'/updateStepData',
[
'methods' => 'POST',
'callback' => [ $this, 'update_step_data' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
'args' => $this->update_step_args(),
]
);
register_rest_route(
$this->namespace,
'/updateTrackingOptin',
[
'methods' => 'POST',
'callback' => [ $this, 'update_tracking_optin' ],
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'can_manage_options' ],
'args' => $this->tracking_optin_args(),
]
);
}
/**
* Get Current step data.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return array View Data.
*/
public function get_step_data( WP_REST_Request $request ) {
$step = $request->get_param( 'step' );
// Track step change.
do_action( 'rank_math/setup_wizard/step_viewed', $step );
return \RankMath\Admin\Setup_Wizard::get_localized_data( $step );
}
/**
* Update the step data.
*
* @param WP_REST_Request $request Full details about the request.
*/
public function update_step_data( WP_REST_Request $request ) {
$step = $request->get_param( 'step' );
$values = $request->get_param( 'value' );
return \RankMath\Admin\Setup_Wizard::save_data( $step, $values );
}
/**
* Update tracking opt-in status.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return array Response data.
*/
public function update_tracking_optin( WP_REST_Request $request ) {
$enable_tracking = $request->get_param( 'enable_tracking' );
do_action( 'rank_math/setup_wizard/enable_tracking', $enable_tracking === 'on' );
return [
'success' => true,
'status' => 200,
];
}
/**
* Get step endpoint arguments.
*
* @return array
*/
private function get_step_args() {
return [
'step' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Current Step', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
];
}
/**
* Update step data endpoint arguments.
*
* @return array
*/
private function update_step_args() {
return [
'step' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Current Step', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
'value' => [
'type' => 'object',
'required' => true,
'description' => esc_html__( 'Current Step Data', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
];
}
/**
* Tracking opt-in endpoint arguments.
*
* @return array
*/
private function tracking_optin_args() {
return [
'enable_tracking' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Enable Tracking', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => 'rest_validate_request_arg',
],
];
}
}

View File

@@ -0,0 +1,455 @@
<?php
/**
* The shared REST routes for front and backend.
*
* Defines the functionality loaded both on front and backend.
*
* @since 1.0.60
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Rest;
use RankMath\Helper;
use RankMath\Helpers\Str;
use RankMath\Helpers\Url;
use RankMath\Redirections\Metabox;
use RankMath\Rest\Rest_Helper;
use RankMath\Rest\Sanitize;
use RankMath\Traits\Meta;
use RankMath\Schema\DB;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Server;
defined( 'ABSPATH' ) || exit;
/**
* Shared class.
*/
class Shared extends WP_REST_Controller {
use Meta;
/**
* Constructor.
*/
public function __construct() {
$this->namespace = Rest_Helper::BASE;
}
/**
* Register shared routes.
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/updateRedirection',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'update_redirection' ],
'args' => $this->get_update_redirection_args(),
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'get_redirection_permissions_check' ],
]
);
register_rest_route(
$this->namespace,
'/updateMeta',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'update_metadata' ],
'args' => $this->get_update_metadata_args(),
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'get_object_permissions_check' ],
]
);
register_rest_route(
$this->namespace,
'/updateSchemas',
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [ $this, 'update_schemas' ],
'args' => $this->get_update_schemas_args(),
'permission_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'get_schema_permissions_check' ],
]
);
}
/**
* Update redirection.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_redirection( WP_REST_Request $request ) {
$cmb = new \stdClass();
$metabox = new Metabox();
$cmb->object_id = $request->get_param( 'objectID' );
$cmb->object_type = null !== $request->get_param( 'objectType' ) ? $request->get_param( 'objectType' ) : 'post';
$cmb->data_to_save = [
'has_redirect' => $request->get_param( 'hasRedirect' ),
'redirection_id' => $request->get_param( 'redirectionID' ),
'redirection_url_to' => $request->get_param( 'redirectionUrl' ),
'redirection_sources' => \str_replace( home_url( '/' ), '', $request->get_param( 'redirectionSources' ) ),
'redirection_header_code' => $request->get_param( 'redirectionType' ) ? $request->get_param( 'redirectionType' ) : 301,
'rank_math_enable_redirection' => 'on',
];
if ( false === $request->get_param( 'hasRedirect' ) ) {
unset( $cmb->data_to_save['redirection_url_to'] );
}
if ( empty( $request->get_param( 'redirectionID' ) ) ) {
unset( $cmb->data_to_save['redirection_id'] );
}
return $metabox->save_advanced_meta( $cmb );
}
/**
* Update metadata.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_metadata( WP_REST_Request $request ) {
$object_id = $request->get_param( 'objectID' );
$object_type = $request->get_param( 'objectType' );
$meta = apply_filters( 'rank_math/filter_metadata', $request->get_param( 'meta' ), $request );
$content = $request->get_param( 'content' );
if ( $object_id === 0 ) {
$this->update_site_editor_homepage( $meta );
return [
'slug' => '/',
'schemas' => [],
];
}
do_action( 'rank_math/pre_update_metadata', $object_id, $object_type, $content );
$new_slug = true;
if ( isset( $meta['permalink'] ) && ! empty( $meta['permalink'] ) && 'post' === $object_type ) {
$post = get_post( $object_id );
$new_slug = wp_unique_post_slug( $meta['permalink'], $post->ID, $post->post_status, $post->post_type, $post->post_parent );
if ( $new_slug !== $post->post_name ) {
wp_update_post(
[
'ID' => $object_id,
'post_name' => $new_slug,
]
);
}
unset( $meta['permalink'] );
}
// Add protection.
remove_all_filters( 'is_protected_meta' );
add_filter( 'is_protected_meta', [ $this, 'only_this_plugin' ], 10, 2 );
$sanitizer = Sanitize::get();
foreach ( $meta as $meta_key => $meta_value ) {
// Delete schema by meta id.
if ( Str::starts_with( 'rank_math_delete_', $meta_key ) ) {
$this->maybe_delete_schema( $object_type, $object_id, $meta_key );
continue;
}
if ( empty( $meta_value ) ) {
delete_metadata( $object_type, $object_id, $meta_key );
continue;
}
$this->update_meta( $object_type, $object_id, $meta_key, $sanitizer->sanitize( $meta_key, $meta_value ) );
}
return [
'slug' => $new_slug,
'schemas' => DB::get_schemas( $object_id, "{$object_type}meta", true ),
];
}
/**
* Update metadata.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function update_schemas( WP_REST_Request $request ) {
$object_id = $request->get_param( 'objectID' );
$object_type = $request->get_param( 'objectType' );
$schemas = apply_filters( 'rank_math/schema/filter_data', $request->get_param( 'schemas' ), $request );
$new_ids = [];
do_action( 'rank_math/pre_update_schema', $object_id, $object_type );
$sanitizer = Sanitize::get();
foreach ( $schemas as $meta_id => $schema ) {
$schema = $sanitizer->sanitize( 'rank_math_schema', $schema );
$schema = $this->sanitize_schema_type( $schema );
$type = is_array( $schema['@type'] ) ? $schema['@type'][0] : $schema['@type'];
$meta_key = 'rank_math_schema_' . $type;
$schema = wp_kses_post_deep( $schema );
// Add new.
if ( Str::starts_with( 'new-', $meta_id ) ) {
$new_ids[ $meta_id ] = add_metadata( $object_type, $object_id, $meta_key, $schema );
// Add "shortcut" to the new schema: a meta data where the key is $schema['metadata']['shortcode'] and the value is the new meta id.
if ( isset( $schema['metadata']['shortcode'] ) ) {
add_metadata( $object_type, $object_id, 'rank_math_shortcode_schema_' . $schema['metadata']['shortcode'], $new_ids[ $meta_id ] );
}
continue;
}
// Update old.
$db_id = absint( str_replace( 'schema-', '', $meta_id ) );
$prev_value = update_metadata_by_mid( $object_type, $db_id, $schema, $meta_key );
// Update or delete the "shortcut" to the new schema.
if ( isset( $schema['metadata']['shortcode'] ) ) {
update_metadata( $object_type, $object_id, 'rank_math_shortcode_schema_' . $schema['metadata']['shortcode'], $db_id );
} elseif ( isset( $prev_value['metadata']['shortcode'] ) ) {
delete_metadata( $object_type, $object_id, 'rank_math_shortcode_schema_' . $prev_value['metadata']['shortcode'] );
}
}
do_action( 'rank_math/schema/update', $object_id, $schemas, $object_type );
return $new_ids;
}
/**
* Allow only rank math meta keys
*
* @param bool $is_protected Whether the key is considered protected.
* @param string $meta_key Meta key.
*
* @return bool
*/
public function only_this_plugin( $is_protected, $meta_key ) {
return Str::starts_with( 'rank_math_', $meta_key );
}
/**
* Get update redirection endpoint arguments.
*
* @return array
*/
private function get_update_redirection_args() {
return [
'objectID' => [
'type' => 'integer',
'required' => true,
'description' => esc_html__( 'Object unique id', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
'objectType' => [
'type' => 'string',
'default' => 'post',
'required' => true,
'description' => esc_html__( 'Object Type i.e. post, term, user', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_valid_string' ],
],
'hasRedirect' => [
'type' => 'boolean',
'required' => true,
'description' => esc_html__( 'Whether the object has a redirect or not', 'rank-math' ),
],
'redirectionID' => [
'type' => 'string',
'required' => false,
'description' => esc_html__( 'Redirection ID', 'rank-math' ),
],
'redirectionUrl' => [
'type' => 'string',
'required' => false,
'description' => esc_html__( 'Redirection URL', 'rank-math' ),
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => function ( $param, $request ) {
$redirection_type = $request->get_param( 'redirectionType' );
if ( in_array( $param, [ '301', '302', '307' ], true ) ) {
return Url::is_url( $param );
}
return true;
},
],
'redirectionType' => [
'type' => 'string',
'default' => '301',
'required' => true,
'description' => esc_html__( 'Redirection Type', 'rank-math' ),
'enum' => [ '301', '302', '307', '410', '451' ],
'sanitize_callback' => 'rest_sanitize_request_arg',
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_valid_string' ],
],
];
}
/**
* Get update metadata endpoint arguments.
*
* @return array
*/
private function get_update_metadata_args() {
return [
'objectType' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Object Type i.e. post, term, user', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
'objectID' => [
'type' => 'integer',
'required' => true,
'description' => esc_html__( 'Object unique id', 'rank-math' ),
'validate_callback' => function ( $param ) {
if ( empty( $param ) && 0 !== $param ) {
return new WP_Error(
'param_value_empty',
esc_html__( 'Sorry, field is empty which is not allowed.', 'rank-math' )
);
}
return true;
},
],
'meta' => [
'required' => true,
'description' => esc_html__( 'Meta to add or update data.', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
];
}
/**
* Update site editor homepage metadata.
*
* @param array $meta Metadata to update.
*/
private function update_site_editor_homepage( $meta ) {
$meta_keys = [
'homepage_title' => 'rank_math_title',
'homepage_description' => 'rank_math_description',
'homepage_facebook_title' => 'rank_math_facebook_title',
'homepage_facebook_description' => 'rank_math_facebook_description',
'homepage_facebook_image' => 'rank_math_facebook_image',
'homepage_facebook_image_id' => 'rank_math_facebook_image_id',
'homepage_robots' => 'rank_math_robots',
'homepage_advanced_robots' => 'rank_math_advanced_robots',
'breadcrumbs_home_label' => 'rank_math_breadcrumb_title',
];
$settings = rank_math()->settings->all_raw();
foreach ( $meta_keys as $key => $meta_key ) {
if ( empty( $meta[ $meta_key ] ) ) {
continue;
}
$prefix = $key === 'breadcrumbs_home_label' ? 'general' : 'titles';
$settings[ $prefix ][ $key ] = $meta[ $meta_key ];
}
Helper::update_all_settings( $settings['general'], $settings['titles'], null );
}
/**
* Make sure that the Schema @type is alphanumerical.
*
* @param array $schema Schema to sanitize.
* @return array
*/
private function sanitize_schema_type( $schema ) {
if ( ! isset( $schema['@type'] ) ) {
return $schema;
}
if ( ! is_array( $schema['@type'] ) ) {
// Sanitize single type.
$schema['@type'] = preg_replace( '/[^a-zA-Z0-9]/', '', $schema['@type'] );
return $schema;
}
// Sanitize each type.
foreach ( $schema['@type'] as $key => $type ) {
$schema['@type'][ $key ] = preg_replace( '/[^a-zA-Z0-9]/', '', $type );
}
return $schema;
}
/**
* Get update schemas endpoint arguments.
*
* @return array
*/
private function get_update_schemas_args() {
return [
'objectType' => [
'type' => 'string',
'required' => true,
'description' => esc_html__( 'Object Type i.e. post, term, user', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
'objectID' => [
'type' => 'integer',
'required' => true,
'description' => esc_html__( 'Object unique id', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
'schemas' => [
'required' => true,
'description' => esc_html__( 'schemas to add or update data.', 'rank-math' ),
'validate_callback' => [ '\\RankMath\\Rest\\Rest_Helper', 'is_param_empty' ],
],
];
}
/**
* Maybe delete schema.
*
* This function checks if a schema should be deleted based on the provided object type, object ID, and meta key.
*
* @param string $object_type The type of the object (e.g., post, term, user).
* @param int $object_id The ID of the object.
* @param string $meta_key The meta key associated with the schema.
*/
private function maybe_delete_schema( $object_type, $object_id, $meta_key ) {
// Early bail if user doesn't have the capability to edit the schema data.
if ( ! Helper::has_cap( 'onpage_snippet' ) ) {
return;
}
update_metadata( $object_type, $object_id, 'rank_math_rich_snippet', 'off' );
$meta_id = absint( \str_replace( 'rank_math_delete_schema-', '', $meta_key ) );
$schemas = DB::get_schemas( $object_id, "{$object_type}meta" );
// Early bail if meta_id doesn't match with the schema data of the current post.
if ( empty( $schemas ) || ! in_array( "schema-{$meta_id}", array_keys( $schemas ), true ) ) {
return;
}
// First, delete the "shortcut" to the new schema.
$schema = \get_metadata_by_mid( $object_type, $meta_id );
if ( ! empty( $schema->meta_value ) ) {
// Maybe unserialize the schema.
$schema = \maybe_unserialize( $schema->meta_value );
if ( ! empty( $schema['metadata']['shortcode'] ) ) {
\delete_metadata( $object_type, $object_id, 'rank_math_shortcode_schema_' . $schema['metadata']['shortcode'] );
}
}
// Now delete the schema.
\delete_metadata_by_mid( $object_type, $meta_id );
}
}