*/
// Abort if this file is accessed directly.
if (!defined('ABSPATH')) {
exit;
}
class Metasync_Post_Meta_Settings
{
private $common;
public function __construct()
{
$this->common = new Metasync_Common();
add_action('admin_init', [$this, 'add_post_meta_data'], 2);
add_action('save_post', [$this, 'common_robots_meta_box_save']);
add_action('save_post', [$this, 'advance_robots_meta_box_save']);
add_action('save_post', [$this, 'redirection_meta_box_save']);
add_action('save_post', [$this, 'canonical_meta_box_save']);
add_action('save_post', [$this, 'video_sitemap_meta_box_save']);
}
public function add_post_meta_data()
{
// Don't show meta boxes if user's role doesn't have plugin access
if (!Metasync::current_user_has_plugin_access()) {
return;
}
$plugin_name = Metasync::get_effective_plugin_name();
$general_settings = Metasync::get_option('general', []);
$post_types = array_values(get_post_types(['public' => true], 'names'));
$post_types = array_diff($post_types, ['attachment']);
// Only add meta boxes if not disabled in settings
if (empty($general_settings['disable_common_robots_metabox'])) {
add_meta_box('common-robots-meta', "Common Robots Meta by $plugin_name", [$this, 'common_robots_meta_box_display'], $post_types, 'normal', 'default');
}
if (empty($general_settings['disable_advance_robots_metabox'])) {
add_meta_box('advance-robots-meta', "Advance Robots Meta by $plugin_name", [$this, 'advance_robots_meta_box_display'], $post_types, 'normal', 'default');
}
if (empty($general_settings['disable_redirection_metabox'])) {
add_meta_box('post-redirection-meta', "Redirection by $plugin_name", [$this, 'post_redirection_display'], $post_types, 'normal', 'default');
}
if (empty($general_settings['disable_canonical_metabox'])) {
add_meta_box('post-canonical-meta', "Canonical by $plugin_name", [$this, 'post_canonical_display'], $post_types, 'normal', 'default');
}
// Video Sitemap meta box — only if video sitemap is enabled
$video_settings = get_option('metasync_video_sitemap_settings', []);
if (!empty($video_settings['enabled'])) {
$video_post_types = !empty($video_settings['post_types']) ? (array) $video_settings['post_types'] : ['post', 'page'];
add_meta_box(
'metasync-video-sitemap-meta',
"Video Sitemap by $plugin_name",
[$this, 'video_sitemap_meta_box_display'],
$video_post_types,
'normal',
'default'
);
}
}
public function common_robots_meta_box_display()
{
global $post;
$post_meta_robots = get_post_meta($post->ID, 'metasync_common_robots', true);
// Check new spelling first, fall back to old for backward compatibility
$common_meta_robots = Metasync::get_option('common_robots_meta') ?? Metasync::get_option('common_robots_mata') ?? '';
$common_robots = $post_meta_robots ? $post_meta_robots : $common_meta_robots;
wp_nonce_field('metasync_common_robots_nonce', 'metasync_common_robots_nonce');
?>
ID, 'metasync_advance_robots', true);
// Check new spelling first, fall back to old for backward compatibility
$common_meta_robots = Metasync::get_option('advance_robots_meta') ?? Metasync::get_option('advance_robots_mata') ?? '';
$advance_robots = $post_meta_robots ? $post_meta_robots : $common_meta_robots;
$snippet_advance_robots_enable = $advance_robots['max-snippet']['enable'] ?? '';
$snippet_advance_robots_length = $advance_robots['max-snippet']['length'] ?? '';
$video_advance_robots_enable = $advance_robots['max-video-preview']['enable'] ?? '';
$video_advance_robots_length = $advance_robots['max-video-preview']['length'] ?? '';
$image_advance_robots_enable = $advance_robots['max-image-preview']['enable'] ?? '';
$image_advance_robots_length = $advance_robots['max-image-preview']['length'] ?? '';
wp_nonce_field('metasync_advance_robots_nonce', 'metasync_advance_robots_nonce');
?>
ID, 'metasync_post_redirection_meta', true) ?? '';
$enable = $post_redirection['enable'] ?? '';
$type = $post_redirection['type'] ?? '';
$url = $post_redirection['url'] ?? '';
wp_nonce_field('metasync_post_redirection_nonce', 'metasync_post_redirection_nonce');
?>
ID, 'meta_canonical', true) ?? '';
// Fix legacy array values stored by sanitize_array()
if (is_array($post_canonical)) {
$post_canonical = reset($post_canonical) ?: '';
// Repair the stored value so it won't recur
if (!empty($post_canonical)) {
update_post_meta($post->ID, 'meta_canonical', (string) $post_canonical);
}
}
wp_nonce_field('metasync_post_canonical_nonce', 'metasync_post_canonical_nonce');
?>
common->sanitize_array($post_data[$field_name]);
}
if (!empty($common_robots))
update_post_meta($post_id, 'metasync_common_robots', $common_robots);
elseif (empty($common_robots) && $old_common_robots)
delete_post_meta($post_id, 'metasync_common_robots', $old_common_robots);
}
public function advance_robots_meta_box_save($post_id)
{
if (!current_user_can('edit_post', $post_id))
return;
// WP-197: When saving from Gutenberg (REST API context) and the sidebar
// JSON exists, skip — the sidebar auto-save is the source of truth.
if (defined('REST_REQUEST') && REST_REQUEST && !empty(get_post_meta($post_id, '_metasync_robots_advanced', true))) {
return;
}
$post_data = metasync_sanitize_input_array($_POST);
// Check for new field name first, then old for backward compatibility
$field_name = isset($post_data['advanced_robots_meta']) ? 'advanced_robots_meta' : 'advanced_robots_mata';
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'))
return;
$old_advance_robots = get_post_meta($post_id, 'metasync_advance_robots', true);
$advance_robots = $this->common->sanitize_array($post_data[$field_name]);
if (!empty($advance_robots))
update_post_meta($post_id, 'metasync_advance_robots', $advance_robots);
elseif (empty($advance_robots) && $old_advance_robots)
delete_post_meta($post_id, 'metasync_advance_robots', $old_advance_robots);
}
public function redirection_meta_box_save($post_id)
{
if (!current_user_can('edit_post', $post_id))
return;
$post_data = metasync_sanitize_input_array($_POST);
// Check for new field name first, then old for backward compatibility
$field_name = isset($post_data['post_redirect_meta']) ? 'post_redirect_meta' : 'post_redirect_mata';
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'))
return;
$old_post_redirection_meta = get_post_meta($post_id, 'metasync_post_redirection_meta', true);
$post_redirection_meta = $this->common->sanitize_array($post_data[$field_name]);
if (isset($post_redirection_meta['enable']))
update_post_meta($post_id, 'metasync_post_redirection_meta', $post_redirection_meta);
else
delete_post_meta($post_id, 'metasync_post_redirection_meta', $old_post_redirection_meta);
}
public function canonical_meta_box_save($post_id)
{
if (!current_user_can('edit_post', $post_id))
return;
$post_data = metasync_sanitize_input_array($_POST);
// Check for new field name first, then old for backward compatibility
$field_name = isset($post_data['post_canonical_url_meta']) ? 'post_canonical_url_meta' : 'post_canonical_url_mata';
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'))
return;
$old_post_canonical_meta = get_post_meta($post_id, 'meta_canonical', true);
// Canonical is a URL string — sanitize as URL, not array
$raw_value = $post_data[$field_name];
if (is_array($raw_value)) {
$raw_value = reset($raw_value); // extract first element if array
}
$post_canonical_meta = esc_url_raw(trim((string) $raw_value));
if (!empty($post_canonical_meta))
update_post_meta($post_id, 'meta_canonical', $post_canonical_meta);
else
delete_post_meta($post_id, 'meta_canonical', $old_post_canonical_meta);
}
public function show_top_admin_bar() {
if ( Metasync::current_user_has_plugin_access() ) {
show_admin_bar( true );
}
}
/**
* Display the Video Sitemap meta box in post editor.
*/
public function video_sitemap_meta_box_display()
{
global $post;
$video_url = get_post_meta($post->ID, '_metasync_video_url', true);
$video_thumbnail = get_post_meta($post->ID, '_metasync_video_thumbnail', true);
$video_title = get_post_meta($post->ID, '_metasync_video_title', true);
$video_desc = get_post_meta($post->ID, '_metasync_video_description', true);
$video_duration = get_post_meta($post->ID, '_metasync_video_duration', true);
wp_nonce_field('metasync_video_sitemap_meta_nonce', 'metasync_video_sitemap_meta_nonce');
?>
'_metasync_video_url',
'metasync_video_thumbnail' => '_metasync_video_thumbnail',
'metasync_video_title' => '_metasync_video_title',
'metasync_video_description' => '_metasync_video_description',
'metasync_video_duration' => '_metasync_video_duration',
];
foreach ($fields as $form_key => $meta_key) {
if (!isset($_POST[$form_key])) {
continue;
}
$value = $_POST[$form_key];
// Sanitize per field type
if (in_array($meta_key, ['_metasync_video_url', '_metasync_video_thumbnail'], true)) {
$value = esc_url_raw($value);
} elseif ($meta_key === '_metasync_video_duration') {
$value = absint($value);
$value = $value > 0 ? $value : '';
} elseif ($meta_key === '_metasync_video_description') {
$value = sanitize_textarea_field($value);
} else {
$value = sanitize_text_field($value);
}
if (!empty($value)) {
update_post_meta($post_id, $meta_key, $value);
} else {
delete_post_meta($post_id, $meta_key);
}
}
}
}