PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 1.10.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v1.10.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 / admin / class-focus-keyword-ajax.php

class-focus-keyword-ajax.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 1.10.0, at includes/admin/class-focus-keyword-ajax.php

186 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Focus Keyword AJAX Handler
4 *
5 * Handles AJAX requests for inline editing of focus keywords in post list
6 *
7 * @package ThinkRank\Admin
8 * @since 1.0.0
9 */
10
11 declare(strict_types=1);
12
13 namespace ThinkRank\Admin;
14
15 // Prevent direct access
16 if (!defined('ABSPATH')) {
17 exit;
18 }
19
20 /**
21 * Focus Keyword AJAX Handler Class
22 *
23 * Single Responsibility: Handle AJAX operations for focus keyword updates
24 *
25 * @since 1.0.0
26 */
27 class Focus_Keyword_Ajax {
28
29 /**
30 * AJAX action name
31 *
32 * @var string
33 */
34 private const AJAX_ACTION = 'thinkrank_update_focus_keyword';
35
36 /**
37 * Nonce action name
38 *
39 * @var string
40 */
41 private const NONCE_ACTION = 'thinkrank_focus_keyword_nonce';
42
43 /**
44 * Initialize AJAX handler
45 *
46 * @return void
47 */
48 public function init(): void {
49 add_action('wp_ajax_' . self::AJAX_ACTION, [$this, 'handle_update_focus_keyword']);
50 }
51
52 /**
53 * Get nonce action name
54 *
55 * @return string
56 */
57 public static function get_nonce_action(): string {
58 return self::NONCE_ACTION;
59 }
60
61 /**
62 * Get AJAX action name
63 *
64 * @return string
65 */
66 public static function get_ajax_action(): string {
67 return self::AJAX_ACTION;
68 }
69
70 /**
71 * Handle AJAX request to update focus keyword
72 *
73 * @return void
74 */
75 public function handle_update_focus_keyword(): void {
76 // Verify nonce
77 if (!check_ajax_referer(self::NONCE_ACTION, 'nonce', false)) {
78 wp_send_json_error([
79 'message' => __('Security check failed. Please refresh the page and try again.', 'thinkrank')
80 ], 403);
81 }
82
83 // Check user capabilities
84 if (!current_user_can('edit_posts')) {
85 wp_send_json_error([
86 'message' => __('You do not have permission to perform this action.', 'thinkrank')
87 ], 403);
88 }
89
90 // Get and validate post ID
91 $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
92
93 if (!$post_id) {
94 wp_send_json_error([
95 'message' => __('Invalid post ID.', 'thinkrank')
96 ], 400);
97 }
98
99 // Check if user can edit this specific post
100 if (!current_user_can('edit_post', $post_id)) {
101 wp_send_json_error([
102 'message' => __('You do not have permission to edit this post.', 'thinkrank')
103 ], 403);
104 }
105
106 // Get and sanitize focus keyword
107 $focus_keyword = isset($_POST['focus_keyword']) ? sanitize_text_field(wp_unslash($_POST['focus_keyword'])) : '';
108
109 // Trim whitespace
110 $focus_keyword = trim($focus_keyword);
111
112 // Update or delete post meta
113 if ( ! empty( $focus_keyword ) ) {
114 $updated = update_post_meta( $post_id, '_thinkrank_focus_keyword', $focus_keyword );
115 } else {
116 $updated = delete_post_meta($post_id, '_thinkrank_focus_keyword');
117 }
118
119 // Check if update was successful
120 if ($updated === false) {
121 wp_send_json_error([
122 'message' => __('Failed to update focus keyword. Please try again.', 'thinkrank')
123 ], 500);
124 }
125
126 // Prepare response data
127 $response_data = [
128 'message' => __('Focus keyword updated successfully.', 'thinkrank'),
129 'focus_keyword' => $focus_keyword,
130 'display_value' => !empty($focus_keyword) ? $focus_keyword : __('Not Set', 'thinkrank'),
131 'has_keyword' => !empty($focus_keyword)
132 ];
133
134 // update post modified time
135 $this->update_post_modified( $post_id );
136
137 /**
138 * Filter the AJAX response data for focus keyword update
139 *
140 * @param array $response_data Response data
141 * @param int $post_id Post ID
142 * @param string $focus_keyword Updated focus keyword
143 */
144 $response_data = apply_filters('thinkrank_focus_keyword_ajax_response', $response_data, $post_id, $focus_keyword);
145
146 wp_send_json_success($response_data);
147 }
148
149 /**
150 * Force update post_modified and post_modified_gmt timestamps.
151 *
152 * @param int $post_id
153 * @return bool
154 */
155 function update_post_modified( $post_id ) {
156
157 if ( ! $post_id || ! get_post( $post_id ) ) {
158 return false;
159 }
160
161 global $wpdb;
162
163 $now = current_time( 'mysql' );
164 $now_gmt = current_time( 'mysql', true );
165
166 // Update database directly
167 $updated = $wpdb->update(
168 $wpdb->posts,
169 [
170 'post_modified' => $now,
171 'post_modified_gmt' => $now_gmt,
172 ],
173 [ 'ID' => $post_id ],
174 [ '%s', '%s' ],
175 [ '%d' ]
176 );
177
178 // Clear cache so WordPress picks up new values
179 clean_post_cache( $post_id );
180
181 return ( $updated !== false );
182 }
183
184 }
185
186