PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.0.2
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.0.2
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-term-seo-checks.php

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

231 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Get term 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
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit; // Exit if accessed directly.
16 }
17
18 /**
19 * Runs lightweight ThinkRank-native on-page SEO checks for taxonomy terms.
20 *
21 * ThinkRank has no dedicated term analysis engine, so this ability performs a
22 * small set of basic checks against the term's SEO title, meta description, and
23 * description.
24 */
25 class Get_Term_Seo_Checks extends Ability_Base {
26 /**
27 * Constructor.
28 */
29 public function __construct() {
30 $this->id = 'thinkrank/get-term-seo-checks';
31 $this->label = __( 'Get ThinkRank Term SEO Checks', 'thinkrank' );
32 $this->description = __( 'Run ThinkRank-native basic on-page SEO checks for one or more taxonomy terms (SEO title, meta description, and term description).', '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 'term_ids' => [
61 'type' => 'array',
62 'description' => __( 'One or more term IDs to inspect.', 'thinkrank' ),
63 'items' => [
64 'type' => 'integer',
65 ],
66 ],
67 ],
68 'required' => [ 'term_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 $term_ids = isset( $input['term_ids'] ) && is_array( $input['term_ids'] ) ? array_map( 'absint', $input['term_ids'] ) : [];
96 $term_ids = array_values(
97 array_filter(
98 $term_ids,
99 static function ( $term_id ) {
100 return $term_id > 0 && get_term( $term_id ) instanceof \WP_Term;
101 }
102 )
103 );
104
105 if ( empty( $term_ids ) ) {
106 return new \WP_Error(
107 'thinkrank_missing_term_ids',
108 __( 'At least one valid term ID is required.', 'thinkrank' ),
109 [ 'status' => 400 ]
110 );
111 }
112
113 $data = [];
114
115 foreach ( $term_ids as $term_id ) {
116 $term = get_term( $term_id );
117 if ( ! $term instanceof \WP_Term ) {
118 continue;
119 }
120
121 $data[] = [
122 'term_id' => $term_id,
123 'taxonomy' => (string) $term->taxonomy,
124 'checks' => $this->build_checks( $term ),
125 ];
126 }
127
128 return [
129 'status' => 'success',
130 'message' => __( 'Term SEO checks generated.', 'thinkrank' ),
131 'data' => $data,
132 ];
133 }
134
135 /**
136 * Build the on-page checks for a single term.
137 *
138 * @param \WP_Term $term Term object.
139 * @return array<int, array<string, string>>
140 */
141 private function build_checks( \WP_Term $term ) {
142 $seo_title = (string) get_term_meta( $term->term_id, '_thinkrank_seo_title', true );
143 $description = (string) get_term_meta( $term->term_id, '_thinkrank_meta_description', true );
144
145 $title_length = mb_strlen( $seo_title );
146 $desc_length = mb_strlen( $description );
147
148 $checks = [];
149
150 if ( '' === $seo_title ) {
151 $checks[] = [
152 'id' => 'seo_title_present',
153 'label' => __( 'SEO title', 'thinkrank' ),
154 'status' => 'warning',
155 'message' => __( 'No SEO title is set for this term.', 'thinkrank' ),
156 ];
157 } else {
158 $checks[] = [
159 'id' => 'seo_title_present',
160 'label' => __( 'SEO title', 'thinkrank' ),
161 'status' => 'ok',
162 'message' => __( 'An SEO title is set.', 'thinkrank' ),
163 ];
164
165 if ( $title_length < 30 || $title_length > 60 ) {
166 $checks[] = [
167 'id' => 'seo_title_length',
168 'label' => __( 'SEO title length', 'thinkrank' ),
169 'status' => 'warning',
170 'message' => __( 'The SEO title should be between 30 and 60 characters.', 'thinkrank' ),
171 ];
172 } else {
173 $checks[] = [
174 'id' => 'seo_title_length',
175 'label' => __( 'SEO title length', 'thinkrank' ),
176 'status' => 'ok',
177 'message' => __( 'The SEO title length is within the recommended range.', 'thinkrank' ),
178 ];
179 }
180 }
181
182 if ( '' === $description ) {
183 $checks[] = [
184 'id' => 'meta_description_present',
185 'label' => __( 'Meta description', 'thinkrank' ),
186 'status' => 'warning',
187 'message' => __( 'No meta description is set for this term.', 'thinkrank' ),
188 ];
189 } else {
190 $checks[] = [
191 'id' => 'meta_description_present',
192 'label' => __( 'Meta description', 'thinkrank' ),
193 'status' => 'ok',
194 'message' => __( 'A meta description is set.', 'thinkrank' ),
195 ];
196
197 if ( $desc_length < 70 || $desc_length > 160 ) {
198 $checks[] = [
199 'id' => 'meta_description_length',
200 'label' => __( 'Meta description length', 'thinkrank' ),
201 'status' => 'warning',
202 'message' => __( 'The meta description should be between 70 and 160 characters.', 'thinkrank' ),
203 ];
204 } else {
205 $checks[] = [
206 'id' => 'meta_description_length',
207 'label' => __( 'Meta description length', 'thinkrank' ),
208 'status' => 'ok',
209 'message' => __( 'The meta description length is within the recommended range.', 'thinkrank' ),
210 ];
211 }
212 }
213
214 $checks[] = '' === trim( (string) $term->description )
215 ? [
216 'id' => 'term_description_present',
217 'label' => __( 'Term description', 'thinkrank' ),
218 'status' => 'warning',
219 'message' => __( 'This term has no description.', 'thinkrank' ),
220 ]
221 : [
222 'id' => 'term_description_present',
223 'label' => __( 'Term description', 'thinkrank' ),
224 'status' => 'ok',
225 'message' => __( 'This term has a description.', 'thinkrank' ),
226 ];
227
228 return $checks;
229 }
230 }
231