PluginProbe ʕ •ᴥ•ʔ
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 27.5
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v27.5
27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 19.1 19.10 19.11 19.12 19.13 19.14 19.2 19.3 19.4 19.5 19.5.1 19.6 19.6.1 19.7 19.7.1 19.7.2 19.8 19.9 20.0 20.1 20.10 20.11 20.12 20.13 20.2 20.2.1 20.3 20.4 20.5 20.6 20.7 20.8 20.9 21.0 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.8.1 21.9 21.9.1 22.0 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 23.0 23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 24.0 24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.8.1 24.9 25.0 25.1 25.2 25.3 25.3.1 25.4 25.5 25.6 25.7 25.8 25.9 26.0 26.1 26.1.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 27.0 27.1 27.1.1 27.2 27.3 27.4
wordpress-seo / admin / ajax.php
wordpress-seo / admin Last commit date
ajax 2 years ago capabilities 1 year ago endpoints 2 years ago exceptions 3 months ago filters 3 months ago formatter 1 year ago google_search_console 3 months ago import 3 months ago listeners 8 years ago menu 3 months ago metabox 3 months ago notifiers 3 months ago pages 3 months ago roles 3 months ago services 3 months ago statistics 3 months ago taxonomy 3 months ago tracking 3 months ago views 3 months ago watchers 3 months ago admin-settings-changed-listener.php 2 years ago ajax.php 3 months ago class-admin-asset-analysis-worker-location.php 3 months ago class-admin-asset-dev-server-location.php 3 months ago class-admin-asset-location.php 8 years ago class-admin-asset-manager.php 3 months ago class-admin-asset-seo-location.php 4 years ago class-admin-editor-specific-replace-vars.php 3 months ago class-admin-gutenberg-compatibility-notification.php 3 months ago class-admin-help-panel.php 3 months ago class-admin-init.php 3 months ago class-admin-recommended-replace-vars.php 2 years ago class-admin-user-profile.php 7 months ago class-admin-utils.php 3 months ago class-admin.php 3 months ago class-asset.php 1 year ago class-bulk-description-editor-list-table.php 3 months ago class-bulk-editor-list-table.php 3 months ago class-bulk-title-editor-list-table.php 3 months ago class-collector.php 1 year ago class-config.php 3 months ago class-database-proxy.php 3 months ago class-export.php 3 months ago class-expose-shortlinks.php 7 months ago class-gutenberg-compatibility.php 1 month ago class-meta-columns.php 3 months ago class-my-yoast-proxy.php 3 months ago class-option-tab.php 4 years ago class-option-tabs-formatter.php 3 months ago class-option-tabs.php 2 years ago class-paper-presenter.php 5 years ago class-plugin-availability.php 3 months ago class-plugin-conflict.php 2 years ago class-premium-popup.php 1 year ago class-premium-upsell-admin-block.php 3 months ago class-primary-term-admin.php 3 months ago class-product-upsell-notice.php 3 months ago class-remote-request.php 2 years ago class-schema-person-upgrade-notification.php 3 months ago class-suggested-plugins.php 3 months ago class-wincher-dashboard-widget.php 3 months ago class-yoast-columns.php 3 months ago class-yoast-dashboard-widget.php 3 months ago class-yoast-form.php 3 months ago class-yoast-input-validation.php 3 months ago class-yoast-network-admin.php 3 months ago class-yoast-network-settings-api.php 3 months ago class-yoast-notification-center.php 3 months ago class-yoast-notification.php 3 months ago class-yoast-notifications.php 3 months ago class-yoast-plugin-conflict.php 3 months ago index.php 10 years ago interface-collection.php 7 years ago interface-installable.php 8 years ago
ajax.php
412 lines
1 <?php
2 /**
3 * WPSEO plugin file.
4 *
5 * @package WPSEO\Admin
6 */
7
8 if ( ! defined( 'WPSEO_VERSION' ) ) {
9 header( 'Status: 403 Forbidden' );
10 header( 'HTTP/1.1 403 Forbidden' );
11 exit();
12 }
13
14 /**
15 * Convenience function to JSON encode and echo results and then die.
16 *
17 * @param array $results Results array for encoding.
18 *
19 * @return void
20 */
21 function wpseo_ajax_json_echo_die( $results ) {
22 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
23 echo WPSEO_Utils::format_json_encode( $results );
24 exit();
25 }
26
27 /**
28 * Function used from AJAX calls, takes it variables from $_POST, dies on exit.
29 *
30 * @return void
31 */
32 function wpseo_set_option() {
33 if ( ! current_user_can( 'manage_options' ) ) {
34 exit( '-1' );
35 }
36
37 check_ajax_referer( 'wpseo-setoption' );
38
39 if ( ! isset( $_POST['option'] ) || ! is_string( $_POST['option'] ) ) {
40 exit( '-1' );
41 }
42
43 $option = sanitize_text_field( wp_unslash( $_POST['option'] ) );
44 if ( $option !== 'page_comments' ) {
45 exit( '-1' );
46 }
47
48 update_option( $option, 0 );
49 exit( '1' );
50 }
51
52 add_action( 'wp_ajax_wpseo_set_option', 'wpseo_set_option' );
53
54 /**
55 * Since 3.2 Notifications are dismissed in the Notification Center.
56 */
57 add_action( 'wp_ajax_yoast_dismiss_notification', [ 'Yoast_Notification_Center', 'ajax_dismiss_notification' ] );
58
59 /**
60 * Function used to remove the admin notices for several purposes, dies on exit.
61 *
62 * @return void
63 */
64 function wpseo_set_ignore() {
65 if ( ! current_user_can( 'manage_options' ) ) {
66 exit( '-1' );
67 }
68
69 check_ajax_referer( 'wpseo-ignore' );
70
71 if ( ! isset( $_POST['option'] ) || ! is_string( $_POST['option'] ) ) {
72 exit( '-1' );
73 }
74
75 $ignore_key = sanitize_text_field( wp_unslash( $_POST['option'] ) );
76 WPSEO_Options::set( 'ignore_' . $ignore_key, true );
77
78 exit( '1' );
79 }
80
81 add_action( 'wp_ajax_wpseo_set_ignore', 'wpseo_set_ignore' );
82
83 /**
84 * Save an individual SEO title from the Bulk Editor.
85 *
86 * @return void
87 */
88 function wpseo_save_title() {
89 wpseo_save_what( 'title' );
90 }
91
92 add_action( 'wp_ajax_wpseo_save_title', 'wpseo_save_title' );
93
94 /**
95 * Save an individual meta description from the Bulk Editor.
96 *
97 * @return void
98 */
99 function wpseo_save_description() {
100 wpseo_save_what( 'metadesc' );
101 }
102
103 add_action( 'wp_ajax_wpseo_save_metadesc', 'wpseo_save_description' );
104
105 /**
106 * Save titles & descriptions.
107 *
108 * @param string $what Type of item to save (title, description).
109 *
110 * @return void
111 */
112 function wpseo_save_what( $what ) {
113 check_ajax_referer( 'wpseo-bulk-editor' );
114
115 if ( ! isset( $_POST['new_value'], $_POST['wpseo_post_id'], $_POST['existing_value'] ) || ! is_string( $_POST['new_value'] ) || ! is_string( $_POST['existing_value'] ) ) {
116 exit( '-1' );
117 }
118
119 $new = sanitize_text_field( wp_unslash( $_POST['new_value'] ) );
120 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are casting the unsafe value to an integer.
121 $post_id = (int) wp_unslash( $_POST['wpseo_post_id'] );
122 $original = sanitize_text_field( wp_unslash( $_POST['existing_value'] ) );
123
124 if ( $post_id === 0 ) {
125 exit( '-1' );
126 }
127
128 $results = wpseo_upsert_new( $what, $post_id, $new, $original );
129
130 wpseo_ajax_json_echo_die( $results );
131 }
132
133 /**
134 * Helper function to update a post's meta data, returning relevant information
135 * about the information updated and the results or the meta update.
136 *
137 * @param int $post_id Post ID.
138 * @param string $new_meta_value New meta value to record.
139 * @param string $orig_meta_value Original meta value.
140 * @param string $meta_key Meta key string.
141 * @param string $return_key Return key string to use in results.
142 *
143 * @return array
144 */
145 function wpseo_upsert_meta( $post_id, $new_meta_value, $orig_meta_value, $meta_key, $return_key ) {
146
147 $post_id = (int) $post_id;
148 $sanitized_new_meta_value = wp_strip_all_tags( $new_meta_value );
149 $orig_meta_value = wp_strip_all_tags( $orig_meta_value );
150
151 $upsert_results = [
152 'status' => 'success',
153 'post_id' => $post_id,
154 "new_{$return_key}" => $sanitized_new_meta_value,
155 "original_{$return_key}" => $orig_meta_value,
156 ];
157
158 $the_post = get_post( $post_id );
159 if ( empty( $the_post ) ) {
160
161 $upsert_results['status'] = 'failure';
162 $upsert_results['results'] = __( 'Post doesn\'t exist.', 'wordpress-seo' );
163
164 return $upsert_results;
165 }
166
167 $post_type_object = get_post_type_object( $the_post->post_type );
168 if ( ! $post_type_object ) {
169
170 $upsert_results['status'] = 'failure';
171 $upsert_results['results'] = sprintf(
172 /* translators: %s expands to post type. */
173 __( 'Post has an invalid Content Type: %s.', 'wordpress-seo' ),
174 $the_post->post_type,
175 );
176
177 return $upsert_results;
178 }
179
180 if ( ! current_user_can( $post_type_object->cap->edit_posts ) ) {
181
182 $upsert_results['status'] = 'failure';
183 $upsert_results['results'] = sprintf(
184 /* translators: %s expands to post type name. */
185 __( 'You can\'t edit %s.', 'wordpress-seo' ),
186 $post_type_object->label,
187 );
188
189 return $upsert_results;
190 }
191
192 if ( ! current_user_can( $post_type_object->cap->edit_others_posts ) && (int) $the_post->post_author !== get_current_user_id() ) {
193
194 $upsert_results['status'] = 'failure';
195 $upsert_results['results'] = sprintf(
196 /* translators: %s expands to the name of a post type (plural). */
197 __( 'You can\'t edit %s that aren\'t yours.', 'wordpress-seo' ),
198 $post_type_object->label,
199 );
200
201 return $upsert_results;
202 }
203
204 if ( $sanitized_new_meta_value === $orig_meta_value && $sanitized_new_meta_value !== $new_meta_value ) {
205 $upsert_results['status'] = 'failure';
206 $upsert_results['results'] = __( 'You have used HTML in your value which is not allowed.', 'wordpress-seo' );
207
208 return $upsert_results;
209 }
210
211 $res = update_post_meta( $post_id, $meta_key, $sanitized_new_meta_value );
212
213 $upsert_results['status'] = ( $res !== false ) ? 'success' : 'failure';
214 $upsert_results['results'] = $res;
215
216 return $upsert_results;
217 }
218
219 /**
220 * Save all titles sent from the Bulk Editor.
221 *
222 * @return void
223 */
224 function wpseo_save_all_titles() {
225 wpseo_save_all( 'title' );
226 }
227
228 add_action( 'wp_ajax_wpseo_save_all_titles', 'wpseo_save_all_titles' );
229
230 /**
231 * Save all description sent from the Bulk Editor.
232 *
233 * @return void
234 */
235 function wpseo_save_all_descriptions() {
236 wpseo_save_all( 'metadesc' );
237 }
238
239 add_action( 'wp_ajax_wpseo_save_all_descriptions', 'wpseo_save_all_descriptions' );
240
241 /**
242 * Utility function to save values.
243 *
244 * @param string $what Type of item so save.
245 *
246 * @return void
247 */
248 function wpseo_save_all( $what ) {
249 check_ajax_referer( 'wpseo-bulk-editor' );
250
251 $results = [];
252 if ( ! isset( $_POST['items'], $_POST['existingItems'] ) ) {
253 wpseo_ajax_json_echo_die( $results );
254 }
255
256 $new_values = array_map( [ 'WPSEO_Utils', 'sanitize_text_field' ], wp_unslash( (array) $_POST['items'] ) );
257 $original_values = array_map( [ 'WPSEO_Utils', 'sanitize_text_field' ], wp_unslash( (array) $_POST['existingItems'] ) );
258
259 foreach ( $new_values as $post_id => $new_value ) {
260 $original_value = $original_values[ $post_id ];
261 $results[] = wpseo_upsert_new( $what, $post_id, $new_value, $original_value );
262 }
263
264 wpseo_ajax_json_echo_die( $results );
265 }
266
267 /**
268 * Insert a new value.
269 *
270 * @param string $what Item type (such as title).
271 * @param int $post_id Post ID.
272 * @param string $new_value New value to record.
273 * @param string $original Original value.
274 *
275 * @return string
276 */
277 function wpseo_upsert_new( $what, $post_id, $new_value, $original ) {
278 $meta_key = WPSEO_Meta::$meta_prefix . $what;
279
280 return wpseo_upsert_meta( $post_id, $new_value, $original, $meta_key, $what );
281 }
282
283 /**
284 * Retrieves the post ids where the keyword is used before as well as the types of those posts.
285 *
286 * @return void
287 */
288 function ajax_get_keyword_usage_and_post_types() {
289 check_ajax_referer( 'wpseo-keyword-usage-and-post-types', 'nonce' );
290
291 if ( ! isset( $_POST['post_id'], $_POST['keyword'] ) || ! is_string( $_POST['keyword'] ) ) {
292 exit( '-1' );
293 }
294
295 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We are casting to an integer.
296 $post_id = (int) wp_unslash( $_POST['post_id'] );
297
298 if ( $post_id === 0 || ! current_user_can( 'edit_post', $post_id ) ) {
299 exit( '-1' );
300 }
301
302 $keyword = sanitize_text_field( wp_unslash( $_POST['keyword'] ) );
303
304 $post_ids = WPSEO_Meta::keyword_usage( $keyword, $post_id );
305
306 $return_object = [
307 'keyword_usage' => $post_ids,
308 'post_types' => WPSEO_Meta::post_types_for_ids( $post_ids ),
309 ];
310
311 wp_die(
312 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
313 WPSEO_Utils::format_json_encode( $return_object ),
314 );
315 }
316
317 add_action( 'wp_ajax_get_focus_keyword_usage_and_post_types', 'ajax_get_keyword_usage_and_post_types' );
318
319 /**
320 * Retrieves the keyword for the keyword doubles of the termpages.
321 *
322 * @return void
323 */
324 function ajax_get_term_keyword_usage() {
325 check_ajax_referer( 'wpseo-keyword-usage', 'nonce' );
326
327 if ( ! isset( $_POST['post_id'], $_POST['keyword'], $_POST['taxonomy'] ) || ! is_string( $_POST['keyword'] ) || ! is_string( $_POST['taxonomy'] ) ) {
328 wp_die( -1 );
329 }
330
331 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are casting the unsafe input to an integer.
332 $post_id = (int) wp_unslash( $_POST['post_id'] );
333
334 if ( $post_id === 0 ) {
335 wp_die( -1 );
336 }
337
338 $keyword = sanitize_text_field( wp_unslash( $_POST['keyword'] ) );
339 $taxonomy_name = sanitize_text_field( wp_unslash( $_POST['taxonomy'] ) );
340
341 $taxonomy = get_taxonomy( $taxonomy_name );
342
343 if ( ! $taxonomy ) {
344 wp_die( 0 );
345 }
346
347 if ( ! current_user_can( $taxonomy->cap->edit_terms ) ) {
348 wp_die( -1 );
349 }
350
351 $usage = WPSEO_Taxonomy_Meta::get_keyword_usage( $keyword, $post_id, $taxonomy_name );
352
353 // Normalize the result so it is the same as the post keyword usage AJAX request.
354 $usage = $usage[ $keyword ];
355
356 wp_die(
357 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
358 WPSEO_Utils::format_json_encode( $usage ),
359 );
360 }
361
362 add_action( 'wp_ajax_get_term_keyword_usage', 'ajax_get_term_keyword_usage' );
363
364 /**
365 * Registers hooks for all AJAX integrations.
366 *
367 * @return void
368 */
369 function wpseo_register_ajax_integrations() {
370 $integrations = [ new Yoast_Network_Admin() ];
371
372 foreach ( $integrations as $integration ) {
373 $integration->register_ajax_hooks();
374 }
375 }
376
377 wpseo_register_ajax_integrations();
378
379 new WPSEO_Shortcode_Filter();
380
381 new WPSEO_Taxonomy_Columns();
382
383 /* ********************* DEPRECATED FUNCTIONS ********************* */
384
385 /**
386 * Retrieves the keyword for the keyword doubles.
387 *
388 * @return void
389 */
390 function ajax_get_keyword_usage() {
391 _deprecated_function( __METHOD__, 'WPSEO 20.4' );
392 check_ajax_referer( 'wpseo-keyword-usage', 'nonce' );
393
394 if ( ! isset( $_POST['post_id'], $_POST['keyword'] ) || ! is_string( $_POST['keyword'] ) ) {
395 exit( '-1' );
396 }
397
398 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We are casting to an integer.
399 $post_id = (int) wp_unslash( $_POST['post_id'] );
400
401 if ( $post_id === 0 || ! current_user_can( 'edit_post', $post_id ) ) {
402 exit( '-1' );
403 }
404
405 $keyword = sanitize_text_field( wp_unslash( $_POST['keyword'] ) );
406
407 wp_die(
408 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
409 WPSEO_Utils::format_json_encode( WPSEO_Meta::keyword_usage( $keyword, $post_id ) ),
410 );
411 }
412