PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.1.1
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.1.1
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 / content / class-update-post-seo.php

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

199 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Update post SEO ability.
4 *
5 * @package ThinkRank\Abilities\Content
6 */
7
8 declare(strict_types=1);
9
10 namespace ThinkRank\Abilities\Content;
11
12 use ThinkRank\Abilities\Ability_Base;
13 use ThinkRank\Admin\Metabox_Manager;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 /**
20 * Updates ThinkRank SEO data for a post object.
21 */
22 class Update_Post_Seo extends Ability_Base {
23 /**
24 * Constructor.
25 */
26 public function __construct() {
27 $this->id = 'thinkrank/update-post-seo';
28 $this->label = __( 'Update ThinkRank Post SEO', 'thinkrank' );
29 $this->description = __( 'Update ThinkRank SEO metadata for a post, page, or custom post type item. Read the current values with get-post-seo first; only the fields you pass are changed, and get-post-seo-checks reports what would improve.', 'thinkrank' );
30 }
31
32 /**
33 * {@inheritDoc}
34 *
35 * @return array<string, mixed>
36 */
37 public function get_input_schema() {
38 return [
39 'type' => 'object',
40 'additionalProperties' => false,
41 'properties' => [
42 'post_id' => [
43 'type' => 'integer',
44 'description' => __( 'The target post ID.', 'thinkrank' ),
45 ],
46 'settings' => [
47 'type' => 'object',
48 'additionalProperties' => true,
49 'description' => __( 'ThinkRank post SEO fields to update.', 'thinkrank' ),
50 'properties' => [
51 'title' => [ 'type' => 'string' ],
52 'description' => [ 'type' => 'string' ],
53 'canonical_url' => [ 'type' => 'string' ],
54 'focus_keyword' => [ 'type' => 'string' ],
55 'focus_keywords' => [
56 'type' => 'array',
57 'items' => [ 'type' => 'string' ],
58 ],
59 'robots_meta_enabled' => [ 'type' => 'boolean' ],
60 'robots_meta' => [ 'type' => 'object' ],
61 'advanced_robots_meta' => [ 'type' => 'object' ],
62 'og_title' => [ 'type' => 'string' ],
63 'og_description' => [ 'type' => 'string' ],
64 'og_image' => [ 'type' => 'string' ],
65 'twitter_title' => [ 'type' => 'string' ],
66 'twitter_description' => [ 'type' => 'string' ],
67 'twitter_image' => [ 'type' => 'string' ],
68 ],
69 ],
70 ],
71 'required' => [ 'post_id', 'settings' ],
72 ];
73 }
74
75 /**
76 * {@inheritDoc}
77 *
78 * @return array<string, mixed>
79 */
80 public function get_output_schema() {
81 return [
82 'type' => 'object',
83 'properties' => [
84 'success' => [ 'type' => 'boolean' ],
85 'message' => [ 'type' => 'string' ],
86 'post_id' => [ 'type' => 'integer' ],
87 ],
88 ];
89 }
90
91 /**
92 * Execute ability.
93 *
94 * @param array<string, mixed> $input Ability input payload.
95 * @return array<string, mixed>|\WP_Error
96 */
97 public function execute( $input ) {
98 $post_id = isset( $input['post_id'] ) ? absint( $input['post_id'] ) : 0;
99 $settings = isset( $input['settings'] ) && is_array( $input['settings'] ) ? $input['settings'] : [];
100
101 if ( ! $post_id || empty( $settings ) ) {
102 return new \WP_Error(
103 'thinkrank_invalid_post_update',
104 __( 'A valid post ID and settings payload are required.', 'thinkrank' ),
105 [ 'status' => 400 ]
106 );
107 }
108
109 if ( ! get_post( $post_id ) instanceof \WP_Post ) {
110 return new \WP_Error(
111 'thinkrank_post_not_found',
112 __( 'No post was found for the provided ID.', 'thinkrank' ),
113 [ 'status' => 404 ]
114 );
115 }
116
117 if ( ! current_user_can( 'edit_post', $post_id ) ) {
118 return new \WP_Error(
119 'thinkrank_cannot_edit_post',
120 __( 'You are not allowed to edit this post.', 'thinkrank' ),
121 [ 'status' => 403 ]
122 );
123 }
124
125 $fields = $this->map_fields( $settings, $post_id );
126
127 if ( empty( $fields ) ) {
128 return new \WP_Error(
129 'thinkrank_no_valid_post_meta_keys',
130 __( 'No valid ThinkRank post SEO keys were provided.', 'thinkrank' ),
131 [ 'status' => 400 ]
132 );
133 }
134
135 ( new Metabox_Manager() )->save_seo_fields( $post_id, $fields );
136
137 return [
138 'success' => true,
139 'message' => __( 'Post SEO metadata updated.', 'thinkrank' ),
140 'post_id' => $post_id,
141 ];
142 }
143
144 /**
145 * Map normalized input keys to metabox form field names.
146 *
147 * @param array<string, mixed> $settings Normalized settings payload.
148 * @param int $post_id Target post ID.
149 * @return array<string, mixed>
150 */
151 private function map_fields( array $settings, $post_id ) {
152 $fields = [];
153
154 $simple = [
155 'title' => 'thinkrank_seo_title',
156 'description' => 'thinkrank_meta_description',
157 'canonical_url' => 'thinkrank_canonical_url',
158 'focus_keyword' => 'thinkrank_focus_keyword',
159 'og_title' => 'thinkrank_og_title',
160 'og_description' => 'thinkrank_og_description',
161 'og_image' => 'thinkrank_og_image',
162 'twitter_title' => 'thinkrank_twitter_title',
163 'twitter_description' => 'thinkrank_twitter_description',
164 'twitter_image' => 'thinkrank_twitter_image',
165 ];
166
167 foreach ( $simple as $key => $field ) {
168 if ( array_key_exists( $key, $settings ) ) {
169 $fields[ $field ] = (string) $settings[ $key ];
170 }
171 }
172
173 if ( array_key_exists( 'focus_keywords', $settings ) && is_array( $settings['focus_keywords'] ) ) {
174 $fields['thinkrank_focus_keywords'] = (string) wp_json_encode( array_values( $settings['focus_keywords'] ) );
175 }
176
177 $has_robots = array_key_exists( 'robots_meta', $settings ) || array_key_exists( 'advanced_robots_meta', $settings );
178
179 if ( array_key_exists( 'robots_meta_enabled', $settings ) ) {
180 $fields['thinkrank_robots_meta_enabled'] = (int) (bool) $settings['robots_meta_enabled'];
181 } elseif ( $has_robots ) {
182 // The metabox only persists robots blobs when the toggle key is
183 // present; default to the currently stored value (or 1).
184 $existing = get_post_meta( $post_id, '_thinkrank_robots_meta_enabled', true );
185 $fields['thinkrank_robots_meta_enabled'] = '' === $existing ? 1 : (int) (bool) $existing;
186 }
187
188 if ( array_key_exists( 'robots_meta', $settings ) ) {
189 $fields['thinkrank_robots_meta'] = (string) wp_json_encode( (array) $settings['robots_meta'] );
190 }
191
192 if ( array_key_exists( 'advanced_robots_meta', $settings ) ) {
193 $fields['thinkrank_advanced_robots_meta'] = (string) wp_json_encode( (array) $settings['advanced_robots_meta'] );
194 }
195
196 return $fields;
197 }
198 }
199