| @@ -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 |