PluginProbe
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms / trunk
Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms vtrunk
3.53.0 3.52.0 3.51.0 3.50.0 3.45.0 3.38.0 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.40.0 3.40.1 3.41.0 3.42.0 3.43.0 3.44.0 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 All 177 releases
simple-tags / inc / ajax-request.php

ajax-request.php in Tag, Category, and Taxonomy Manager – Autotagger Automatically Add Terms trunk, at inc/ajax-request.php

335 lines 16.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared,WordPressVIPMinimum.Security.ProperEscapingFunction.htmlAttrNotByEscHTML -- Legacy TaxoPress file: keep behavior unchanged while documenting existing PHPCS exceptions.
4 //Taxopress auto terms => Auto terms all content ajax callback
5 add_action('wp_ajax_taxopress_autoterms_content_by_ajax', 'taxopress_autoterms_content_by_ajax');
6 function taxopress_autoterms_content_by_ajax()
7 {
8 global $wpdb, $added_post_term, $empty_term_messages;
9
10 $added_post_term = [];
11 $empty_term_messages = [];
12
13 // run a quick security check
14 check_ajax_referer('st-admin-js', 'security');
15
16 //instantiate response default value
17 $response['status'] = 'error';
18 $response['message'] = '';
19 $response['content'] = '';
20 $response['total'] = 0;
21 $response['next_start'] = 0;
22 $response['percentage'] = '';
23
24 $autoterms = taxopress_get_autoterm_data();
25 $auto_term_id = !empty($_POST['taxopress_autoterm_content']['autoterm_id']) ? (int)$_POST['taxopress_autoterm_content']['autoterm_id'] : 0;
26
27 $existing_terms_batches = !empty($_POST['taxopress_autoterm_content']['existing_terms_batches']) ? (int)$_POST['taxopress_autoterm_content']['existing_terms_batches'] : 0;
28 $existing_terms_sleep = !empty($_POST['taxopress_autoterm_content']['existing_terms_sleep']) ? (int)$_POST['taxopress_autoterm_content']['existing_terms_sleep'] : 0;
29 $limit_days = !empty($_POST['taxopress_autoterm_content']['limit_days']) ? (int)$_POST['taxopress_autoterm_content']['limit_days'] : 0;
30 $autoterm_existing_content_exclude = !empty($_POST['taxopress_autoterm_content']['autoterm_existing_content_exclude']) ? (int)$_POST['taxopress_autoterm_content']['autoterm_existing_content_exclude'] : 0;
31
32 $start_from = isset($_POST['start_from']) && (int)$_POST['start_from'] > 0 ? (int)$_POST['start_from'] : 0;
33 $offset_start_from = max(0, $start_from);
34
35 if (!current_user_can('simple_tags')) {
36 $response['message'] = '<div class="taxopress-response-css red"><p>' . esc_html__('Permission denied.', 'simple-tags') . '</p><button type="button" class="notice-dismiss"></button></div>';
37 wp_send_json($response);
38 }
39
40 $max_batch_size = max(1, (int) apply_filters('taxopress_autoterms_max_batch_size', 25));
41 $max_batch_wait = max(0, (int) apply_filters('taxopress_autoterms_max_batch_wait', 60));
42
43 if (1 > $existing_terms_batches) {
44 $response['message'] = sprintf(
45 esc_html__('The batch limit must be between 1 and %d posts.', 'simple-tags'),
46 $max_batch_size
47 );
48 wp_send_json($response, 400);
49 }
50
51 if (0 > $existing_terms_sleep) {
52 $response['message'] = sprintf(
53 esc_html__('The batch wait time must be between 0 and %d seconds.', 'simple-tags'),
54 $max_batch_wait
55 );
56 wp_send_json($response, 400);
57 }
58
59 // Clamp legacy saved values and hostile requests to the current safe limits.
60 $existing_terms_batches = min($existing_terms_batches, $max_batch_size);
61 $existing_terms_sleep = min($existing_terms_sleep, $max_batch_wait);
62
63 if ($start_from === 0) {
64 delete_option('tmp_auto_terms_st');
65 }
66
67 $auto_term_settings = [
68 'autoterm_id' => $auto_term_id,
69 'existing_terms_batches' => $existing_terms_batches,
70 'existing_terms_sleep' => $existing_terms_sleep,
71 'limit_days' => $limit_days,
72 'autoterm_existing_content_exclude' => $autoterm_existing_content_exclude,
73 ];
74 update_option('taxopress_autoterms_content', $auto_term_settings);
75
76 if (empty($auto_term_id)) {
77 $response['message'] = '<div class="taxopress-response-css red"><p>' . esc_html__('Auto Term is required, kindly add an Auto Term from Auto Term menu.', 'simple-tags') . '</p><button type="button" class="notice-dismiss"></button></div>';
78 wp_send_json($response);
79 } elseif (empty($existing_terms_batches)) {
80 $response['message'] = '<div class="taxopress-response-css red"><p>' . esc_html__('Limit per batches is required.', 'simple-tags') . '</p><button type="button" class="notice-dismiss"></button></div>';
81 wp_send_json($response);
82 } elseif (0 > $existing_terms_sleep) {
83 $response['message'] = '<div class="taxopress-response-css red"><p>' . esc_html__('Batches wait time is required.', 'simple-tags') . '</p><button type="button" class="notice-dismiss"></button></div>';
84 wp_send_json($response);
85 }
86
87 if ($auto_term_id && array_key_exists($auto_term_id, $autoterms)) {
88 $autoterm_data = $autoterms[$auto_term_id];
89 $autoterm_data['existing_terms_batches'] = $existing_terms_batches;
90 $autoterm_data['existing_terms_sleep'] = $existing_terms_sleep;
91 $autoterm_data['limit_days'] = $limit_days;
92 $autoterm_data['autoterm_exclude'] = $autoterm_existing_content_exclude;
93 $autoterm_data['replace_type'] = isset($autoterm_data['existing_content_replace_type']) ? $autoterm_data['existing_content_replace_type'] : '';
94 $autoterm_data['terms_limit'] = !empty($autoterm_data['existing_content_terms_limit']) ? $autoterm_data['existing_content_terms_limit'] : '';
95 } else {
96 $response['message'] = '<div class="taxopress-response-css red"><p>' . esc_html__('Auto term settings not found', 'simple-tags') . '</p><button type="button" class="notice-dismiss"></button></div>';
97 wp_send_json($response);
98 }
99
100 if (empty($autoterm_data['post_types'])) {
101 $response['message'] = '<div class="taxopress-response-css red"><p>' . esc_html__('The selected Auto Term setting is not enabled for any post type. Please select at least one post type in the Auto Term settings.', 'simple-tags') . '</p><button type="button" class="notice-dismiss"></button></div>';
102 wp_send_json($response);
103 }
104
105 if (empty($autoterm_data['autoterm_for_existing_content'])) {
106 $response['message'] = '<div class="taxopress-response-css red"><p>' . esc_html__('The selected Auto Term is not enabled for existing content. Please enable it in Auto Term settings.', 'simple-tags') . '</p><button type="button" class="notice-dismiss"></button></div>';
107 wp_send_json($response);
108 }
109
110 $lock_key = 'taxopress_autoterms_scan_lock_' . $auto_term_id;
111 $lock_ttl = max(30, (int) apply_filters('taxopress_autoterms_scan_lock_ttl', 300));
112 $lock_token = wp_generate_uuid4();
113 $existing_lock = get_option($lock_key, []);
114 $existing_lock_time = is_array($existing_lock) && isset($existing_lock['time'])
115 ? (int) $existing_lock['time']
116 : 0;
117
118 if ($existing_lock_time && $existing_lock_time < (time() - $lock_ttl)) {
119 delete_option($lock_key);
120 }
121
122 if (!add_option($lock_key, ['token' => $lock_token, 'time' => time()], '', false)) {
123 $response['message'] = esc_html__('This Auto Terms scan is already processing another batch. Please wait and try again.', 'simple-tags');
124 wp_send_json($response, 409);
125 }
126
127 $limit = (isset($autoterm_data['existing_terms_batches']) && (int)$autoterm_data['existing_terms_batches'] > 0) ? (int)$autoterm_data['existing_terms_batches'] : 2;
128
129 $sleep = (isset($autoterm_data['existing_terms_sleep']) && (int)$autoterm_data['existing_terms_sleep'] > 0) ? (int)$autoterm_data['existing_terms_sleep'] : 0;
130
131 // Waiting is performed by the browser between requests so PHP workers are not held idle.
132 $response['wait'] = $sleep;
133
134 $limit_days = (int) $autoterm_data['limit_days'];
135 $limit_days_sql = '';
136 if ($limit_days > 0) {
137 $limit_days_sql = 'AND post_date > "' . gmdate('Y-m-d H:i:s', time() - $limit_days * 86400) . '"';
138 }
139
140 $post_types = $autoterm_data['post_types'];
141 $post_status = isset($autoterm_data['post_status']) && is_array($autoterm_data['post_status']) ? $autoterm_data['post_status'] : ['publish'];
142
143 $total = isset($_POST['total']) ? (int)$_POST['total'] : 0;
144
145 $post_types = array_map('sanitize_key', (array) $post_types);
146 $post_status = array_map('sanitize_key', (array) $post_status);
147
148 $post_types_placeholders = implode(',', array_fill(0, count($post_types), '%s'));
149 $post_status_placeholders = implode(',', array_fill(0, count($post_status), '%s'));
150
151 if ($autoterm_existing_content_exclude > 0) {
152 $sql = "SELECT ID, post_title, post_content FROM {$wpdb->posts}
153 LEFT JOIN {$wpdb->postmeta} ON ( ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_taxopress_autotermed' )
154 WHERE post_type IN ({$post_types_placeholders})
155 AND {$wpdb->postmeta}.post_id IS NULL
156 AND post_status IN ({$post_status_placeholders})
157 {$limit_days_sql}
158 ORDER BY ID DESC
159 LIMIT %d OFFSET %d";
160
161 $prepare_args = array_merge($post_types, $post_status, [$limit, $offset_start_from]);
162 $objects = (array) $wpdb->get_results($wpdb->prepare($sql, $prepare_args));
163 } else {
164 $sql = "SELECT ID, post_title, post_content FROM {$wpdb->posts}
165 WHERE post_type IN ({$post_types_placeholders})
166 AND post_status IN ({$post_status_placeholders})
167 {$limit_days_sql}
168 ORDER BY ID DESC
169 LIMIT %d OFFSET %d";
170
171 $prepare_args = array_merge($post_types, $post_status, [$limit, $offset_start_from]);
172 $objects = (array) $wpdb->get_results($wpdb->prepare($sql, $prepare_args));
173 }
174
175 $response_content = '';
176 if (!empty($objects)) {
177 foreach ($objects as $object) {
178 update_post_meta($object->ID, '_taxopress_autotermed', 1);
179 $post_object = get_post($object->ID);
180 SimpleTags_Client_Autoterms::auto_terms_post($post_object, $autoterm_data['taxonomy'], $autoterm_data, true, 'existing_content', 'st_autoterms');
181 $log_messages = !empty($empty_term_messages[$object->ID]['message']) ? $empty_term_messages[$object->ID]['message'] : [];
182 $log_message_html = '';
183 if (!empty($log_messages)) {
184 $log_message_html .= '<div class="log-message-show-button"><a href="#" class="msg-show">' . sprintf(esc_html__('Show Log Messages (%1s)', 'simple-tags'), '<strong>' . count($log_messages) . '</strong>') . '</a></div>';
185 $log_message_html .= '<div class="autoterm-log-message" style="display: none;"><ul>';
186 $log_msg_lists = array_map(function ($item) {
187 return '<li class="log-message-list">' . $item . '</li>';
188 }, $log_messages);
189 $log_message_html .= join('', $log_msg_lists);
190 $log_message_html .= '</ul></div>';
191 $log_message_html .= '<div class="log-message-hide-button"><a href="#" class="msg-hide" style="display: none;">' . sprintf(esc_html__('Hide Log Messages (%1s)', 'simple-tags'), '<strong>' . count($log_messages) . '</strong>') . '</a></div>';
192 }
193 if (!empty($added_post_term[$object->ID])) {
194 $tag_lists = array_map(function ($item) {
195 return '<span class="taxopress-term"><span class="term-name">' . $item . '</span></span>';
196 }, $added_post_term[$object->ID]);
197 $added_terms_html = join('', $tag_lists) . $log_message_html;
198 } else {
199 $added_terms_html = esc_html__('No terms added.', 'simple-tags') . $log_message_html;
200 ;
201 }
202 $response_content .= '<li class="result-item">
203 <fieldset>
204 <legend>
205 <span class="result-title">
206 <a target="_blank" href="' . esc_url(get_edit_post_link($object->ID)) . '">' . esc_html($object->post_title) . '</a>
207 </span>
208 </legend>
209 <div class="result-content">' . $added_terms_html . '</div>
210 </fieldset></li>';
211 unset($object);
212 }
213
214 $response['status'] = 'progress';
215 $response['content'] = $response_content;
216 $response['done'] = ($start_from + count($objects));
217 $percentage = 100;
218 $response['notice'] = '<div class="taxopress-response-css yellow"><p>' . sprintf(esc_html__('Please leave this screen running to continue the scan. To stop the scan, close this screen or click here: %1sStop%2s | %3sPause%4s', 'simple-tags'), '<a href="#" class="terminate-autoterm-scan">', '</a>', '<a href="#" class="pause-autoterm-scan" data-pause="0" data-pause-text="' . esc_html__('Pause', 'simple-tags') . '" data-resume-text="' . esc_html__('Resume', 'simple-tags') . '">', '</a>') . '</p></div>';
219 $progress_message = '<div class="taxopress-response-css yellow"><p>' . sprintf(esc_html__('Progress Report: %s posts checked.', 'simple-tags'), '<strong>' . ($start_from + count($objects)) . '</strong>') . '</p></div>';
220 } else {
221 $counter = (int)get_option('tmp_auto_terms_st');
222 delete_option('tmp_auto_terms_st');
223 $percentage = 100;
224 $response['status'] = 'sucess';
225 $response['done'] = $total;
226 $progress_message = '<div class="taxopress-response-css green"><p>' . sprintf(esc_html__('Completed: %s terms added from %s posts checked.', 'simple-tags'), $counter, ($start_from + count($objects))) . '</p><button type="button" class="notice-dismiss"></button></div>';
227 $response['message'] = $progress_message;
228 }
229 $response['percentage'] = $progress_message;
230
231 $current_lock = get_option($lock_key, []);
232 if (is_array($current_lock) && isset($current_lock['token']) && $current_lock['token'] === $lock_token) {
233 delete_option($lock_key);
234 }
235
236 wp_send_json($response);
237 }
238
239
240 //Taxopress search post call back
241 add_action('wp_ajax_taxopress_post_search', 'taxopress_post_search_callback');
242
243 function taxopress_post_search_callback()
244 {
245 header('Content-Type: application/javascript');
246
247 if (
248 empty($_GET['nonce'])
249 || !wp_verify_nonce(sanitize_key(wp_unslash($_GET['nonce'])), 'taxopress-post-search')
250 ) {
251 wp_send_json_error(null, 403);
252 }
253
254 if (!current_user_can('simple_tags')) {
255 wp_send_json_error(null, 403);
256 }
257
258 $search = !empty($_GET['q']) ? sanitize_text_field(wp_unslash($_GET['q'])) : '';
259 $post_type = !empty($_GET['post_types']) ? array_map('sanitize_text_field', wp_unslash($_GET['post_types'])) : 'any';
260
261 $post_args = [
262 'post_type' => $post_type,
263 'post_status' => 'publish',
264 'posts_per_page' => apply_filters('taxopress_filter_posts_search_result_limit', 20),
265 ];
266
267 if (!empty($search)) {
268 $post_args['s'] = $search;
269 }
270
271 $posts = get_posts($post_args);
272 $results = [];
273
274 foreach ($posts as $post) {
275 $results[] = [
276 'id' => $post->ID,
277 'text' => $post->post_title,
278 ];
279 }
280
281 $response = [
282 'results' => $results,
283 ];
284 echo wp_json_encode($response);
285 exit;
286 }
287
288
289 //Taxopress search field call back
290 add_action('wp_ajax_taxopress_custom_fields_search', 'taxopress_custom_fields_search_callback');
291
292 function taxopress_custom_fields_search_callback()
293 {
294 global $wpdb;
295
296 header('Content-Type: application/javascript');
297
298 if (
299 empty($_GET['nonce'])
300 || !wp_verify_nonce(sanitize_key(wp_unslash($_GET['nonce'])), 'taxopress-custom-fields-search')
301 ) {
302 wp_send_json_error(null, 403);
303 }
304
305 if (!current_user_can('simple_tags')) {
306 wp_send_json_error(null, 403);
307 }
308
309 $search = !empty($_GET['q']) ? sanitize_text_field(wp_unslash($_GET['q'])) : '';
310
311 $whereClause = '';
312 if (!empty($search)) {
313 $like = '%' . $wpdb->esc_like($search) . '%';
314 $whereClause = $wpdb->prepare("AND meta_key LIKE %s", $like);
315 }
316
317 $queryResults = $wpdb->get_col("SELECT DISTINCT meta_key FROM $wpdb->postmeta WHERE 1=1 $whereClause ORDER BY meta_key ASC LIMIT 20");
318
319 $results = [];
320 if (!empty($queryResults)) {
321 foreach ($queryResults as $queryResult) {
322 $results[] = [
323 'id' => $queryResult,
324 'text' => $queryResult,
325 ];
326 }
327 }
328
329 $response = [
330 'results' => $results,
331 ];
332 echo wp_json_encode($response);
333 exit;
334 }
335