PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.10
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.10
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / admin / class-metasync-post-meta-setting.php

class-metasync-post-meta-setting.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.10, at admin/class-metasync-post-meta-setting.php

463 lines 19.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The header and footer code snippets functionality of the plugin.
5 *
6 *
7 * @link https://searchatlas.com
8 * @since 1.0.0
9 * @package Metasync
10 * @subpackage Metasync/admin
11 * @author Engineering Team <support@searchatlas.com>
12 */
13
14 // Abort if this file is accessed directly.
15 if (!defined('ABSPATH')) {
16 exit;
17 }
18
19 class Metasync_Post_Meta_Settings
20 {
21 private $common;
22
23 public function __construct()
24 {
25 $this->common = new Metasync_Common();
26
27 add_action('admin_init', [$this, 'add_post_meta_data'], 2);
28 add_action('save_post', [$this, 'common_robots_meta_box_save']);
29 add_action('save_post', [$this, 'advance_robots_meta_box_save']);
30 add_action('save_post', [$this, 'redirection_meta_box_save']);
31 add_action('save_post', [$this, 'canonical_meta_box_save']);
32 add_action('save_post', [$this, 'video_sitemap_meta_box_save']);
33 }
34
35 public function add_post_meta_data()
36 {
37 // Don't show meta boxes if user's role doesn't have plugin access
38 if (!Metasync::current_user_has_plugin_access()) {
39 return;
40 }
41
42 $plugin_name = Metasync::get_effective_plugin_name();
43 $general_settings = Metasync::get_option('general', []);
44 $post_types = array_values(get_post_types(['public' => true], 'names'));
45 $post_types = array_diff($post_types, ['attachment']);
46
47 // Only add meta boxes if not disabled in settings
48 if (empty($general_settings['disable_common_robots_metabox'])) {
49 add_meta_box('common-robots-meta', "Common Robots Meta by $plugin_name", [$this, 'common_robots_meta_box_display'], $post_types, 'normal', 'default');
50 }
51
52 if (empty($general_settings['disable_advance_robots_metabox'])) {
53 add_meta_box('advance-robots-meta', "Advance Robots Meta by $plugin_name", [$this, 'advance_robots_meta_box_display'], $post_types, 'normal', 'default');
54 }
55
56 if (empty($general_settings['disable_redirection_metabox'])) {
57 add_meta_box('post-redirection-meta', "Redirection by $plugin_name", [$this, 'post_redirection_display'], $post_types, 'normal', 'default');
58 }
59
60 if (empty($general_settings['disable_canonical_metabox'])) {
61 add_meta_box('post-canonical-meta', "Canonical by $plugin_name", [$this, 'post_canonical_display'], $post_types, 'normal', 'default');
62 }
63
64 // Video Sitemap meta box — only if video sitemap is enabled
65 $video_settings = get_option('metasync_video_sitemap_settings', []);
66 if (!empty($video_settings['enabled'])) {
67 $video_post_types = !empty($video_settings['post_types']) ? (array) $video_settings['post_types'] : ['post', 'page'];
68 add_meta_box(
69 'metasync-video-sitemap-meta',
70 "Video Sitemap by $plugin_name",
71 [$this, 'video_sitemap_meta_box_display'],
72 $video_post_types,
73 'normal',
74 'default'
75 );
76 }
77 }
78
79 public function common_robots_meta_box_display()
80 {
81 global $post;
82 $post_meta_robots = get_post_meta($post->ID, 'metasync_common_robots', true);
83 // Check new spelling first, fall back to old for backward compatibility
84 $common_meta_robots = Metasync::get_option('common_robots_meta') ?? Metasync::get_option('common_robots_mata') ?? '';
85 $common_robots = $post_meta_robots ? $post_meta_robots : $common_meta_robots;
86 wp_nonce_field('metasync_common_robots_nonce', 'metasync_common_robots_nonce');
87 ?>
88 <ul class="checkbox-list">
89 <li>
90 <input type="checkbox" name="common_robots_meta[index]" id="robots_common1" value="index" <?php isset($common_robots['index']) ? checked('index', $common_robots['index']) : '' ?>>
91 <label for="robots_common1">Index </br>
92 <span class="description">
93 <span>Search engines to index and show these pages in the search results.</span>
94 </span>
95 </label>
96 </li>
97 <li>
98 <input type="checkbox" name="common_robots_meta[noindex]" id="robots_common2" value="noindex" <?php isset($common_robots['noindex']) ? checked('noindex', $common_robots['noindex']) : '' ?>>
99 <label for="robots_common2">No Index </br>
100 <span class="description">
101 <span>Prevents search engines from indexing and displaying these pages in search results.</span>
102 </span>
103 </label>
104 </li>
105 <li>
106 <input type="checkbox" name="common_robots_meta[nofollow]" id="robots_common3" value="nofollow" <?php isset($common_robots['nofollow']) ? checked('nofollow', $common_robots['nofollow']) : '' ?>>
107 <label for="robots_common3">No Follow </br>
108 <span class="description">
109 <span>Prevents search engines from following the links on the pages.</span>
110 </span>
111 </label>
112 </li>
113 <li>
114 <input type="checkbox" name="common_robots_meta[noarchive]" id="robots_common4" value="noarchive" <?php isset($common_robots['noarchive']) ? checked('noarchive', $common_robots['noarchive']) : '' ?>>
115 <label for="robots_common4">No Archive </br>
116 <span class="description">
117 <span>Prevents search engines from showing cached links for pages.</span>
118 </span>
119 </label>
120 </li>
121 <li>
122 <input type="checkbox" name="common_robots_meta[noimageindex]" id="robots_common5" value="noimageindex" <?php isset($common_robots['noimageindex']) ? checked('noimageindex', $common_robots['noimageindex']) : '' ?>>
123 <label for="robots_common5">No Image Index </br>
124 <span class="description">
125 <span>Prevents your pages from appearing as the referring page for images in image search results.</span>
126 </span>
127 </label>
128 </li>
129 <li>
130 <input type="checkbox" name="common_robots_meta[nosnippet]" id="robots_common6" value="nosnippet" <?php isset($common_robots['nosnippet']) ? checked('nosnippet', $common_robots['nosnippet']) : '' ?>>
131 <label for="robots_common6">No Snippet </br>
132 <span class="description">
133 <span>Prevents search engines from showing a snippet in the search results.</span>
134 </span>
135 </label>
136 </li>
137 </ul>
138
139 <?php
140 }
141
142 public function advance_robots_meta_box_display()
143 {
144 global $post;
145 $post_meta_robots = get_post_meta($post->ID, 'metasync_advance_robots', true);
146 // Check new spelling first, fall back to old for backward compatibility
147 $common_meta_robots = Metasync::get_option('advance_robots_meta') ?? Metasync::get_option('advance_robots_mata') ?? '';
148 $advance_robots = $post_meta_robots ? $post_meta_robots : $common_meta_robots;
149 $snippet_advance_robots_enable = $advance_robots['max-snippet']['enable'] ?? '';
150 $snippet_advance_robots_length = $advance_robots['max-snippet']['length'] ?? '';
151 $video_advance_robots_enable = $advance_robots['max-video-preview']['enable'] ?? '';
152 $video_advance_robots_length = $advance_robots['max-video-preview']['length'] ?? '';
153 $image_advance_robots_enable = $advance_robots['max-image-preview']['enable'] ?? '';
154 $image_advance_robots_length = $advance_robots['max-image-preview']['length'] ?? '';
155 wp_nonce_field('metasync_advance_robots_nonce', 'metasync_advance_robots_nonce');
156 ?>
157 <ul class="checkbox-list">
158 <li>
159 <label for="advanced_robots_snippet">
160 <input type="checkbox" name="advanced_robots_meta[max-snippet][enable]" id="advanced_robots_snippet" value="1" <?php checked('1', esc_attr($snippet_advance_robots_enable)) ?>>
161 Snippet </br>
162 <input type="number" class="input-length" name="advanced_robots_meta[max-snippet][length]" id="advanced_robots_snippet_value" value="<?php echo esc_attr($snippet_advance_robots_length); ?>" min="-1"> </br>
163 <span class="description">
164 <span>Add maximum text-length, in characters, of a snippet for your page.</span>
165 </span>
166 </label>
167 </li>
168 <li>
169 <label for="advanced_robots_video">
170 <input type="checkbox" name="advanced_robots_meta[max-video-preview][enable]" id="advanced_robots_video" value="1" <?php checked('1', esc_attr($video_advance_robots_enable)) ?>>
171 Video Preview </br>
172 <input type="number" class="input-length" name="advanced_robots_meta[max-video-preview][length]" id="advanced_robots_video_value" value="<?php echo esc_attr($video_advance_robots_length); ?>" min="-1"> </br>
173 <span class="description">
174 <span>Add maximum duration in seconds of an animated video preview.</span>
175 </span>
176 </label>
177 </li>
178 <li>
179 <label for="advanced_robots_image">
180 <input type="checkbox" name="advanced_robots_meta[max-image-preview][enable]" id="advanced_robots_image" value="1" <?php checked('1', esc_attr($image_advance_robots_enable)) ?>>
181 Image Preview </br>
182 <select class="input-length" name="advanced_robots_meta[max-image-preview][length]' ?>" id="advanced_robots_image_value">
183 <option value="large" <?php selected(esc_attr($image_advance_robots_length), 'large'); ?>>Large</option>
184 <option value="standard" <?php selected(esc_attr($image_advance_robots_length), 'standard'); ?>>Standard</option>
185 <option value="none" <?php selected(esc_attr($image_advance_robots_length), 'none'); ?>>None</option>
186 </select>
187 </br>
188 <span class="description">
189 <span>Add maximum size of image preview to show the images on this page.</span>
190 </span>
191 </label>
192 </li>
193 </ul>
194 <?php
195 }
196
197 public function post_redirection_display()
198 {
199 global $post;
200 $post_redirection = get_post_meta($post->ID, 'metasync_post_redirection_meta', true) ?? '';
201 $enable = $post_redirection['enable'] ?? '';
202 $type = $post_redirection['type'] ?? '';
203 $url = $post_redirection['url'] ?? '';
204 wp_nonce_field('metasync_post_redirection_nonce', 'metasync_post_redirection_nonce');
205 ?>
206 <ul class="checkbox-list">
207 <li>
208 <input type="checkbox" name="post_redirect_meta[enable]" id="post_redirection" value="true" <?php checked('true', esc_attr($enable)); ?>>
209 <label for="post_redirection">Redirection</label>
210 </li>
211 <li class="hide"> Redirection Type:
212 <select class="regular-text" name="post_redirect_meta[type]" id="post_redirection_type">
213 <option value="301" <?php selected(esc_attr($type), '301'); ?>>301 Permanent Move</option>
214 <option value="302" <?php selected(esc_attr($type), '302'); ?>>302 Temporary Move</option>
215 <option value="307" <?php selected(esc_attr($type), '307'); ?>>307 Temporary Redirect</option>
216 <option value="410" <?php selected(esc_attr($type), '410'); ?>>410 Content Deleted</option>
217 <option value="451" <?php selected(esc_attr($type), '451'); ?>>451 Content Unavailable</option>
218 </select>
219 </li>
220 <li class="hide" id="post_redirect_url"> Destination URL:
221 <input type="text" class="regular-text" name="post_redirect_meta[url]" id="post_redirect_url_val" value="<?php echo esc_attr($url); ?>">
222 </li>
223 </ul>
224 <?php
225 }
226
227 public function post_canonical_display()
228 {
229 global $post;
230
231 $post_canonical = get_post_meta($post->ID, 'meta_canonical', true) ?? '';
232 // Fix legacy array values stored by sanitize_array()
233 if (is_array($post_canonical)) {
234 $post_canonical = reset($post_canonical) ?: '';
235 // Repair the stored value so it won't recur
236 if (!empty($post_canonical)) {
237 update_post_meta($post->ID, 'meta_canonical', (string) $post_canonical);
238 }
239 }
240 wp_nonce_field('metasync_post_canonical_nonce', 'metasync_post_canonical_nonce');
241 ?>
242 <ul>
243 <li> Canonical URL:
244 <input type="text" class="regular-text" name="post_canonical_url_meta" placeholder="<?php echo get_permalink($post->ID) ?>" value="<?php echo esc_attr($post_canonical); ?>">
245 </li>
246 </ul>
247 <?php
248 }
249
250 public function common_robots_meta_box_save($post_id)
251 {
252 if (!current_user_can('edit_post', $post_id))
253 return;
254
255 // WP-197: When saving from Gutenberg (REST API context) and the sidebar
256 // JSON exists, skip — the sidebar auto-save is the source of truth.
257 // Classic editor form submits (non-REST) always proceed so classic-only
258 // users can still save via the meta boxes.
259 if (defined('REST_REQUEST') && REST_REQUEST && !empty(get_post_meta($post_id, '_metasync_robots_advanced', true))) {
260 return;
261 }
262
263 $post_data = metasync_sanitize_input_array($_POST);
264 // Check for new field name first, then old for backward compatibility
265 $field_name = isset($post_data['common_robots_meta']) ? 'common_robots_meta' : 'common_robots_mata';
266
267 if (!isset($post_data['metasync_common_robots_nonce'], $post_data[$field_name]) || !wp_verify_nonce($post_data['metasync_common_robots_nonce'], 'metasync_common_robots_nonce'))
268 return;
269
270 $old_common_robots = get_post_meta($post_id, 'metasync_common_robots', true);
271
272 $common_robots = [];
273 if (!empty($post_data[$field_name])) {
274 $common_robots = $this->common->sanitize_array($post_data[$field_name]);
275 }
276
277 if (!empty($common_robots))
278 update_post_meta($post_id, 'metasync_common_robots', $common_robots);
279 elseif (empty($common_robots) && $old_common_robots)
280 delete_post_meta($post_id, 'metasync_common_robots', $old_common_robots);
281 }
282
283 public function advance_robots_meta_box_save($post_id)
284 {
285 if (!current_user_can('edit_post', $post_id))
286 return;
287
288 // WP-197: When saving from Gutenberg (REST API context) and the sidebar
289 // JSON exists, skip — the sidebar auto-save is the source of truth.
290 if (defined('REST_REQUEST') && REST_REQUEST && !empty(get_post_meta($post_id, '_metasync_robots_advanced', true))) {
291 return;
292 }
293
294 $post_data = metasync_sanitize_input_array($_POST);
295 // Check for new field name first, then old for backward compatibility
296 $field_name = isset($post_data['advanced_robots_meta']) ? 'advanced_robots_meta' : 'advanced_robots_mata';
297
298 if (!isset($post_data['metasync_advance_robots_nonce'], $post_data[$field_name]) || !wp_verify_nonce($post_data['metasync_advance_robots_nonce'], 'metasync_advance_robots_nonce'))
299 return;
300
301 $old_advance_robots = get_post_meta($post_id, 'metasync_advance_robots', true);
302
303 $advance_robots = $this->common->sanitize_array($post_data[$field_name]);
304
305 if (!empty($advance_robots))
306 update_post_meta($post_id, 'metasync_advance_robots', $advance_robots);
307 elseif (empty($advance_robots) && $old_advance_robots)
308 delete_post_meta($post_id, 'metasync_advance_robots', $old_advance_robots);
309 }
310
311 public function redirection_meta_box_save($post_id)
312 {
313 if (!current_user_can('edit_post', $post_id))
314 return;
315
316 $post_data = metasync_sanitize_input_array($_POST);
317 // Check for new field name first, then old for backward compatibility
318 $field_name = isset($post_data['post_redirect_meta']) ? 'post_redirect_meta' : 'post_redirect_mata';
319
320 if (!isset($post_data['metasync_post_redirection_nonce'], $post_data[$field_name]) || !wp_verify_nonce($post_data['metasync_post_redirection_nonce'], 'metasync_post_redirection_nonce'))
321 return;
322
323 $old_post_redirection_meta = get_post_meta($post_id, 'metasync_post_redirection_meta', true);
324
325 $post_redirection_meta = $this->common->sanitize_array($post_data[$field_name]);
326
327 if (isset($post_redirection_meta['enable']))
328 update_post_meta($post_id, 'metasync_post_redirection_meta', $post_redirection_meta);
329 else
330 delete_post_meta($post_id, 'metasync_post_redirection_meta', $old_post_redirection_meta);
331 }
332
333 public function canonical_meta_box_save($post_id)
334 {
335 if (!current_user_can('edit_post', $post_id))
336 return;
337
338 $post_data = metasync_sanitize_input_array($_POST);
339 // Check for new field name first, then old for backward compatibility
340 $field_name = isset($post_data['post_canonical_url_meta']) ? 'post_canonical_url_meta' : 'post_canonical_url_mata';
341
342 if (!isset($post_data['metasync_post_canonical_nonce'], $post_data[$field_name]) || !wp_verify_nonce($post_data['metasync_post_canonical_nonce'], 'metasync_post_canonical_nonce'))
343 return;
344
345 $old_post_canonical_meta = get_post_meta($post_id, 'meta_canonical', true);
346
347 // Canonical is a URL string — sanitize as URL, not array
348 $raw_value = $post_data[$field_name];
349 if (is_array($raw_value)) {
350 $raw_value = reset($raw_value); // extract first element if array
351 }
352 $post_canonical_meta = esc_url_raw(trim((string) $raw_value));
353
354 if (!empty($post_canonical_meta))
355 update_post_meta($post_id, 'meta_canonical', $post_canonical_meta);
356 else
357 delete_post_meta($post_id, 'meta_canonical', $old_post_canonical_meta);
358 }
359
360 public function show_top_admin_bar() {
361 if ( Metasync::current_user_has_plugin_access() ) {
362 show_admin_bar( true );
363 }
364 }
365
366 /**
367 * Display the Video Sitemap meta box in post editor.
368 */
369 public function video_sitemap_meta_box_display()
370 {
371 global $post;
372 $video_url = get_post_meta($post->ID, '_metasync_video_url', true);
373 $video_thumbnail = get_post_meta($post->ID, '_metasync_video_thumbnail', true);
374 $video_title = get_post_meta($post->ID, '_metasync_video_title', true);
375 $video_desc = get_post_meta($post->ID, '_metasync_video_description', true);
376 $video_duration = get_post_meta($post->ID, '_metasync_video_duration', true);
377
378 wp_nonce_field('metasync_video_sitemap_meta_nonce', 'metasync_video_sitemap_meta_nonce');
379 ?>
380 <p style="color: #666; margin-bottom: 12px;">
381 <?php esc_html_e('Override auto-detected video data for this post. Leave fields empty to use auto-detection.', 'metasync'); ?>
382 </p>
383 <table class="form-table" style="margin: 0;">
384 <tr>
385 <th scope="row"><label for="metasync_video_url"><?php esc_html_e('Video URL', 'metasync'); ?></label></th>
386 <td><input type="url" id="metasync_video_url" name="metasync_video_url" value="<?php echo esc_attr($video_url); ?>" class="large-text" placeholder="https://www.youtube.com/watch?v=..." /></td>
387 </tr>
388 <tr>
389 <th scope="row"><label for="metasync_video_thumbnail"><?php esc_html_e('Thumbnail URL', 'metasync'); ?></label></th>
390 <td><input type="url" id="metasync_video_thumbnail" name="metasync_video_thumbnail" value="<?php echo esc_attr($video_thumbnail); ?>" class="large-text" placeholder="https://img.youtube.com/vi/.../hqdefault.jpg" /></td>
391 </tr>
392 <tr>
393 <th scope="row"><label for="metasync_video_title"><?php esc_html_e('Video Title', 'metasync'); ?></label></th>
394 <td><input type="text" id="metasync_video_title" name="metasync_video_title" value="<?php echo esc_attr($video_title); ?>" class="large-text" placeholder="<?php esc_attr_e('Defaults to post title', 'metasync'); ?>" /></td>
395 </tr>
396 <tr>
397 <th scope="row"><label for="metasync_video_description"><?php esc_html_e('Video Description', 'metasync'); ?></label></th>
398 <td><textarea id="metasync_video_description" name="metasync_video_description" class="large-text" rows="3" placeholder="<?php esc_attr_e('Defaults to post excerpt', 'metasync'); ?>"><?php echo esc_textarea($video_desc); ?></textarea></td>
399 </tr>
400 <tr>
401 <th scope="row"><label for="metasync_video_duration"><?php esc_html_e('Duration (seconds)', 'metasync'); ?></label></th>
402 <td><input type="number" id="metasync_video_duration" name="metasync_video_duration" value="<?php echo esc_attr($video_duration); ?>" class="small-text" min="0" step="1" placeholder="300" /></td>
403 </tr>
404 </table>
405 <?php
406 }
407
408 /**
409 * Save the Video Sitemap meta box data.
410 *
411 * @param int $post_id The post ID.
412 */
413 public function video_sitemap_meta_box_save($post_id)
414 {
415 if (!isset($_POST['metasync_video_sitemap_meta_nonce']) ||
416 !wp_verify_nonce($_POST['metasync_video_sitemap_meta_nonce'], 'metasync_video_sitemap_meta_nonce')) {
417 return;
418 }
419
420 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
421 return;
422 }
423
424 if (!current_user_can('edit_post', $post_id)) {
425 return;
426 }
427
428 $fields = [
429 'metasync_video_url' => '_metasync_video_url',
430 'metasync_video_thumbnail' => '_metasync_video_thumbnail',
431 'metasync_video_title' => '_metasync_video_title',
432 'metasync_video_description' => '_metasync_video_description',
433 'metasync_video_duration' => '_metasync_video_duration',
434 ];
435
436 foreach ($fields as $form_key => $meta_key) {
437 if (!isset($_POST[$form_key])) {
438 continue;
439 }
440
441 $value = $_POST[$form_key];
442
443 // Sanitize per field type
444 if (in_array($meta_key, ['_metasync_video_url', '_metasync_video_thumbnail'], true)) {
445 $value = esc_url_raw($value);
446 } elseif ($meta_key === '_metasync_video_duration') {
447 $value = absint($value);
448 $value = $value > 0 ? $value : '';
449 } elseif ($meta_key === '_metasync_video_description') {
450 $value = sanitize_textarea_field($value);
451 } else {
452 $value = sanitize_text_field($value);
453 }
454
455 if (!empty($value)) {
456 update_post_meta($post_id, $meta_key, $value);
457 } else {
458 delete_post_meta($post_id, $meta_key);
459 }
460 }
461 }
462 }
463