PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.1
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.1
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 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 All 129 releases
wordpress-seo / admin / ajax.php

ajax.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.1, at admin/ajax.php

333 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 function wpseo_ajax_json_echo_die( $results ) {
20 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
21 echo WPSEO_Utils::format_json_encode( $results );
22 die();
23 }
24
25 /**
26 * Function used from AJAX calls, takes it variables from $_POST, dies on exit.
27 */
28 function wpseo_set_option() {
29 if ( ! current_user_can( 'manage_options' ) ) {
30 die( '-1' );
31 }
32
33 check_ajax_referer( 'wpseo-setoption' );
34
35 $option = sanitize_text_field( filter_input( INPUT_POST, 'option' ) );
36 if ( $option !== 'page_comments' ) {
37 die( '-1' );
38 }
39
40 update_option( $option, 0 );
41 die( '1' );
42 }
43
44 add_action( 'wp_ajax_wpseo_set_option', 'wpseo_set_option' );
45
46 /**
47 * Since 3.2 Notifications are dismissed in the Notification Center.
48 */
49 add_action( 'wp_ajax_yoast_dismiss_notification', [ 'Yoast_Notification_Center', 'ajax_dismiss_notification' ] );
50
51 /**
52 * Function used to remove the admin notices for several purposes, dies on exit.
53 */
54 function wpseo_set_ignore() {
55 if ( ! current_user_can( 'manage_options' ) ) {
56 die( '-1' );
57 }
58
59 check_ajax_referer( 'wpseo-ignore' );
60
61 $ignore_key = sanitize_text_field( filter_input( INPUT_POST, 'option' ) );
62 WPSEO_Options::set( 'ignore_' . $ignore_key, true );
63
64 die( '1' );
65 }
66
67 add_action( 'wp_ajax_wpseo_set_ignore', 'wpseo_set_ignore' );
68
69 /**
70 * Save an individual SEO title from the Bulk Editor.
71 */
72 function wpseo_save_title() {
73 wpseo_save_what( 'title' );
74 }
75
76 add_action( 'wp_ajax_wpseo_save_title', 'wpseo_save_title' );
77
78 /**
79 * Save an individual meta description from the Bulk Editor.
80 */
81 function wpseo_save_description() {
82 wpseo_save_what( 'metadesc' );
83 }
84
85 add_action( 'wp_ajax_wpseo_save_metadesc', 'wpseo_save_description' );
86
87 /**
88 * Save titles & descriptions.
89 *
90 * @param string $what Type of item to save (title, description).
91 */
92 function wpseo_save_what( $what ) {
93 check_ajax_referer( 'wpseo-bulk-editor' );
94
95 $new = filter_input( INPUT_POST, 'new_value' );
96 $post_id = intval( filter_input( INPUT_POST, 'wpseo_post_id' ) );
97 $original = filter_input( INPUT_POST, 'existing_value' );
98
99 $results = wpseo_upsert_new( $what, $post_id, $new, $original );
100
101 wpseo_ajax_json_echo_die( $results );
102 }
103
104 /**
105 * Helper function to update a post's meta data, returning relevant information
106 * about the information updated and the results or the meta update.
107 *
108 * @param int $post_id Post ID.
109 * @param string $new_meta_value New meta value to record.
110 * @param string $orig_meta_value Original meta value.
111 * @param string $meta_key Meta key string.
112 * @param string $return_key Return key string to use in results.
113 *
114 * @return string
115 */
116 function wpseo_upsert_meta( $post_id, $new_meta_value, $orig_meta_value, $meta_key, $return_key ) {
117
118 $post_id = intval( $post_id );
119 $sanitized_new_meta_value = wp_strip_all_tags( $new_meta_value );
120 $orig_meta_value = wp_strip_all_tags( $orig_meta_value );
121
122 $upsert_results = [
123 'status' => 'success',
124 'post_id' => $post_id,
125 "new_{$return_key}" => $sanitized_new_meta_value,
126 "original_{$return_key}" => $orig_meta_value,
127 ];
128
129 $the_post = get_post( $post_id );
130 if ( empty( $the_post ) ) {
131
132 $upsert_results['status'] = 'failure';
133 $upsert_results['results'] = __( 'Post doesn\'t exist.', 'wordpress-seo' );
134
135 return $upsert_results;
136 }
137
138 $post_type_object = get_post_type_object( $the_post->post_type );
139 if ( ! $post_type_object ) {
140
141 $upsert_results['status'] = 'failure';
142 $upsert_results['results'] = sprintf(
143 /* translators: %s expands to post type. */
144 __( 'Post has an invalid Content Type: %s.', 'wordpress-seo' ),
145 $the_post->post_type
146 );
147
148 return $upsert_results;
149 }
150
151 if ( ! current_user_can( $post_type_object->cap->edit_posts ) ) {
152
153 $upsert_results['status'] = 'failure';
154 $upsert_results['results'] = sprintf(
155 /* translators: %s expands to post type name. */
156 __( 'You can\'t edit %s.', 'wordpress-seo' ),
157 $post_type_object->label
158 );
159
160 return $upsert_results;
161 }
162
163 if ( ! current_user_can( $post_type_object->cap->edit_others_posts ) && (int) $the_post->post_author !== get_current_user_id() ) {
164
165 $upsert_results['status'] = 'failure';
166 $upsert_results['results'] = sprintf(
167 /* translators: %s expands to the name of a post type (plural). */
168 __( 'You can\'t edit %s that aren\'t yours.', 'wordpress-seo' ),
169 $post_type_object->label
170 );
171
172 return $upsert_results;
173 }
174
175 if ( $sanitized_new_meta_value === $orig_meta_value && $sanitized_new_meta_value !== $new_meta_value ) {
176 $upsert_results['status'] = 'failure';
177 $upsert_results['results'] = __( 'You have used HTML in your value which is not allowed.', 'wordpress-seo' );
178
179 return $upsert_results;
180 }
181
182 $res = update_post_meta( $post_id, $meta_key, $sanitized_new_meta_value );
183
184 $upsert_results['status'] = ( $res !== false ) ? 'success' : 'failure';
185 $upsert_results['results'] = $res;
186
187 return $upsert_results;
188 }
189
190 /**
191 * Save all titles sent from the Bulk Editor.
192 */
193 function wpseo_save_all_titles() {
194 wpseo_save_all( 'title' );
195 }
196
197 add_action( 'wp_ajax_wpseo_save_all_titles', 'wpseo_save_all_titles' );
198
199 /**
200 * Save all description sent from the Bulk Editor.
201 */
202 function wpseo_save_all_descriptions() {
203 wpseo_save_all( 'metadesc' );
204 }
205
206 add_action( 'wp_ajax_wpseo_save_all_descriptions', 'wpseo_save_all_descriptions' );
207
208 /**
209 * Utility function to save values.
210 *
211 * @param string $what Type of item so save.
212 */
213 function wpseo_save_all( $what ) {
214 check_ajax_referer( 'wpseo-bulk-editor' );
215
216 $results = [];
217 if ( ! isset( $_POST['items'], $_POST['existingItems'] ) ) {
218 wpseo_ajax_json_echo_die( $results );
219 }
220
221 $new_values = array_map( [ 'WPSEO_Utils', 'sanitize_text_field' ], wp_unslash( (array) $_POST['items'] ) );
222 $original_values = array_map( [ 'WPSEO_Utils', 'sanitize_text_field' ], wp_unslash( (array) $_POST['existingItems'] ) );
223
224 foreach ( $new_values as $post_id => $new_value ) {
225 $original_value = $original_values[ $post_id ];
226 $results[] = wpseo_upsert_new( $what, $post_id, $new_value, $original_value );
227 }
228
229 wpseo_ajax_json_echo_die( $results );
230 }
231
232 /**
233 * Insert a new value.
234 *
235 * @param string $what Item type (such as title).
236 * @param int $post_id Post ID.
237 * @param string $new_value New value to record.
238 * @param string $original Original value.
239 *
240 * @return string
241 */
242 function wpseo_upsert_new( $what, $post_id, $new_value, $original ) {
243 $meta_key = WPSEO_Meta::$meta_prefix . $what;
244
245 return wpseo_upsert_meta( $post_id, $new_value, $original, $meta_key, $what );
246 }
247
248 /**
249 * Retrieves the keyword for the keyword doubles.
250 */
251 function ajax_get_keyword_usage() {
252 $post_id = filter_input( INPUT_POST, 'post_id' );
253 $keyword = filter_input( INPUT_POST, 'keyword' );
254
255 if ( ! current_user_can( 'edit_post', $post_id ) ) {
256 die( '-1' );
257 }
258
259 wp_die(
260 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
261 WPSEO_Utils::format_json_encode( WPSEO_Meta::keyword_usage( $keyword, $post_id ) )
262 );
263 }
264
265 add_action( 'wp_ajax_get_focus_keyword_usage', 'ajax_get_keyword_usage' );
266
267 /**
268 * Retrieves the keyword for the keyword doubles of the termpages.
269 */
270 function ajax_get_term_keyword_usage() {
271 $post_id = filter_input( INPUT_POST, 'post_id' );
272 $keyword = filter_input( INPUT_POST, 'keyword' );
273 $taxonomy_name = filter_input( INPUT_POST, 'taxonomy' );
274
275 $taxonomy = get_taxonomy( $taxonomy_name );
276
277 if ( ! $taxonomy ) {
278 wp_die( 0 );
279 }
280
281 if ( ! current_user_can( $taxonomy->cap->edit_terms ) ) {
282 wp_die( -1 );
283 }
284
285 $usage = WPSEO_Taxonomy_Meta::get_keyword_usage( $keyword, $post_id, $taxonomy_name );
286
287 // Normalize the result so it it the same as the post keyword usage AJAX request.
288 $usage = $usage[ $keyword ];
289
290 wp_die(
291 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: WPSEO_Utils::format_json_encode is safe.
292 WPSEO_Utils::format_json_encode( $usage )
293 );
294 }
295
296 add_action( 'wp_ajax_get_term_keyword_usage', 'ajax_get_term_keyword_usage' );
297
298 /**
299 * Registers hooks for all AJAX integrations.
300 *
301 * @return void
302 */
303 function wpseo_register_ajax_integrations() {
304 $integrations = [ new Yoast_Network_Admin() ];
305
306 foreach ( $integrations as $integration ) {
307 $integration->register_ajax_hooks();
308 }
309 }
310
311 wpseo_register_ajax_integrations();
312
313 new WPSEO_Shortcode_Filter();
314
315 new WPSEO_Taxonomy_Columns();
316
317 /* ********************* DEPRECATED FUNCTIONS ********************* */
318
319 /**
320 * Hides the default tagline notice for a specific user.
321 *
322 * @deprecated 13.2
323 * @codeCoverageIgnore
324 */
325 function wpseo_dismiss_tagline_notice() {
326 if ( ! current_user_can( 'manage_options' ) ) {
327 die( '-1' );
328 }
329
330 _deprecated_function( __FUNCTION__, 'WPSEO 13.2', 'This method is deprecated.' );
331 wpseo_ajax_json_echo_die( '' );
332 }
333