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

View File

@@ -0,0 +1 @@
!function(){"use strict";var e={n:function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,{a:t}),t},d:function(n,t){for(var r in t)e.o(t,r)&&!e.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:t[r]})},o:function(e,n){return Object.prototype.hasOwnProperty.call(e,n)}},n=jQuery,t=e.n(n);function r(e,n,r,o){n=n||"error",o=o||!1;var i=t()('<div class="notice notice-'+n+' is-dismissible"><p>'+e+"</p></div>").hide();r.next(".notice").remove(),r.after(i),i.slideDown(),t()(document).trigger("wp-updates-notice-added"),o&&setTimeout((function(){i.fadeOut((function(){i.remove()}))}),o)}var o,i=lodash;(o=jQuery)((function(){var e=o("#indexnow_urls"),n=o("#indexnow_submit"),t=o("#indexnow_spinner"),a=o("div.cmb2-id-indexnow-urls"),s=!1,d="all",c=function(){s||(s=!0,o.ajax({url:rankMath.indexNow.restUrl+"/getLog",data:{filter:d},type:"GET",beforeSend:function(e){e.setRequestHeader("X-WP-Nonce",rankMath.api.nonce)},success:function(e){if(o("#indexnow_clear_history, #indexnow_history_filters").removeClass("hidden"),0===e.total&&o("#indexnow_clear_history, #indexnow_history_filters").addClass("hidden"),o('#indexnow_history_filters a[data-filter="'+d+'"]').addClass("current").siblings().removeClass("current"),!e.data.length)return n=o("#indexnow_history").find("thead th").length,void o("#indexnow_history").find("tbody").html('<tr><td colspan="'+n+'">'+rankMath.indexNow.i18n.noHistory+"</td></tr>");var n,t="";e.data.forEach((function(e){t+="<tr>",t+='<td title="'+e.timeFormatted+'">'+e.timeHumanReadable+"</td>",t+="<td>"+e.url+"</td>",t+="<td>"+e.status+"</td>",t+="</tr>"})),o("#indexnow_history tbody").html(t)},error:function(e){r(rankMath.indexNow.i18n.getHistoryError,"error",o("#indexnow_history"),5e3)},complete:function(){s=!1}}))};n.on("click",(function(i){i.preventDefault();var s=e.val();n.addClass("disabled"),t.addClass("is-active"),o.ajax({url:rankMath.indexNow.restUrl+"/submitUrls",type:"POST",beforeSend:function(e){e.setRequestHeader("X-WP-Nonce",rankMath.api.nonce)},data:{urls:s},success:function(n){n.success?(r(n.message,"success",a,5e3),e.val("")):r(n.message,"error",a,5e3)},error:function(e){r(void 0!==e.responseJSON.message?e.responseJSON.message:rankMath.indexNow.i18n.submitError,"error",a,5e3)},complete:function(){n.removeClass("disabled"),t.removeClass("is-active"),d="all",c()}})})),o("#indexnow_show_response_codes").on("click",(function(e){e.preventDefault(),o(this).toggleClass("active"),o("#indexnow_response_codes").toggleClass("hidden")})),function(){o("#indexnow_clear_history").on("click",(function(e){e.preventDefault(),o.ajax({url:rankMath.indexNow.restUrl+"/clearLog",type:"POST",beforeSend:function(e){e.setRequestHeader("X-WP-Nonce",rankMath.api.nonce)},success:function(e){c()},error:function(e){r(rankMath.indexNow.i18n.clearHistoryError,"error",a,5e3)}})}));var e=(0,i.toInteger)(rankMath.indexNow.refreshHistoryInterval);e>0&&(e=Math.max((0,i.toInteger)(rankMath.indexNow.refreshHistoryInterval),1e3),setInterval(c,e)),o("#indexnow_history_filters a").on("click",(function(e){e.preventDefault();var n=o(this).data("filter");n!==d&&(d=n,c())})),c()}(),o("#indexnow_reset_key").on("click",(function(e){e.preventDefault();var n=o("#indexnow_api_key").val();o("#indexnow_api_key").val("..."),o.ajax({url:rankMath.indexNow.restUrl+"/resetKey",type:"POST",beforeSend:function(e){e.setRequestHeader("X-WP-Nonce",rankMath.api.nonce)},success:function(e){o("#indexnow_api_key").val(e.key),o("#indexnow_api_key_location").text(e.location),o("#indexnow_check_key").attr("href",e.location)},error:function(e){o("#indexnow_api_key").val(n)}})}))}))}();

View File

@@ -0,0 +1,391 @@
<?php
/**
* IndexNow API
*
* @since 1.0.56
* @package RankMath
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Instant_Indexing;
use RankMath\Helper;
use RankMath\Traits\Hooker;
defined( 'ABSPATH' ) || exit;
/**
* API class.
*
* @codeCoverageIgnore
*/
class Api {
use Hooker;
/**
* IndexNow API URL.
*
* @var string
*/
private $api_url = 'https://api.indexnow.org/indexnow/';
/**
* IndexNow API key.
*
* @var string
*/
protected $api_key = '';
/**
* 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;
/**
* Next submission is a manual submission.
*
* @var bool
*/
public $is_manual = true;
/**
* User agent used for the API requests.
*
* @var string
*/
protected $user_agent = '';
/**
* User agent used for the API requests.
*
* @var string
*/
protected $version = '';
/**
* 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->user_agent = 'RankMath/' . md5( esc_url( home_url( '/' ) ) );
$instance->version = rank_math()->version;
}
return $instance;
}
/**
* Make request to the IndexNow API.
*
* @param array $urls URLs to submit.
* @param bool $manual Whether the request is manual or not.
*
* @return bool
*/
public function submit( $urls, $manual = null ) {
$this->reset();
if ( ! is_null( $manual ) ) {
$this->is_manual = (bool) $manual;
}
$data = $this->get_payload( $urls );
$response = wp_remote_post(
'https://api.indexnow.org/indexnow/',
[
'body' => $data,
'headers' => [
'Content-Type' => 'application/json',
'User-Agent' => $this->user_agent,
'X-Source-Info' => 'https://rankmath.com/' . $this->version . '/' . ( $this->is_manual ? '1' : '' ),
],
]
);
if ( is_wp_error( $response ) ) {
$this->last_error = 'WP_Error: ' . $response->get_error_message();
$this->log( (array) $urls, 0, $this->last_error );
return false;
}
$this->last_code = wp_remote_retrieve_response_code( $response );
$this->last_response = wp_remote_retrieve_body( $response );
if ( in_array( $this->last_code, [ 200, 202, 204 ], true ) ) {
$this->is_success = true;
$this->log( (array) $urls, $this->last_code, 'OK' );
return true;
}
$message = wp_remote_retrieve_response_message( $response );
$this->set_error_message( $message );
$this->log( (array) $urls, $this->last_code, $this->last_error );
return false;
}
/**
* Get the last error message.
*
* @return string
*/
public function get_error() {
return $this->last_error;
}
/**
* Get the last response code.
*
* @return int
*/
public function get_response_code() {
return $this->last_code;
}
/**
* Get the last response.
*
* @return string
*/
public function get_response() {
return $this->last_response;
}
/**
* Get the host parameter value to send to the API.
*
* @return string
*/
public function get_host() {
$host = wp_parse_url( home_url(), PHP_URL_HOST );
if ( empty( $host ) ) {
$host = 'localhost';
}
/**
* Filter the host parameter value to send to the API.
*
* @param string $host Host.
*/
return $this->do_filter( 'instant_indexing/indexnow_host', $host );
}
/**
* Get the API key.
*
* @return string
*/
public function get_key() {
if ( ! empty( $this->api_key ) ) {
return $this->api_key;
}
$api_key = Helper::get_settings( 'instant_indexing.indexnow_api_key' );
/**
* Filter the API key.
*
* @param string $api_key API key.
*/
$this->api_key = $this->do_filter( 'instant_indexing/indexnow_key', $api_key );
return $this->api_key;
}
/**
* Alias for get_key().
*/
public function get_api_key() {
return $this->get_key();
}
/**
* Get the API key location.
*
* @param string $context Key context.
* @return string
*/
public function get_key_location( $context = '' ) {
/**
* Filter the API key location.
*
* @param string $location Location.
*/
return $this->do_filter( 'instant_indexing/indexnow_key_location', trailingslashit( home_url() ) . $this->get_key() . '.txt', $context );
}
/**
* Log the request.
*
* @param array $urls URLs to submit.
* @param int $status Response code.
* @param string $message Response message.
*/
public function log( $urls, $status, $message = '' ) {
$log = get_option( 'rank_math_indexnow_log', [] );
$url = $this->get_loggable_url( $urls );
if ( ! $url ) {
return;
}
$log[] = [
'url' => $url,
'status' => (int) $status,
'manual_submission' => (bool) $this->is_manual,
'message' => $message,
'time' => time(),
];
// Only keep the last 100 entries.
$log = array_slice( $log, -100 );
update_option( 'rank_math_indexnow_log', $log, false );
}
/**
* Get the loggable URL from an array of URLs.
* If multiple URLs are submitted, return the first one and [+12]
*
* @param array $urls URLs to submit.
*
* @return string
*/
public function get_loggable_url( $urls ) {
$urls = array_values( (array) $urls );
$count_urls = count( $urls );
if ( ! $count_urls ) {
return '';
}
$url = $urls[0];
if ( $count_urls > 1 ) {
$url .= ' [+' . ( $count_urls - 1 ) . ']';
}
return $url;
}
/**
* Get the log.
*
* @return array
*/
public function get_log() {
return get_option( 'rank_math_indexnow_log', [] );
}
/**
* Clear the log.
*/
public function clear_log() {
delete_option( 'rank_math_indexnow_log' );
}
/**
* Reset object properties.
*/
private function reset() {
$this->last_error = '';
$this->last_code = 0;
$this->last_response = '';
$this->is_success = false;
}
/**
* Get the additional data to send to the API.
*
* @param array $urls URLs to submit.
*
* @return array
*/
private function get_payload( $urls ) {
return wp_json_encode(
[
'host' => $this->get_host(),
'key' => $this->get_key(),
'keyLocation' => $this->get_key_location( 'request_payload' ),
'urlList' => (array) $urls,
]
);
}
/**
* Get the error message from the response message.
*
* @param string $message Response message.
*/
private function set_error_message( $message ) {
if ( ! empty( $message ) ) {
$this->last_error = $message;
return;
}
$message = __( 'Unknown error.', 'rank-math' );
$message_map = [
400 => __( 'Invalid request.', 'rank-math' ),
403 => __( 'Invalid API key.', 'rank-math' ),
422 => __( 'Invalid URL.', 'rank-math' ),
429 => __( 'Too many requests.', 'rank-math' ),
500 => __( 'Internal server error.', 'rank-math' ),
];
if ( isset( $message_map[ $this->last_code ] ) ) {
$message = $message_map[ $this->last_code ];
}
$this->last_error = $message;
}
/**
* Generate and save a new API key.
*/
public function reset_key() {
$settings = Helper::get_settings( 'instant_indexing', [] );
$settings['indexnow_api_key'] = $this->generate_api_key();
$this->api_key = $settings['indexnow_api_key'];
update_option( 'rank-math-options-instant-indexing', $settings );
}
/**
* Generate new random API key.
*/
private function generate_api_key() {
$api_key = wp_generate_uuid4();
$api_key = preg_replace( '[-]', '', $api_key );
return $api_key;
}
}

View File

@@ -0,0 +1,475 @@
<?php
/**
* Instant Indexing module.
*
* @since 1.0.56
* @package RankMath
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Instant_Indexing;
use RankMath\KB;
use RankMath\Helper;
use RankMath\Module\Base;
use RankMath\Traits\Hooker;
use RankMath\Traits\Ajax;
use RankMath\Admin\Options;
use RankMath\Helpers\Param;
defined( 'ABSPATH' ) || exit;
/**
* Instant_Indexing class.
*/
class Instant_Indexing extends Base {
use Hooker, Ajax;
/**
* API Object.
*
* @var string
*/
private $api;
/**
* Keep log of submitted objects to avoid double submissions.
*
* @var array
*/
private $submitted = [];
/**
* Store previous post status that we can check agains in save_post.
*
* @var array
*/
private $previous_post_status = [];
/**
* Store original permalinks for when they get trashed.
*
* @var array
*/
private $previous_post_permalinks = [];
/**
* Restrict to one request every X seconds to a given URL.
*/
const THROTTLE_LIMIT = 5;
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
$this->action( 'admin_enqueue_scripts', 'enqueue', 20 );
if ( ! $this->is_configured() ) {
Api::get()->reset_key();
}
$post_types = $this->get_auto_submit_post_types();
if ( ! empty( $post_types ) ) {
$this->filter( 'wp_insert_post_data', 'before_save_post', 10, 4 );
}
foreach ( $post_types as $post_type ) {
$this->action( 'save_post_' . $post_type, 'save_post', 10, 3 );
$this->filter( "bulk_actions-edit-{$post_type}", 'post_bulk_actions', 11 );
$this->filter( "handle_bulk_actions-edit-{$post_type}", 'handle_post_bulk_actions', 10, 3 );
}
$this->filter( 'post_row_actions', 'post_row_actions', 10, 2 );
$this->filter( 'page_row_actions', 'post_row_actions', 10, 2 );
$this->filter( 'admin_init', 'handle_post_row_actions' );
$this->action( 'wp', 'serve_api_key' );
$this->action( 'rest_api_init', 'init_rest_api' );
}
/**
* Load the REST API endpoints.
*/
public function init_rest_api() {
$rest = new Rest();
$rest->register_routes();
}
/**
* Add bulk actions for applicable posts, pages, CPTs.
*
* @param array $actions Actions.
* @return array New actions.
*/
public function post_bulk_actions( $actions ) {
$actions['rank_math_indexnow'] = esc_html__( 'Instant Indexing: Submit Pages', 'rank-math' );
return $actions;
}
/**
* Action links for the post listing screens.
*
* @param array $actions Action links.
* @param object $post Current post object.
* @return array
*/
public function post_row_actions( $actions, $post ) {
if ( ! Helper::has_cap( 'general' ) ) {
return $actions;
}
if ( 'publish' !== $post->post_status ) {
return $actions;
}
$post_types = $this->get_auto_submit_post_types();
if ( ! in_array( $post->post_type, $post_types, true ) ) {
return $actions;
}
$link = wp_nonce_url(
add_query_arg(
[
'action' => 'rank_math_instant_index_post',
'index_post_id' => $post->ID,
'method' => 'bing_submit',
]
),
'rank_math_instant_index_post'
);
$actions['indexnow_submit'] = '<a href="' . esc_url( $link ) . '" class="rm-instant-indexing-action rm-indexnow-submit">' . __( 'Instant Indexing: Submit Page', 'rank-math' ) . '</a>';
return $actions;
}
/**
* Handle post row action link actions.
*
* @return void
*/
public function handle_post_row_actions() {
if ( 'rank_math_instant_index_post' !== Param::get( 'action' ) ) {
return;
}
$post_id = absint( Param::get( 'index_post_id' ) );
if ( ! $post_id ) {
return;
}
if ( ! wp_verify_nonce( Param::get( '_wpnonce' ), 'rank_math_instant_index_post' ) ) {
return;
}
if ( ! Helper::has_cap( 'general' ) ) {
return;
}
$this->api_submit( get_permalink( $post_id ), true );
Helper::redirect( remove_query_arg( [ 'action', 'index_post_id', 'method', '_wpnonce' ] ) );
exit;
}
/**
* Handle bulk actions for applicable posts, pages, CPTs.
*
* @param string $redirect Redirect URL.
* @param string $doaction Performed action.
* @param array $object_ids Post IDs.
*
* @return string New redirect URL.
*/
public function handle_post_bulk_actions( $redirect, $doaction, $object_ids ) {
if ( 'rank_math_indexnow' !== $doaction || empty( $object_ids ) ) {
return $redirect;
}
if ( ! Helper::has_cap( 'general' ) ) {
return $redirect;
}
$urls = [];
foreach ( $object_ids as $object_id ) {
$urls[] = get_permalink( $object_id );
}
$this->api_submit( $urls, true );
return $redirect;
}
/**
* Register admin page.
*/
public function register_admin_page() {
$tabs = [
'url-submission' => [
'icon' => 'rm-icon rm-icon-instant-indexing',
'title' => esc_html__( 'Submit URLs', 'rank-math' ),
'desc' => esc_html__( 'Send URLs directly to the IndexNow API.', 'rank-math' ) . ' <a href="' . KB::get( 'instant-indexing', 'Indexing Submit URLs' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>',
'classes' => 'rank-math-advanced-option',
'file' => dirname( __FILE__ ) . '/views/console.php',
],
'settings' => [
'icon' => 'rm-icon rm-icon-settings',
'title' => esc_html__( 'Settings', 'rank-math' ),
/* translators: Link to kb article */
'desc' => sprintf( esc_html__( 'Instant Indexing module settings. %s.', 'rank-math' ), '<a href="' . KB::get( 'instant-indexing', 'Indexing Settings' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
'file' => dirname( __FILE__ ) . '/views/options.php',
],
'history' => [
'icon' => 'rm-icon rm-icon-htaccess',
'title' => esc_html__( 'History', 'rank-math' ),
'desc' => esc_html__( 'The last 100 IndexNow API requests.', 'rank-math' ),
'classes' => 'rank-math-advanced-option',
'file' => dirname( __FILE__ ) . '/views/history.php',
],
];
if ( 'easy' === Helper::get_settings( 'general.setup_mode', 'advanced' ) ) {
// Move ['settings'] to the top.
$tabs = [ 'settings' => $tabs['settings'] ] + $tabs;
}
/**
* Allow developers to add new sections in the IndexNow settings.
*
* @param array $tabs
*/
$tabs = $this->do_filter( 'settings/instant_indexing', $tabs );
new Options(
[
'key' => 'rank-math-options-instant-indexing',
'title' => esc_html__( 'Instant Indexing', 'rank-math' ),
'menu_title' => esc_html__( 'Instant Indexing', 'rank-math' ),
'capability' => 'rank_math_general',
'tabs' => $tabs,
'position' => 100,
]
);
}
/**
* Store previous post status & permalink before saving the post.
*
* @param array $data Post data.
* @param array $postarr Raw post data.
* @param array $unsanitized_postarr Unsanitized post data.
* @param bool $update Whether this is an existing post being updated or not.
*/
public function before_save_post( $data, $postarr, $unsanitized_postarr, $update = false ) {
if ( ! $update ) {
return $data;
}
$this->previous_post_status[ $postarr['ID'] ] = get_post_status( $postarr['ID'] );
$this->previous_post_permalinks[ $postarr['ID'] ] = str_replace( '__trashed', '', get_permalink( $postarr['ID'] ) );
return $data;
}
/**
* When a post from a watched post type is published or updated, submit its URL
* to the API and add notice about it.
*
* @param int $post_id Post ID.
* @param object $post Post object.
*
* @return void
*/
public function save_post( $post_id, $post ) {
// Check if already submitted.
if ( in_array( $post_id, $this->submitted, true ) ) {
return;
}
// Check if post status changed to publish or trash.
if ( ! in_array( $post->post_status, [ 'publish', 'trash' ], true ) ) {
return;
}
// If new status is trash, check if previous status was publish.
if ( 'trash' === $post->post_status && 'publish' !== $this->previous_post_status[ $post_id ] ) {
return;
}
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
return;
}
if ( ! Helper::is_post_indexable( $post_id ) ) {
return;
}
// Check if it's a hidden product.
if ( 'product' === $post->post_type && Helper::is_woocommerce_active() ) {
$product = wc_get_product( $post_id );
if ( $product && ! $product->is_visible() ) {
return;
}
}
$url = get_permalink( $post );
if ( 'trash' === $post->post_status ) {
$url = $this->previous_post_permalinks[ $post_id ];
}
/**
* Filter the URL to be submitted to IndexNow.
* Returning false will prevent the URL from being submitted.
*
* @param string $url URL to be submitted.
* @param WP_POST $post Post object.
*/
$send_url = $this->do_filter( 'instant_indexing/publish_url', $url, $post );
// Early exit if filter is set to false.
if ( ! $send_url ) {
return;
}
$this->api_submit( $send_url, false );
$this->submitted[] = $post_id;
}
/**
* Is module configured.
*
* @return boolean
*/
private function is_configured() {
return (bool) Helper::get_settings( 'instant_indexing.indexnow_api_key' );
}
/**
* Enqueue CSS & JS.
*
* @param string $hook Page hook name.
* @return void
*/
public function enqueue( $hook ) {
if ( 'rank-math_page_rank-math-options-instant-indexing' !== $hook && 'rank-math_page_instant-indexing' !== $hook ) {
return;
}
$uri = untrailingslashit( plugin_dir_url( __FILE__ ) );
wp_enqueue_script( 'rank-math-instant-indexing', $uri . '/assets/js/instant-indexing.js', [ 'jquery' ], rank_math()->version, true );
Helper::add_json(
'indexNow',
[
'restUrl' => rest_url( \RankMath\Rest\Rest_Helper::BASE . '/in' ),
'refreshHistoryInterval' => 30000,
'i18n' => [
'submitError' => esc_html__( 'An error occurred while submitting the URL.', 'rank-math' ),
'clearHistoryError' => esc_html__( 'Error: could not clear history.', 'rank-math' ),
'getHistoryError' => esc_html__( 'Error: could not get history.', 'rank-math' ),
'noHistory' => esc_html__( 'No submissions yet.', 'rank-math' ),
],
]
);
}
/**
* Serve API key for search engines.
*/
public function serve_api_key() {
global $wp;
$api = Api::get();
$key = $api->get_key();
$key_location = $api->get_key_location( 'serve_api_key' );
$current_url = home_url( $wp->request );
if ( isset( $current_url ) && $key_location === $current_url ) {
header( 'Content-Type: text/plain' );
header( 'X-Robots-Tag: noindex' );
status_header( 200 );
echo esc_html( $key );
exit();
}
}
/**
* Submit URL to IndexNow API.
*
* @param string $url URL to be submitted.
* @param bool $is_manual_submission Whether the URL is submitted manually by the user.
*
* @return bool
*/
private function api_submit( $url, $is_manual_submission ) {
$api = Api::get();
/**
* Filter the URL to be submitted to IndexNow.
* Returning false will prevent the URL from being submitted.
*
* @param bool $is_manual_submission Whether the URL is submitted manually by the user.
*/
$url = $this->do_filter( 'instant_indexing/submit_url', $url, $is_manual_submission );
if ( ! $url ) {
return false;
}
$api_logs = $api->get_log();
if ( ! $is_manual_submission && ! empty( $api_logs ) ) {
$logs = array_values( array_reverse( $api_logs ) );
if ( ! empty( $logs[0] ) && $logs[0]['url'] === $url && time() - $logs[0]['time'] < self::THROTTLE_LIMIT ) {
return false;
}
}
$submitted = $api->submit( $url, $is_manual_submission );
if ( ! $is_manual_submission ) {
return $submitted;
}
$count = is_array( $url ) ? count( $url ) : 1;
$this->add_submit_message_notice( $submitted, $count );
return $submitted;
}
/**
* Add notice after submitting one or more URLs.
*
* @param bool $success Whether the submission was successful.
* @param int $count Number of submitted URLs.
*
* @return void
*/
private function add_submit_message_notice( $success, $count ) {
$notification_type = 'error';
$notification_message = __( 'Error submitting page to IndexNow.', 'rank-math' );
if ( $success ) {
$notification_type = 'success';
$notification_message = sprintf(
/* translators: %s: Number of pages submitted. */
_n( '%s page submitted to IndexNow.', '%s pages submitted to IndexNow.', $count, 'rank-math' ),
$count
);
}
Helper::add_notification( $notification_message, [ 'type' => $notification_type ] );
}
/**
* Get post types where auto-submit is enabled.
*
* @return array
*/
private function get_auto_submit_post_types() {
$post_types = Helper::get_settings( 'instant_indexing.bing_post_types', [] );
return $post_types;
}
}

View File

@@ -0,0 +1,215 @@
<?php
/**
* The Global functionality of the plugin.
*
* Defines the functionality loaded on admin.
*
* @since 1.0.49
* @package RankMath
* @subpackage RankMath\Rest
* @author Rank Math <support@rankmath.com>
*/
namespace RankMath\Instant_Indexing;
use RankMath\Helper;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Controller;
use WP_REST_Response;
use RankMath\Helpers\Arr;
defined( 'ABSPATH' ) || exit;
/**
* Rest class.
*/
class Rest extends WP_REST_Controller {
/**
* Constructor.
*/
public function __construct() {
$this->namespace = \RankMath\Rest\Rest_Helper::BASE . '/in';
}
/**
* Register REST routes.
*
* @return void
*/
public function register_routes() {
$namespace = $this->namespace;
$endpoint = '/submitUrls/';
register_rest_route(
$namespace,
$endpoint,
[
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'submit_urls' ],
'permission_callback' => [ $this, 'has_permission' ],
],
]
);
$endpoint = '/getLog/';
register_rest_route(
$namespace,
$endpoint,
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_log' ],
'permission_callback' => [ $this, 'has_permission' ],
],
]
);
$endpoint = '/clearLog/';
register_rest_route(
$namespace,
$endpoint,
[
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'clear_log' ],
'permission_callback' => [ $this, 'has_permission' ],
],
]
);
$endpoint = '/resetKey/';
register_rest_route(
$namespace,
$endpoint,
[
[
'methods' => WP_REST_Server::EDITABLE,
'callback' => [ $this, 'reset_key' ],
'permission_callback' => [ $this, 'has_permission' ],
],
]
);
}
/**
* Submit URLs.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error
*/
public function submit_urls( WP_REST_Request $request ) {
$urls = $request->get_param( 'urls' );
if ( empty( $urls ) ) {
return new WP_Error( 'empty_urls', __( 'No URLs provided.', 'rank-math' ) );
}
$urls = Arr::from_string( $urls, "\n" );
$urls = array_values( array_unique( array_filter( $urls, 'wp_http_validate_url' ) ) );
if ( ! $urls ) {
return new WP_Error( 'invalid_urls', __( 'Invalid URLs provided.', 'rank-math' ) );
}
$result = Api::get()->submit( $urls );
if ( ! $result ) {
return new WP_Error( 'submit_failed', __( 'Failed to submit URLs. See details in the History tab.', 'rank-math' ) );
}
$urls_number = count( $urls );
return new WP_REST_Response(
[
'success' => true,
'message' => sprintf(
// Translators: %s is the number of URLs submitted.
_n(
'Successfully submitted %s URL.',
'Successfully submitted %s URLs.',
$urls_number,
'rank-math'
),
$urls_number
),
]
);
}
/**
* Get log.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error
*/
public function get_log( WP_REST_Request $request ) {
$filter = $request->get_param( 'filter' );
$result = Api::get()->get_log();
$total = count( $result );
foreach ( $result as $key => $value ) {
$result[ $key ]['timeFormatted'] = wp_date( 'Y-m-d H:i:s', $value['time'] );
// Translators: placeholder is human-readable time, e.g. "1 hour".
$result[ $key ]['timeHumanReadable'] = sprintf( __( '%s ago', 'rank-math' ), human_time_diff( $value['time'] ) );
if ( 'manual' === $filter && empty( $result[ $key ]['manual_submission'] ) ) {
unset( $result[ $key ] );
} elseif ( 'auto' === $filter && ! empty( $result[ $key ]['manual_submission'] ) ) {
unset( $result[ $key ] );
}
}
$result = array_values( array_reverse( $result ) );
return new WP_REST_Response(
[
'data' => $result,
'total' => $total,
]
);
}
/**
* Clear log.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error
*/
public function clear_log( WP_REST_Request $request ) {
Api::get()->clear_log();
return new WP_REST_Response( [ 'status' => 'ok' ] );
}
/**
* Reset key.
*
* @param WP_REST_Request $request Full details about the request.
*
* @return WP_REST_Response|WP_Error
*/
public function reset_key( WP_REST_Request $request ) {
$api = Api::get();
$api->reset_key();
$key = $api->get_key();
$location = $api->get_key_location( 'reset_key' );
return new WP_REST_Response(
[
'status' => 'ok',
'key' => $key,
'location' => $location,
]
);
}
/**
* Determine if the current user can manage instant indexing.
*
* @return bool
*/
public function has_permission() {
return Helper::has_cap( 'general' );
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* IndexNow Options: Console tab.
*
* @since 1.0.56
* @package Rank_Math
*/
defined( 'ABSPATH' ) || exit;
$cmb->add_field(
[
'id' => 'indexnow_description',
'type' => 'raw',
'content' => '<div class="bing-api-description description"><p>' . esc_html__( 'Insert URLs to send to the IndexNow API (one per line, up to 10,000):', 'rank-math' ) . '</p></div>',
]
);
$cmb->add_field(
[
'id' => 'indexnow_urls',
'type' => 'textarea_small',
'sanitization_cb' => '__return_false',
'attributes' => [
'class' => 'instant-indexing-urls',
'placeholder' => trailingslashit( home_url() ) . _x( 'hello-world', 'URL slug placeholder', 'rank-math' ),
],
'after_field' => '<a href="#" id="indexnow_submit" class="button button-primary large-button" style="margin-top: 20px;">' . esc_html__( 'Submit URLs', 'rank-math' ) . '</a> <span class="spinner" id="indexnow_spinner"></span>',
]
);

View File

@@ -0,0 +1,47 @@
<?php
/**
* IndexNow Options: History tab.
*
* @since 1.0.56
* @package Rank_Math
*/
defined( 'ABSPATH' ) || exit;
$history_content = '';
$history_content .= '<a href="#" id="indexnow_clear_history" class="button alignright hidden">' . esc_html__( 'Clear History', 'rank-math' ) . '</a>';
$history_content .= '<div class="history-filter-links hidden" id="indexnow_history_filters"><a href="#" data-filter="all" class="current">' . esc_html__( 'All', 'rank-math' ) . '</a> | <a href="#" data-filter="manual">' . esc_html__( 'Manual', 'rank-math' ) . '</a> | <a href="#" data-filter="auto">' . esc_html__( 'Auto', 'rank-math' ) . '</a></div>';
$history_content .= '<div class="clear"></div>';
$history_content .= '<table class="wp-list-table widefat striped" id="indexnow_history"><thead><tr><th class="col-date">' . esc_html__( 'Time', 'rank-math' ) . '</th><th class="col-url">' . esc_html__( 'URL', 'rank-math' ) . '</th><th class="col-status">' . esc_html__( 'Response', 'rank-math' ) . '</th></tr></thead><tbody>';
$history_content .= '</tbody></table>';
$cmb->add_field(
[
'id' => 'indexnow_history',
'type' => 'raw',
/* translators: daily quota */
'content' => $history_content,
]
);
$help_contents = '';
$help_contents .= '<a href="#" id="indexnow_show_response_codes">' . esc_html__( 'Response Code Help', 'rank-math' ) . '<span class="dashicons dashicons-arrow-down"></span></a>';
$help_contents .= '<table class="wp-list-table widefat striped hidden" id="indexnow_response_codes"><thead><tr><th class="col-response-code">' . esc_html__( 'Response Code', 'rank-math' ) . '</th><th class="col-response-message">' . esc_html__( 'Response Message', 'rank-math' ) . '</th><th class="col-reasons">' . esc_html__( 'Reasons', 'rank-math' ) . '</th></tr></thead><tbody>';
$help_contents .= '<tr><td class="col-response-code">200</td><td class="col-response-message">' . esc_html__( 'OK', 'rank-math' ) . '</td><td class="col-reasons">' . esc_html__( 'The URL was successfully submitted to the IndexNow API.', 'rank-math' ) . '</td></tr>';
$help_contents .= '<tr><td class="col-response-code">202</td><td class="col-response-message">' . esc_html__( 'Accepted', 'rank-math' ) . '</td><td class="col-reasons">' . esc_html__( 'The URL was successfully submitted to the IndexNow API, but the API key will be checked later.', 'rank-math' ) . '</td></tr>';
$help_contents .= '<tr><td class="col-response-code">400</td><td class="col-response-message">' . esc_html__( 'Bad Request', 'rank-math' ) . '</td><td class="col-reasons">' . esc_html__( 'The request was invalid.', 'rank-math' ) . '</td></tr>';
$help_contents .= '<tr><td class="col-response-code">403</td><td class="col-response-message">' . esc_html__( 'Forbidden', 'rank-math' ) . '</td><td class="col-reasons">' . esc_html__( 'The key was invalid (e.g. key not found, file found but key not in the file).', 'rank-math' ) . '</td></tr>';
$help_contents .= '<tr><td class="col-response-code">422</td><td class="col-response-message">' . esc_html__( 'Unprocessable Entity', 'rank-math' ) . '</td><td class="col-reasons">' . esc_html__( 'The URLs don\'t belong to the host or the key is not matching the schema in the protocol.', 'rank-math' ) . '</td></tr>';
$help_contents .= '<tr><td class="col-response-code">429</td><td class="col-response-message">' . esc_html__( 'Too Many Requests', 'rank-math' ) . '</td><td class="col-reasons">' . esc_html__( 'Too Many Requests (potential Spam).', 'rank-math' ) . '</td></tr>';
$help_contents .= '</tbody></table>';
$cmb->add_field(
[
'id' => 'indexnow_help',
'type' => 'raw',
/* translators: daily quota */
'content' => $help_contents,
]
);

View File

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

View File

@@ -0,0 +1,64 @@
<?php
/**
* IndexNow Settings.
*
* @since 1.0.56
* @package RankMath
* @subpackage RankMath\Settings
*/
namespace RankMath\Instant_Indexing;
use RankMath\Helper;
defined( 'ABSPATH' ) || exit;
$cmb->add_field(
[
'id' => 'bing_post_types',
'type' => 'multicheck',
'name' => esc_html__( 'Auto-Submit Post Types', 'rank-math' ),
'desc' => esc_html__( 'Submit posts from these post types automatically to the IndexNow API when a post is published, updated, or trashed.', 'rank-math' ),
'options' => Helper::choices_post_types(),
]
);
$cmb->add_field(
[
'id' => 'indexnow_api_key',
'name' => esc_html__( 'API Key', 'rank-math' ),
'desc' => esc_html__( 'The IndexNow API key proves the ownership of the site. It is generated automatically. You can change the key if it becomes known to third parties.', 'rank-math' ),
'type' => 'text',
'after_field' => '<a href="#" id="indexnow_reset_key" class="button button-secondary large-button"><span class="dashicons dashicons-update"></span> ' . esc_html__( 'Change Key', 'rank-math' ) . '</a>',
'classes' => 'rank-math-advanced-option',
'attributes' => [
'readonly' => 'readonly',
],
]
);
$key_location = Api::get()->get_key_location( 'settings_field' );
$field_label = esc_html__( 'API Key Location', 'rank-math' );
$check_key_label = esc_html__( 'Check Key', 'rank-math' );
// Translators: %s is the words "Check Key".
$field_desc = sprintf( esc_html__( 'Use the %1$s button to verify that the key is accessible for search engines. Clicking on it should open the key file in your browser and show the API key.', 'rank-math' ), '<strong>' . $check_key_label . '</strong>' );
$location_field = '<div class="cmb-row cmb-type-text cmb2-id-indexnow-api-key-location table-layout rank-math-advanced-option" data-fieldtype="text">
<div class="cmb-th">
<label for="indexnow_api_key_location">' . $field_label . '</label>
</div>
<div class="cmb-td">
<code id="indexnow_api_key_location">' . esc_url( $key_location ) . '</code>
<p class="cmb2-metabox-description">' . $field_desc . '</p>
<a href="' . esc_url( $key_location ) . '" id="indexnow_check_key" class="button button-secondary large-button" target="_blank"><span class="dashicons dashicons-search"></span> ' . $check_key_label . '</a>
</div>
</div>';
$cmb->add_field(
[
'id' => 'indexnow_api_key_location',
'type' => 'raw',
'content' => $location_field,
]
);