PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.10.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.10.0
2.12.0 2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk All 53 releases
← All changes | includes/seo/class-sitemap-generator.php +107 -23 2.9.0 → 2.10.0 View file →
@@ -2162,16 +2162,20 @@
2162 2162 * auto_generate setting: the user deliberately changed inclusion rules and
2163 2163 * expects the served file to reflect them even if content-triggered
2164 2164 * auto-generation is turned off. Still respects the master `enabled` flag.
2165 2165 *
2166 - * @return void
2166 + * @since 2.10.0 Reports whether the served sitemap was actually rebuilt, so
2167 + * a caller can say so rather than assume it (#764). Existing
2168 + * callers that ignore the return are unaffected.
2169 + *
2170 + * @return bool True when the served sitemap now reflects the settings.
2167 2171 */
2168 - public function regenerate_sitemap_from_settings(): void {
2172 + public function regenerate_sitemap_from_settings(): bool {
2169 2173 if (!$this->acquire_generation_lock()) {
2170 2174 // A manual generation (or another request's takeover) is already
2171 2175 // writing the files; the pending marker survives so this rebuild is
2172 2176 // retried rather than lost.
2173 - return;
2177 + return false;
2174 2178 }
2175 2179
2176 2180 try {
2177 2181 $settings = $this->get_settings('site');
@@ -2178,30 +2182,56 @@
2178 2182 if (empty($settings['enabled'])) {
2179 2183 // The sitemap was disabled: remove the previously generated static
2180 2184 // files so the web server stops serving a stale sitemap that
2181 2185 // crawlers would otherwise keep fetching.
2182 - $this->delete_published_sitemaps();
2186 + //
2187 + // A file that could not be removed is still being served, so
2188 + // this is not a success. Reporting one here would tell a caller
2189 + // the sitemap was gone while the web server kept answering with
2190 + // it, which is the failure this return value exists to prevent
2191 + // (#764).
2192 + $removal = $this->delete_published_sitemaps($settings);
2193 + $stuck = is_array($removal['failed'] ?? null) ? $removal['failed'] : [];
2194 +
2195 + if (!empty($stuck)) {
2196 + $this->record_regeneration_failure(
2197 + $this->stuck_files_message($stuck, true),
2198 + 'settings'
2199 + );
2200 +
2201 + return false;
2202 + }
2203 +
2183 2204 $this->mark_regeneration_complete();
2184 - return;
2205 +
2206 + return true;
2185 2207 }
2186 2208
2187 2209 $revision = $this->current_regeneration_revision();
2188 2210
2189 2211 if ('dynamic' === $this->resolve_delivery_mode($settings)) {
2190 - $this->switch_to_dynamic_delivery($settings, $revision, 'settings');
2191 - return;
2212 + // Returns false when a static file is stuck in the web root:
2213 + // the server keeps serving that file in preference to WordPress,
2214 + // so the switch has not taken effect (#764).
2215 + return $this->switch_to_dynamic_delivery($settings, $revision, 'settings');
2192 2216 }
2193 2217
2194 2218 if ($this->generate_and_save($settings)) {
2195 2219 $this->mark_regeneration_complete($revision);
2196 - } else {
2197 - $this->record_regeneration_failure(
2198 - $this->write_failure_message(),
2199 - 'settings'
2200 - );
2220 +
2221 + return true;
2201 2222 }
2223 +
2224 + $this->record_regeneration_failure(
2225 + $this->write_failure_message(),
2226 + 'settings'
2227 + );
2228 +
2229 + return false;
2202 2230 } catch (\Throwable $e) {
2203 2231 $this->record_regeneration_failure($e->getMessage(), 'settings');
2232 +
2233 + return false;
2204 2234 } finally {
2205 2235 $this->release_generation_lock();
2206 2236 }
2207 2237 }
@@ -2206,8 +2236,27 @@
2206 2236 }
2207 2237 }
2208 2238
2209 2239 /**
2240 + * When a rebuild has been outstanding since, or 0 when none is.
2241 + *
2242 + * Lets a caller report an honest "saved, but the served file has not caught
2243 + * up yet" instead of a bare success (#764).
2244 + *
2245 + * @since 2.10.0
2246 + * @return int Unix timestamp, or 0 when nothing is pending.
2247 + */
2248 + public static function regeneration_pending_since(): int {
2249 + $pending = get_option(self::REGENERATION_PENDING_OPTION, []);
2250 +
2251 + if (!is_array($pending) || empty($pending['since'])) {
2252 + return 0;
2253 + }
2254 +
2255 + return (int) $pending['since'];
2256 + }
2257 +
2258 + /**
2210 2259 * Remove every static sitemap file ThinkRank publishes to the web root.
2211 2260 *
2212 2261 * Called when the sitemap feature is disabled, by the cleanup route, and by
2213 2262 * both removal paths, so /sitemap.xml, /sitemap_index.xml, the segmented
@@ -2444,9 +2493,9 @@
2444 2493 * @param int $revision Revision this rebuild is completing.
2445 2494 * @param string $source 'settings' or 'content', for the failure record.
2446 2495 * @return void
2447 2496 */
2448 - private function switch_to_dynamic_delivery(array $settings, int $revision, string $source): void {
2497 + private function switch_to_dynamic_delivery(array $settings, int $revision, string $source): bool {
2449 2498 $this->flush_dynamic_cache();
2450 2499
2451 2500 $removal = $this->delete_published_sitemaps($settings);
2452 2501 $stuck = is_array($removal['failed'] ?? null) ? $removal['failed'] : [];
@@ -2451,22 +2500,57 @@
2451 2500 $removal = $this->delete_published_sitemaps($settings);
2452 2501 $stuck = is_array($removal['failed'] ?? null) ? $removal['failed'] : [];
2453 2502
2454 2503 if (!empty($stuck)) {
2455 - $this->record_regeneration_failure(
2456 - sprintf(
2457 - /* translators: 1: comma-separated file names, 2: absolute path to the WordPress root. */
2458 - __('The sitemap is being served from WordPress, but these files are still in the site root and your web server will keep serving them instead: %1$s. They could not be removed because %2$s is not writable. Delete them, or ask your host to make the WordPress root writable.', 'thinkrank'),
2459 - implode(', ', $stuck),
2460 - untrailingslashit(ABSPATH)
2461 - ),
2462 - $source
2463 - );
2504 + $this->record_regeneration_failure($this->stuck_files_message($stuck), $source);
2464 2505
2465 - return;
2506 + return false;
2466 2507 }
2467 2508
2468 2509 $this->mark_regeneration_complete($revision);
2510 +
2511 + return true;
2512 + }
2513 +
2514 + /**
2515 + * Why a stale file left in the web root means the change has not landed.
2516 + *
2517 + * Shared by every path that removes published files, so they cannot
2518 + * describe the same situation differently (#764).
2519 + *
2520 + * The two situations that reach it differ in what WordPress is doing, and
2521 + * the message has to say which. After a switch to dynamic delivery
2522 + * WordPress IS serving the sitemap and the files shadow it. After the
2523 + * sitemap is switched off WordPress serves nothing, so the one message
2524 + * used to tell a site owner who had just disabled the sitemap that it was
2525 + * "being served from WordPress", which is the opposite of what they did.
2526 + *
2527 + * @since 2.10.0
2528 + * @since 2.10.0 Public, so the REST endpoint uses it rather than a copy;
2529 + * takes $sitemap_disabled for the disabled path.
2530 + *
2531 + * @param string[] $stuck Basenames that could not be removed.
2532 + * @param bool $sitemap_disabled True when the files outlived disabling
2533 + * the sitemap rather than a switch to
2534 + * dynamic delivery.
2535 + * @return string
2536 + */
2537 + public function stuck_files_message(array $stuck, bool $sitemap_disabled = false): string {
2538 + if ($sitemap_disabled) {
2539 + return sprintf(
2540 + /* translators: 1: comma-separated file names, 2: absolute path to the WordPress root. */
2541 + __('The sitemap is disabled, but these files are still in the site root and your web server is still serving them: %1$s. They could not be removed because %2$s is not writable. Delete them, or ask your host to make the WordPress root writable.', 'thinkrank'),
2542 + implode(', ', $stuck),
2543 + untrailingslashit(ABSPATH)
2544 + );
2545 + }
2546 +
2547 + return sprintf(
2548 + /* translators: 1: comma-separated file names, 2: absolute path to the WordPress root. */
2549 + __('The sitemap is being served from WordPress, but these files are still in the site root and your web server will keep serving them instead: %1$s. They could not be removed because %2$s is not writable. Delete them, or ask your host to make the WordPress root writable.', 'thinkrank'),
2550 + implode(', ', $stuck),
2551 + untrailingslashit(ABSPATH)
2552 + );
2469 2553 }
2470 2554
2471 2555 /**
2472 2556 * What to tell the site owner when publishing the files failed.