PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.9.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.9.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-llms-txt-manager.php +25 -6 2.2.0 → 2.9.0 View file →
@@ -750,8 +750,28 @@
750 750 return is_string($content) ? $content : '';
751 751 }
752 752
753 753 /**
754 + * Whether /llms.txt is currently being served, in either delivery mode.
755 + *
756 + * `static` publishes a file at ABSPATH; `dynamic` keeps the document in
757 + * an option and answers from serve_llms_txt(). Callers that only need
758 + * this yes/no must use it in preference to get_llms_txt_status(), which
759 + * resolves the delivery mode, may fire a loopback delivery probe, asks
760 + * the filesystem API whether ABSPATH is writable, reads the document and
761 + * writes a transient — far too much work for a boolean, and not
762 + * something a dashboard summary should be triggering.
763 + *
764 + * @since 2.2.1
765 + *
766 + * @return bool
767 + */
768 + public function is_published(): bool {
769 + return file_exists(ABSPATH . 'llms.txt')
770 + || '' !== trim($this->get_published_content());
771 + }
772 +
773 + /**
754 774 * Ask the common page/CDN cache layers to drop their copy of /llms.txt.
755 775 *
756 776 * A cached response outlives a republish, so without this a mode switch or
757 777 * a content change keeps serving the old document (and, on the static path,
@@ -1174,9 +1194,9 @@
1174 1194 $status = [
1175 1195 'file_exists' => file_exists($llms_file),
1176 1196 // Whether /llms.txt is actually being served, either mode. Prefer
1177 1197 // this over file_exists, which is only meaningful in static mode.
1178 - 'published' => file_exists($llms_file) || '' !== trim($stored),
1198 + 'published' => $this->is_published(),
1179 1199 'delivery_mode' => $mode,
1180 1200 'file_path' => 'dynamic' === $mode ? '' : $llms_file,
1181 1201 'file_url' => home_url('/llms.txt'),
1182 1202 'writable' => $this->is_directory_writable(dirname($llms_file)),
@@ -1212,12 +1232,11 @@
1212 1232 }
1213 1233
1214 1234 if (null !== $content) {
1215 1235 // Get content preview (first 200 characters) with size safety
1216 - $status['content_preview'] = substr($content, 0, 200);
1217 - if (strlen($content) > 200) {
1218 - $status['content_preview'] .= '...';
1219 - }
1236 + // substr()/strlen() count BYTES, so this cut a multibyte character
1237 + // in half and shipped an invalid UTF-8 sequence in the preview (#687).
1238 + $status['content_preview'] = \ThinkRank\Core\Seo_Text::trim_to_length($content, 200);
1220 1239 }
1221 1240
1222 1241 // Cache the result for 5 minutes to improve performance
1223 1242 set_transient($cache_key, $status, 5 * MINUTE_IN_SECONDS);
@@ -2192,9 +2211,9 @@
2192 2211 $content .= "- [Technical Stack]({$website_url}): Built with {$stack}\n";
2193 2212 }
2194 2213
2195 2214 if (!empty($user_input['development_approach'])) {
2196 - $approach_summary = wp_trim_words($user_input['development_approach'], 10);
2215 + $approach_summary = \ThinkRank\Core\Seo_Text::trim_words($user_input['development_approach'], 10);
2197 2216 $content .= "- [Development Guidelines]({$website_url}): {$approach_summary}\n";
2198 2217 }
2199 2218
2200 2219 // Add robots.txt reference