PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.14.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.14.0
2.14.0 2.13.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 All 55 releases
← All changes | includes/api/class-seo-score-endpoint.php +24 -47 2.13.0 → 2.14.0 View file →
@@ -286,41 +286,35 @@
286 286 $metadata,
287 287 $score_options
288 288 );
289 289
290 - // Add readability_score and content_quality from frontend if
291 - // provided. `!== null`, not `!empty()`: 0 is a legitimate score and
292 - // empty() discarded it, so a post the editor scored as 0 kept
293 - // whatever the calculator had produced instead (#394). Both params
294 - // already default to null above, so null means "not sent".
290 + // The browser's own readability_score and content_quality are no
291 + // longer applied. They used to be written over the labels this
292 + // request had just computed, and then persisted, so the saved
293 + // Readability and Content Quality described the editor text alone
294 + // (#829).
295 295 //
296 - // Only when the editor actually measured something, though. Inside a
297 - // page builder there is no editor content to read, so Refresh sent an
298 - // empty `live_content` along with the two labels derived from that
299 - // empty string — the literal words "No content" — and they were
300 - // applied over the correct server-side analysis this request had just
301 - // run, then persisted by save_score(). That is what put "No content"
302 - // on the dashboard for a page with a valid score (#778). With nothing
303 - // measured, the analysis above is the better answer.
296 + // That is wrong whenever the two see different content, which is
297 + // exactly when it matters: `analyze_live_content()` resolves what
298 + // the editor sent AND whatever `thinkrank_analyzable_content`
299 + // contributes on top, so a post with 2 words in the editor and 615
300 + // added by a filter scored 617 words server-side and saved
301 + // "Too short" / "Needs improvement" from the browser's 2.
304 302 //
305 - // Non-empty `live_content` is not on its own proof that the editor
306 - // measured anything: builder markup (Divi 5) is markup the editor
307 - // has plenty of and can read no words from, so it sent that same
308 - // "No content" pair alongside 450 characters of block comments.
309 - // Treat the sentinel itself as "nothing measured" whenever this
310 - // request's own analysis did find words, so a stale bundle cannot
311 - // overwrite a valid analysis either.
312 - $editor_measured = '' !== trim((string) $live_content);
313 - $server_found_content = ($content_data['word_count'] ?? 0) > 0;
303 + // Nothing is lost by ignoring them: when `live_content` is non-empty
304 + // the server analysed the very text the editor measured, so its
305 + // labels cover the live case too. The parameters stay accepted so an
306 + // older cached bundle still gets a successful response, and they
307 + // stay documented in the route args; they simply no longer win.
308 + //
309 + // The panel keeps computing them in the browser for instant feedback
310 + // between calculations. What it must not do is persist them.
311 + unset($readability_score, $content_quality);
314 312
315 - if ($editor_measured && null !== $readability_score
316 - && !($server_found_content && self::is_no_content_label($readability_score))) {
317 - $score_data['readability_score'] = $readability_score;
318 - }
319 - if ($editor_measured && null !== $content_quality
320 - && !($server_found_content && self::is_no_content_label($content_quality))) {
321 - $score_data['content_quality'] = $content_quality;
322 - }
313 + // The resolved word count, so the panel can show the number this
314 + // score was actually calculated from rather than its own count of
315 + // the editor text (#829).
316 + $score_data['word_count'] = (int) ($content_data['word_count'] ?? 0);
323 317
324 318 // Save score if requested
325 319 if ($save_score) {
326 320 $user_id = get_current_user_id();
@@ -342,25 +336,8 @@
342 336 'Failed to calculate SEO score: ' . $e->getMessage(),
343 337 ['status' => 500]
344 338 );
345 339 }
346 - }
347 -
348 - /**
349 - * Whether an editor-supplied label means "I could not read the content".
350 - *
351 - * `calculateReadabilityScore()` and `calculateContentQuality()` both return
352 - * this exact untranslated string when handed an empty body, so it is the
353 - * editor saying it measured nothing rather than a measurement in its own
354 - * right. Every real label carries a level or a grade.
355 - *
356 - * @since 2.12.0
357 - *
358 - * @param mixed $label Label sent by the editor.
359 - * @return bool True when the label is the empty-content sentinel.
360 - */
361 - private static function is_no_content_label($label): bool {
362 - return is_string($label) && 'no content' === strtolower(trim($label));
363 340 }
364 341
365 342 /**
366 343 * Get existing SEO score for a post