PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.4.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.4.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 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / includes / abilities / analysis / class-get-post-seo-checks.php

class-get-post-seo-checks.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.4.0, at includes/abilities/analysis/class-get-post-seo-checks.php

150 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Get post SEO checks ability.
4 *
5 * @package ThinkRank\Abilities\Analysis
6 */
7
8 declare(strict_types=1);
9
10 namespace ThinkRank\Abilities\Analysis;
11
12 use ThinkRank\Abilities\Ability_Base;
13 use ThinkRank\Admin\Metabox_Manager;
14 use ThinkRank\AI\SEOScoreCalculator;
15 use ThinkRank\Core\Database;
16 use ThinkRank\SEO\Pattern_Resolver;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // Exit if accessed directly.
20 }
21
22 /**
23 * Runs ThinkRank's SEO score analysis for one or more posts.
24 */
25 class Get_Post_Seo_Checks extends Ability_Base {
26 /**
27 * Constructor.
28 */
29 public function __construct() {
30 $this->id = 'thinkrank/get-post-seo-checks';
31 $this->label = __( 'Get ThinkRank Post SEO Checks', 'thinkrank' );
32 $this->description = __( 'Run ThinkRank SEO score analysis for one or more posts, pages, or custom post type items. Scores are not persisted; use bulk-analyze-and-save to score and store them.', 'thinkrank' );
33 }
34
35 /**
36 * {@inheritDoc}
37 *
38 * @return array<string, bool|float|string>
39 */
40 public function get_annotations() {
41 return [
42 'readonly' => true,
43 'destructive' => false,
44 'idempotent' => true,
45 'priority' => 1.0,
46 'openWorldHint' => false,
47 ];
48 }
49
50 /**
51 * {@inheritDoc}
52 *
53 * @return array<string, mixed>
54 */
55 public function get_input_schema() {
56 return [
57 'type' => 'object',
58 'additionalProperties' => false,
59 'properties' => [
60 'post_ids' => [
61 'type' => 'array',
62 'description' => __( 'One or more post IDs to inspect.', 'thinkrank' ),
63 'items' => [
64 'type' => 'integer',
65 ],
66 ],
67 ],
68 'required' => [ 'post_ids' ],
69 ];
70 }
71
72 /**
73 * {@inheritDoc}
74 *
75 * @return array<string, mixed>
76 */
77 public function get_output_schema() {
78 return [
79 'type' => 'object',
80 'properties' => [
81 'status' => [ 'type' => 'string' ],
82 'message' => [ 'type' => 'string' ],
83 'data' => [ 'type' => 'array' ],
84 ],
85 ];
86 }
87
88 /**
89 * Execute ability.
90 *
91 * @param array<string, mixed> $input Ability input payload.
92 * @return array<string, mixed>|\WP_Error
93 */
94 public function execute( $input ) {
95 $post_ids = isset( $input['post_ids'] ) && is_array( $input['post_ids'] ) ? array_map( 'absint', $input['post_ids'] ) : [];
96 $post_ids = array_values(
97 array_filter(
98 $post_ids,
99 static function ( $post_id ) {
100 return $post_id > 0 && get_post( $post_id ) instanceof \WP_Post;
101 }
102 )
103 );
104
105 if ( empty( $post_ids ) ) {
106 return new \WP_Error(
107 'thinkrank_missing_post_ids',
108 __( 'At least one valid post ID is required.', 'thinkrank' ),
109 [ 'status' => 400 ]
110 );
111 }
112
113 $calculator = new SEOScoreCalculator( new Database() );
114 $metabox = new Metabox_Manager();
115 $data = [];
116
117 foreach ( $post_ids as $post_id ) {
118 try {
119 $content = $calculator->analyze_post_content( $post_id );
120
121 // Override the raw per-post title/description with their effective
122 // values (custom value, else the resolved Global pattern) so an
123 // inherited title or description is scored as present — matching
124 // the editor and frontend — instead of counting as missing.
125 $metadata = $metabox->get_post_metadata( $post_id );
126 $metadata['title'] = Pattern_Resolver::effective_title( $post_id );
127 $metadata['description'] = Pattern_Resolver::effective_description( $post_id );
128
129 $score = $calculator->calculate_score( $content, $metadata );
130
131 $data[] = [
132 'post_id' => $post_id,
133 'score' => $score,
134 ];
135 } catch ( \Throwable $e ) {
136 $data[] = [
137 'post_id' => $post_id,
138 'error' => $e->getMessage(),
139 ];
140 }
141 }
142
143 return [
144 'status' => 'success',
145 'message' => __( 'SEO checks generated.', 'thinkrank' ),
146 'data' => $data,
147 ];
148 }
149 }
150