← All changes
|
includes/seo/class-content-optimization-manager.php
+36
-19
2.6.0
→
2.10.0
View file →
| @@ -33,19 +33,28 @@ | ||
| 33 | 33 | |
| 34 | 34 | /** |
| 35 | 35 | * Content optimization scoring weights (2025 SEO standards) |
| 36 | 36 | * |
| 37 | + * Semantic relevance used to sit here at 5%, fed by a block that returned | |
| 38 | + * the same numbers for every input (#538). Removing a factor would have | |
| 39 | + * capped the score at 95, so the remaining six were rescaled by 100/95 and | |
| 40 | + * rounded to whole numbers, which preserves their former ratio | |
| 41 | + * (25:20:15:15:10:10) and keeps the array at 100. | |
| 42 | + * | |
| 43 | + * Rounding left technical_seo and user_experience, which were equal at 10, | |
| 44 | + * one point apart at 11 and 10. That is an artefact of landing the spare | |
| 45 | + * point somewhere, not a judgement that technical SEO matters more. | |
| 46 | + * | |
| 37 | 47 | * @since 1.0.0 |
| 38 | 48 | * @var array |
| 39 | 49 | */ |
| 40 | 50 | private array $optimization_weights = [ |
| 41 | - 'content_quality' => 25, // Content depth, uniqueness, value | |
| 42 | - 'keyword_optimization' => 20, // Keyword usage and distribution | |
| 43 | - 'readability' => 15, // Reading ease and comprehension | |
| 44 | - 'structure' => 15, // Headings, paragraphs, formatting | |
| 45 | - 'technical_seo' => 10, // Meta tags, URLs, schema | |
| 46 | - 'user_experience' => 10, // Engagement signals, CTR optimization | |
| 47 | - 'semantic_relevance' => 5 // Topic relevance and entity coverage | |
| 51 | + 'content_quality' => 26, // Content depth, uniqueness, value | |
| 52 | + 'keyword_optimization' => 21, // Keyword usage and distribution | |
| 53 | + 'readability' => 16, // Reading ease and comprehension | |
| 54 | + 'structure' => 16, // Headings, paragraphs, formatting | |
| 55 | + 'technical_seo' => 11, // Meta tags, URLs, schema | |
| 56 | + 'user_experience' => 10 // Engagement signals, CTR optimization | |
| 48 | 57 | ]; |
| 49 | 58 | |
| 50 | 59 | /** |
| 51 | 60 | * SEO content templates for different content types |
| @@ -712,13 +721,8 @@ | ||
| 712 | 721 | // User experience score (10% weight) |
| 713 | 722 | $ux_score = $this->calculate_user_experience_score($content_analysis, $template_compliance); |
| 714 | 723 | $scores['user_experience'] = $ux_score * ($this->optimization_weights['user_experience'] / 100); |
| 715 | 724 | |
| 716 | - // Semantic relevance score (5% weight) | |
| 717 | - if (!empty($content_analysis['semantic_analysis']['relevance_score'])) { | |
| 718 | - $scores['semantic_relevance'] = $content_analysis['semantic_analysis']['relevance_score'] * ($this->optimization_weights['semantic_relevance'] / 100); | |
| 719 | - } | |
| 720 | - | |
| 721 | 725 | return (int) round(array_sum($scores)); |
| 722 | 726 | } |
| 723 | 727 | |
| 724 | 728 | /** |
| @@ -1049,9 +1053,9 @@ | ||
| 1049 | 1053 | // Get recent posts for blog homepage |
| 1050 | 1054 | $recent_posts = get_posts(['numberposts' => 3]); |
| 1051 | 1055 | $content_parts = []; |
| 1052 | 1056 | foreach ($recent_posts as $post) { |
| 1053 | - $content_parts[] = $post->post_title . ' ' . wp_trim_words($post->post_content, 100); | |
| 1057 | + $content_parts[] = $post->post_title . ' ' . \ThinkRank\Core\Seo_Text::trim_words($post->post_content, 100, '...', 1000); | |
| 1054 | 1058 | } |
| 1055 | 1059 | $content = implode(' ', $content_parts); |
| 1056 | 1060 | } |
| 1057 | 1061 | break; |
| @@ -1446,11 +1450,14 @@ | ||
| 1446 | 1450 | |
| 1447 | 1451 | return max(0, $score); |
| 1448 | 1452 | } |
| 1449 | 1453 | |
| 1450 | - // Placeholder implementations for methods referenced but not yet implemented | |
| 1454 | + // Placeholder implementations for methods referenced but not yet implemented. | |
| 1455 | + // Anything here that cannot measure its subject returns null or an empty | |
| 1456 | + // set, never a plausible-looking number: a consumer can branch on "not | |
| 1457 | + // measured", but not on an 80 that was typed rather than computed (#538). | |
| 1451 | 1458 | private function calculate_performance_metrics(array $content_analysis, array $template_compliance): array { |
| 1452 | - return ['performance_score' => 80, 'metrics' => []]; | |
| 1459 | + return ['performance_score' => null, 'metrics' => []]; | |
| 1453 | 1460 | } |
| 1454 | 1461 | |
| 1455 | 1462 | private function generate_optimization_recommendations(array $content_analysis, array $template_compliance, string $content_type): array { |
| 1456 | 1463 | $recommendations = []; |
| @@ -1467,9 +1474,12 @@ | ||
| 1467 | 1474 | return $recommendations; |
| 1468 | 1475 | } |
| 1469 | 1476 | |
| 1470 | 1477 | private function identify_optimization_opportunities(array $content_analysis, array $template_compliance, string $content_type): array { |
| 1471 | - return ['opportunities' => [], 'potential_impact' => 'medium']; | |
| 1478 | + // No potential_impact: with no opportunities found there is nothing to | |
| 1479 | + // rate, and 'medium' was a verdict on an empty list. The sibling in | |
| 1480 | + // Performance_Monitoring_Manager already returns just this shape. | |
| 1481 | + return ['opportunities' => []]; | |
| 1472 | 1482 | } |
| 1473 | 1483 | |
| 1474 | 1484 | private function generate_content_suggestions(array $content_analysis, string $content_type, array $keywords): array { |
| 1475 | 1485 | return ['suggestions' => [], 'content_ideas' => []]; |
| @@ -1498,10 +1508,13 @@ | ||
| 1498 | 1508 | private function calculate_improvement_rate(array $performance_trends): float { |
| 1499 | 1509 | return 0.0; |
| 1500 | 1510 | } |
| 1501 | 1511 | |
| 1502 | - private function calculate_performance_score(array $metrics): int { | |
| 1503 | - return 80; | |
| 1512 | + private function calculate_performance_score(array $metrics): ?int { | |
| 1513 | + // Nothing here scores $metrics, so there is no score to report. Null | |
| 1514 | + // travels into track_performance()'s 'performance_score' and reads as | |
| 1515 | + // "not measured"; an 80 read as a healthy page (#538). | |
| 1516 | + return null; | |
| 1504 | 1517 | } |
| 1505 | 1518 | |
| 1506 | 1519 | private function compare_with_benchmarks(array $metrics, string $context_type): array { |
| 1507 | 1520 | return ['benchmark_comparison' => []]; |
| @@ -1507,7 +1520,11 @@ | ||
| 1507 | 1520 | return ['benchmark_comparison' => []]; |
| 1508 | 1521 | } |
| 1509 | 1522 | |
| 1510 | 1523 | private function store_performance_data(string $context_type, ?int $context_id, array $tracking): bool { |
| 1511 | - return true; | |
| 1524 | + // Reports failure because it stores nothing. The single caller discards | |
| 1525 | + // the return, so this changes no behaviour today, but a caller added | |
| 1526 | + // later must not read "stored successfully" from a method with no | |
| 1527 | + // storage in it (#538). | |
| 1528 | + return false; | |
| 1512 | 1529 | } |
| 1513 | 1530 | } |