Skip to content
37 changes: 29 additions & 8 deletions inc/namespace.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,16 @@ function maybe_ping_indexnow( $new_status, $old_status, $post ): void {
return;
}

/*
* Skip for noindexed posts that have never pinged IndexNow.
*
* Previously pinged URLs are still pinged to encourage removal from
* search engines.
*/
if ( SEOCompat\is_noindex( $post ) && empty( get_post_ping_urls( $post ) ) ) {
return;
}

/*
* Prevent double pings for block editor legacy meta boxes.
*/
Expand Down Expand Up @@ -325,15 +335,16 @@ function ping_indexnow( $post ) {
$current_url = get_permalink( $post );

/*
* Only add the current URL if it is publicly viewable.
* Only add the current URL if it is publicly viewable and indexed.
*
* This prevents unnecessary pings for private or draft posts in
* which the current URL will 404. If the URL has been previously
* pinged, it will be included in the list of URLs to ping as IndexNow
* allows for new 404s to be pinged to encourage search engines
* to remove the URL from their index.
* This prevents unnecessary pings for new URLs that are either not
* viewable (ie, will 404) or noindexed by an SEO plugin.
*
* If the URL has been previously sent to IndexNow it will still be
* pinged to encourage search engines to de-index the page from their
* search engine, either because it's a 404 or should not be listed.
*/
if ( is_post_publicly_viewable( $post ) && ! in_array( $current_url, $url_list, true ) ) {
if ( is_post_publicly_viewable( $post ) && ! SEOCompat\is_noindex( $post ) && ! in_array( $current_url, $url_list, true ) ) {
$url_list[] = get_permalink( $post );
}

Expand Down Expand Up @@ -442,7 +453,17 @@ function async_ping_indexnow( $post ) {

$post_id = $post->ID;

/**
* Filter the delay (in seconds) before the asynchronous ping runs.
*
* @param int $delay The delay in seconds. Default is 10 seconds.
*/
$delay = apply_filters( 'simple_search_submission_async_wait', 10, $post );

// Revert delay to default if it isn't numeric.
$delay = is_numeric( $delay ) ? (int) $delay : 10;

if ( ! wp_next_scheduled( 'simple_search_submission_async_ping', array( $post_id ) ) ) {
wp_schedule_single_event( time() + 5, 'simple_search_submission_async_ping', array( $post_id ) );
wp_schedule_single_event( time() + $delay, 'simple_search_submission_async_ping', array( $post_id ) );
}
}
88 changes: 88 additions & 0 deletions inc/seo-compat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
/**
* Simple Search Submission for IndexNow
*
* @package SimpleSearchSubmission
*/

namespace PWCC\SimpleSearchSubmission\SEOCompat;

/**
* Determine if a post is set to noindex by an SEO plugin.
*
* @param \WP_Post|int $post The post object or ID.
* @return bool True if the post is set to noindex, false otherwise.
*/
function is_noindex( $post ) {
$post = get_post( $post );
if ( ! $post ) {
return true; // No post found, treat as noindex.
}

/*
* Check in order of number of active installs.
*
* To optimize performance for the majority of users, the
* checks are ordered by the popularity of the SEO plugins.
*
* Popularity data from the WordPress plugin repository.
*/

// Check for Yoast SEO noindex (10 million+).
if ( is_yoast_noindex( $post ) ) {
return true;
}

// Check All in One SEO noindex (3 million+).
if ( is_aioseo_noindex( $post ) ) {
return true;
}

return false; // Default to not noindex.
}

/**
* Check Yoast SEO noindex status.
*
* @param \WP_Post|int $post The post object or ID.
* @return bool True if Yoast SEO sets the post to noindex, false otherwise.
*/
function is_yoast_noindex( $post ) {
if ( ! function_exists( 'YoastSEO' ) ) {
return false; // Yoast SEO is not active.
}

$post = get_post( $post );
$post_id = $post->ID;

$robots = YoastSEO()->meta->for_post( $post_id )->robots;

if ( ! isset( $robots['index'] ) ) {
return false; // No index directive found.
}

return 'noindex' === $robots['index'];
}

/**
* Check All in One SEO noindex status.
*
* @param \WP_Post|int $post The post object or ID.
* @return bool True if AIOSEO sets the post to noindex, false otherwise.
*/
function is_aioseo_noindex( $post ) {
if ( ! function_exists( 'aioseo' ) ) {
return false; // AIOSEO is not active.
}

$post = get_post( $post );
$post_id = $post->ID;

$post_meta = aioseo()->meta->metaData->getMetaData( $post_id );

if ( ! $post_meta->robots_default && isset( $post_meta->robots_noindex ) ) {
return $post_meta->robots_noindex;
}

return aioseo()->helpers->isPostTypeNoindexed( get_post_type( $post ) );
}
1 change: 1 addition & 0 deletions simple-search-submission.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
namespace PWCC\SimpleSearchSubmission;

require_once __DIR__ . '/inc/namespace.php';
require_once __DIR__ . '/inc/seo-compat.php';

// Run late to give themes and plugins a chance to set up asynchronous pings.
add_action( 'after_setup_theme', __NAMESPACE__ . '\\bootstrap', 20 );
Expand Down