| @@ -46,9 +46,15 @@ | ||
| 46 | 46 | // Accordion / Section helpers |
| 47 | 47 | // ──────────────────────────────────────────────────────────────── |
| 48 | 48 | |
| 49 | 49 | public function get_accordion_sections_config() { |
| 50 | - return array( | |
| 50 | + // Consent switch for writing into other SEO plugins. Loaded here rather | |
| 51 | + // than through the committed classmap so a stale autoload map can never | |
| 52 | + // make the switch — and with it the user's only way to stop those | |
| 53 | + // writes — silently disappear from the page. | |
| 54 | + require_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-metasync-seo-sync-settings.php'; | |
| 55 | + | |
| 56 | + $sections = array( | |
| 51 | 57 | 'connection' => array( |
| 52 | 58 | 'title' => 'Connection & Authentication', |
| 53 | 59 | 'description' => 'Manage your API connection and authentication settings', |
| 54 | 60 | 'icon' => 'admin-network', |
| @@ -68,8 +74,9 @@ | ||
| 68 | 74 | 'fields' => array( |
| 69 | 75 | 'otto_pixel_uuid', |
| 70 | 76 | 'otto_disable_on_loggedin', |
| 71 | 77 | 'otto_disable_preview_button', |
| 78 | + 'seo_priority', | |
| 72 | 79 | 'otto_wp_rocket_compat', |
| 73 | 80 | 'otto_sg_optimizer_compat', |
| 74 | 81 | 'bookingpress_session_compat', |
| 75 | 82 | ) |
| @@ -81,8 +88,16 @@ | ||
| 81 | 88 | 'priority' => 22, |
| 82 | 89 | 'default_open' => false, |
| 83 | 90 | 'render_callback' => array('Metasync_Edge_Cache_Settings', 'render'), |
| 84 | 91 | ), |
| 92 | + 'seo_plugin_sync' => array( | |
| 93 | + 'title' => 'Sync to Other SEO Plugins', | |
| 94 | + 'description' => 'Control whether ' . Metasync::get_whitelabel_otto_name() . '\'s SEO values are written into Yoast, Rank Math or All in One SEO', | |
| 95 | + 'icon' => 'update', | |
| 96 | + 'priority' => 23, | |
| 97 | + 'default_open' => false, | |
| 98 | + 'render_callback' => array('Metasync_Seo_Sync_Settings', 'render'), | |
| 99 | + ), | |
| 85 | 100 | 'bot_detection' => array( |
| 86 | 101 | 'title' => 'Bot Detection & Filtering', |
| 87 | 102 | 'description' => 'Manage bot traffic and reduce unnecessary API calls', |
| 88 | 103 | 'icon' => 'filter', |
| @@ -94,16 +109,8 @@ | ||
| 94 | 109 | 'otto_bot_blacklist', |
| 95 | 110 | 'otto_bot_statistics_link' |
| 96 | 111 | ) |
| 97 | 112 | ), |
| 98 | - 'breadcrumbs' => array( | |
| 99 | - 'title' => 'Breadcrumbs', | |
| 100 | - 'description' => 'Configure breadcrumb navigation display', | |
| 101 | - 'icon' => 'format-links', | |
| 102 | - 'priority' => 35, | |
| 103 | - 'default_open' => false, | |
| 104 | - 'render_callback' => array($this, 'render_breadcrumbs_section') | |
| 105 | - ), | |
| 106 | 113 | 'open_graph' => array( |
| 107 | 114 | 'title' => 'Open Graph', |
| 108 | 115 | 'description' => 'Control which Open Graph and article meta tags are output', |
| 109 | 116 | 'icon' => 'share', |
| @@ -130,8 +137,9 @@ | ||
| 130 | 137 | 'disable_redirection_metabox', |
| 131 | 138 | 'disable_canonical_metabox', |
| 132 | 139 | 'disable_social_opengraph_metabox', |
| 133 | 140 | 'disable_schema_markup_metabox', |
| 141 | + 'disable_language_alternates_metabox', | |
| 134 | 142 | 'disable_seo_metabox', |
| 135 | 143 | 'open_external_links' |
| 136 | 144 | ) |
| 137 | 145 | ), |
| @@ -172,13 +180,22 @@ | ||
| 172 | 180 | 'fields' => array( |
| 173 | 181 | 'permalink_structure', |
| 174 | 182 | 'hide_dashboard_framework', |
| 175 | 183 | 'show_admin_bar_status', |
| 176 | - 'enable_auto_updates', | |
| 177 | 184 | 'import_external_data' |
| 178 | 185 | ) |
| 179 | 186 | ) |
| 180 | 187 | ); |
| 188 | + | |
| 189 | + // Hidden only when there is nothing to say: no SEO plugin installed, the | |
| 190 | + // switch off, and no saved originals. It is never hidden by the | |
| 191 | + // access-control or whitelabel flags that can conceal Advanced Settings | |
| 192 | + // — a switch that rewrites another plugin's data must stay reachable. | |
| 193 | + if (!Metasync_Seo_Sync_Settings::should_display()) { | |
| 194 | + unset($sections['seo_plugin_sync']); | |
| 195 | + } | |
| 196 | + | |
| 197 | + return $sections; | |
| 181 | 198 | } |
| 182 | 199 | |
| 183 | 200 | public function get_advanced_accordion_config() { |
| 184 | 201 | $config = array(); |
| @@ -203,8 +220,17 @@ | ||
| 203 | 220 | 'default_open' => false, |
| 204 | 221 | 'render_callback' => array($this->admin_instance, 'render_debug_mode_section') |
| 205 | 222 | ); |
| 206 | 223 | |
| 224 | + $config['headless_mode'] = array( | |
| 225 | + 'title' => 'Headless Mode', | |
| 226 | + 'description' => 'Connect WordPress content to a separate public frontend', | |
| 227 | + 'icon' => 'admin-site-alt3', | |
| 228 | + 'priority' => 29, | |
| 229 | + 'default_open' => false, | |
| 230 | + 'render_callback' => array(Metasync_Settings_Registration::instance(), 'render_headless_mode_section') | |
| 231 | + ); | |
| 232 | + | |
| 207 | 233 | $config['error_logs'] = array( |
| 208 | 234 | 'title' => 'Error Logs', |
| 209 | 235 | 'description' => 'View and manage error logs to troubleshoot issues', |
| 210 | 236 | 'icon' => 'warning', |
| @@ -277,9 +303,9 @@ | ||
| 277 | 303 | $content_state = $is_open ? 'open' : 'closed'; |
| 278 | 304 | |
| 279 | 305 | echo '<div class="metasync-accordion-section" data-section="' . esc_attr($section_key) . '">'; |
| 280 | 306 | |
| 281 | - echo '<div class="metasync-accordion-header" role="button" tabindex="0" aria-expanded="' . $aria_expanded . '" aria-controls="' . $section_id . '">'; | |
| 307 | + echo '<div class="metasync-accordion-header" role="button" tabindex="0" aria-expanded="' . esc_attr($aria_expanded) . '" aria-controls="' . esc_attr($section_id) . '">'; | |
| 282 | 308 | echo '<div class="metasync-accordion-title">'; |
| 283 | 309 | echo '<span class="metasync-accordion-icon"><span class="dashicons dashicons-' . esc_attr($section_data['icon']) . '"></span></span>'; |
| 284 | 310 | echo '<div class="metasync-accordion-text">'; |
| 285 | 311 | echo '<h3>' . esc_html($section_data['title']) . '</h3>'; |
| @@ -290,9 +316,9 @@ | ||
| 290 | 316 | echo '<span class="toggle-icon">▼</span>'; |
| 291 | 317 | echo '</button>'; |
| 292 | 318 | echo '</div>'; |
| 293 | 319 | |
| 294 | - echo '<div class="metasync-accordion-content" id="' . $section_id . '" data-state="' . $content_state . '">'; | |
| 320 | + echo '<div class="metasync-accordion-content" id="' . esc_attr($section_id) . '" data-state="' . esc_attr($content_state) . '">'; | |
| 295 | 321 | |
| 296 | 322 | if (isset($section_data['render_callback']) && is_callable($section_data['render_callback'])) { |
| 297 | 323 | call_user_func($section_data['render_callback']); |
| 298 | 324 | } |
| @@ -386,14 +412,18 @@ | ||
| 386 | 412 | if (!function_exists('google_index_direct')) { |
| 387 | 413 | if (file_exists(plugin_dir_path(dirname(__FILE__)) . 'google-index/google-index-init.php')) { |
| 388 | 414 | require_once plugin_dir_path(dirname(__FILE__)) . 'google-index/google-index-init.php'; |
| 389 | 415 | } else { |
| 390 | - error_log('MetaSync Google Index: google-index-init.php not found at ' . plugin_dir_path(dirname(__FILE__)) . 'google-index/google-index-init.php'); | |
| 416 | + error_log('MetaSync Google Index: google-index-init.php not found at ' . plugin_dir_path(dirname(__FILE__)) . 'google-index/google-index-init.php'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets | |
| 391 | 417 | return; |
| 392 | 418 | } |
| 393 | 419 | } |
| 394 | 420 | |
| 395 | 421 | $google_index = google_index_direct(); |
| 422 | + if (!$google_index) { | |
| 423 | + // Nothing to render against, and calling through would be fatal. | |
| 424 | + return; | |
| 425 | + } | |
| 396 | 426 | $service_info = $google_index->get_service_account_info(); |
| 397 | 427 | $is_configured = !isset($service_info['error']); |
| 398 | 428 | |
| 399 | 429 | $saved_json_display = $is_configured ? $google_index->get_redacted_config_json() : ''; |
| @@ -672,9 +702,9 @@ | ||
| 672 | 702 | <p style="color: var(--dashboard-text-secondary); margin: 0 0 20px 0;"> |
| 673 | 703 | Select which user roles can see and access this plugin's menu, settings, and options in the WordPress admin area. |
| 674 | 704 | </p> |
| 675 | 705 | |
| 676 | - <form method="post" action="<?php echo admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '&tab=advanced'); ?>" id="plugin-access-roles-form"> | |
| 706 | + <form method="post" action="<?php echo esc_url(admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '&tab=advanced')); ?>" id="plugin-access-roles-form"> | |
| 677 | 707 | <?php wp_nonce_field('metasync_plugin_access_roles_nonce', 'plugin_access_roles_nonce'); ?> |
| 678 | 708 | <input type="hidden" name="save_plugin_access_roles" value="yes" /> |
| 679 | 709 | |
| 680 | 710 | <div class="metasync-role-selector-container" style="background: var(--dashboard-card-bg-alt, rgba(255,255,255,0.05)); border: 1px solid var(--dashboard-border); border-radius: 8px; padding: 16px; max-height: 300px; overflow-y: auto;"> |
| @@ -792,9 +822,9 @@ | ||
| 792 | 822 | |
| 793 | 823 | public function can_change_memory_limit() { |
| 794 | 824 | $current_limit = ini_get('memory_limit'); |
| 795 | 825 | |
| 796 | - $test_result = @ini_set('memory_limit', $current_limit); | |
| 826 | + $test_result = @ini_set('memory_limit', $current_limit); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API | |
| 797 | 827 | |
| 798 | 828 | return $test_result !== false; |
| 799 | 829 | } |
| 800 | 830 | |
| @@ -846,9 +876,9 @@ | ||
| 846 | 876 | } |
| 847 | 877 | |
| 848 | 878 | $memory_limit_mb = $this->get_execution_setting('max_memory_limit'); |
| 849 | 879 | |
| 850 | - $result = @ini_set('memory_limit', $memory_limit_mb . 'M'); | |
| 880 | + $result = @ini_set('memory_limit', $memory_limit_mb . 'M'); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- runtime PHP setting with no WordPress API | |
| 851 | 881 | |
| 852 | 882 | return $result !== false; |
| 853 | 883 | } |
| 854 | 884 | |
| @@ -1100,8 +1130,9 @@ | ||
| 1100 | 1130 | 'apikey' => sprintf('Auto-generated authentication token used for secure API communication between your WordPress site and %s services. You can refresh this token if needed for security purposes.', $plugin_name), |
| 1101 | 1131 | 'otto_pixel_uuid' => sprintf('Your unique %s tracking pixel identifier. This UUID is used to track %s modifications and analytics on your website pages.', $otto_name, $otto_name), |
| 1102 | 1132 | 'otto_disable_on_loggedin' => sprintf('Disable %s modifications when you are logged in to WordPress. This allows you to see and edit the original content without %s\'s enhancements during editing sessions.', $otto_name, $otto_name), |
| 1103 | 1133 | 'otto_disable_preview_button' => sprintf('Hide the %s frontend toolbar that displays the status indicator, preview button, and debug button. Enable this for a cleaner frontend experience.', $otto_name), |
| 1134 | + 'seo_priority' => sprintf('Choose which value appears first on a page when both your custom SEO value and an approved %s suggestion are available. This changes what visitors see; it does not delete or overwrite saved values.', $otto_name), | |
| 1104 | 1135 | 'otto_wp_rocket_compat' => sprintf('WP Rocket Compatibility Mode: Controls how %s interacts with WP Rocket. "Auto" (recommended) allows both to work together by avoiding DONOTCACHEPAGE constant unless necessary for Brizy pages or SG Optimizer conflicts. This ensures WP Rocket\'s JavaScript delay and optimization features continue working.', $otto_name), |
| 1105 | 1136 | 'otto_sg_optimizer_compat' => sprintf('SiteGround Optimizer Compatibility Mode: Controls how %s renders on SiteGround hosting. "Auto" (recommended) uses the internal HTTP fetch, which protects themes that defer inline CSS to the footer (e.g. Divi). "Buffer Mode" renders in-process with no internal fetch — faster on sites whose pages can never be host-cached, for example when a plugin starts a PHP session on every request (BookingPress sessions are removed automatically, so this does not apply to them).', $otto_name), |
| 1106 | 1137 | 'bookingpress_session_compat' => 'BookingPress Session Compatibility: Controls whether MetaSync removes the PHP session BookingPress starts on every public page, so hosts such as SiteGround can page-cache the site again.', |
| 1107 | 1138 | 'otto_disable_for_bots' => sprintf('Enable bot detection to automatically skip %s processing for search engine crawlers, SEO tools, and other bots. This reduces unnecessary API calls and improves performance.', $otto_name), |
| @@ -1113,8 +1144,9 @@ | ||
| 1113 | 1144 | 'disable_redirection_metabox' => 'Hide the Redirection meta box and stop redirects configured through it from running. Rules added by hand on the Redirections screen keep working. Saved redirects are kept and resume if you re-enable this.', |
| 1114 | 1145 | 'disable_canonical_metabox' => sprintf('Hide the Canonical meta box and stop %1$s emitting or overriding the canonical URL on every render path. WordPress core and third-party canonicals are left in place. Saved values are kept and restored if you re-enable this.', Metasync::get_effective_plugin_name('MetaSync')), |
| 1115 | 1146 | 'disable_social_opengraph_metabox' => sprintf('Hide the Social Media & Open Graph meta box and stop %1$s emitting any Open Graph, Twitter or article tags. Tags from another SEO plugin are left in place. Saved values are kept and restored if you re-enable this.', Metasync::get_effective_plugin_name('MetaSync')), |
| 1116 | 1147 | 'disable_schema_markup_metabox' => sprintf('Hide the Schema Markup meta box and stop %1$s emitting any JSON-LD, including the site-wide Local SEO markup and OTTO structured data. Breadcrumb markup has its own setting. Saved values are kept and restored if you re-enable this.', Metasync::get_effective_plugin_name('MetaSync')), |
| 1148 | + 'disable_language_alternates_metabox' => sprintf('Hide the Language Alternates (hreflang) panel in the block editor and stop %1$s emitting any hreflang tags on the front end, including the auto-detected WPML entries. While disabled, %1$s does not manage or override this data — another SEO plugin, or WPML itself, is free to handle it. Saved values are kept and restored if you re-enable this.', Metasync::get_effective_plugin_name('MetaSync')), | |
| 1117 | 1149 | 'disable_seo_metabox' => 'Hide the SEO Title & Meta Description meta box from post and page edit screens. This removes the Classic editor SEO fields (the Gutenberg sidebar is unaffected).', |
| 1118 | 1150 | 'open_external_links' => sprintf('Automatically add target="_blank" attribute to external links appearing in your posts, pages, and other post types when rendered by %s.', $otto_name), |
| 1119 | 1151 | 'content_genius_sync_roles' => 'Select which WordPress user roles should be synchronized with Content Genius. This determines which users will have their profiles and permissions synced for content collaboration.', |
| 1120 | 1152 | 'permalink_structure' => sprintf('Displays your current WordPress permalink structure. %s works best with pretty permalinks (not "Plain"). If you see a warning, visit Settings > Permalinks to change your structure.', $plugin_name), |
| @@ -1119,9 +1151,8 @@ | ||
| 1119 | 1151 | 'content_genius_sync_roles' => 'Select which WordPress user roles should be synchronized with Content Genius. This determines which users will have their profiles and permissions synced for content collaboration.', |
| 1120 | 1152 | 'permalink_structure' => sprintf('Displays your current WordPress permalink structure. %s works best with pretty permalinks (not "Plain"). If you see a warning, visit Settings > Permalinks to change your structure.', $plugin_name), |
| 1121 | 1153 | 'hide_dashboard_framework' => sprintf('Hide the main %s dashboard from the WordPress admin menu. This is useful if you want to reduce menu clutter but still keep the plugin active.', $plugin_name), |
| 1122 | 1154 | 'show_admin_bar_status' => sprintf('Display the %s status indicator in the WordPress admin bar at the top of your screen. This provides quick visibility of plugin status and key metrics.', $plugin_name), |
| 1123 | - 'enable_auto_updates' => sprintf('Allow WordPress to automatically update the %s plugin when new versions are released. Recommended for security patches, but you may prefer manual updates for major versions.', $plugin_name), | |
| 1124 | 1155 | 'import_external_data' => sprintf('Import your existing SEO settings and metadata from other popular SEO plugins like Yoast, Rank Math, or All in One SEO. This makes migration to %s seamless without losing your SEO data.', $plugin_name), |
| 1125 | 1156 | 'import_seo_metadata' => sprintf('Migrate your existing SEO titles and meta descriptions from Yoast, Rank Math, or All in One SEO. This one-click import preserves your search rankings by copying your optimized meta data to %s, even if the source plugin is deactivated.', $plugin_name), |
| 1126 | 1157 | 'default_page_builder' => 'Choose how Content Genius stores synced articles. "Gutenberg" works with all themes and page builders. Selecting a specific builder converts content to that builder\'s widget format, which inherits the builder\'s global typography and layout styles.', |
| 1127 | 1158 | 'og_image_dimensions' => 'Adds your share image\'s width, height, and file type to the Open Graph tags so Facebook, LinkedIn, and others render your preview instantly at the right size instead of guessing. Leave on unless another plugin already outputs these.', |
| @@ -1167,9 +1198,9 @@ | ||
| 1167 | 1198 | $content_state = $is_open ? 'open' : 'closed'; |
| 1168 | 1199 | |
| 1169 | 1200 | echo '<div class="metasync-accordion-section" data-section="' . esc_attr($section_key) . '">'; |
| 1170 | 1201 | |
| 1171 | - echo '<div class="metasync-accordion-header" role="button" tabindex="0" aria-expanded="' . $aria_expanded . '" aria-controls="' . $section_id . '">'; | |
| 1202 | + echo '<div class="metasync-accordion-header" role="button" tabindex="0" aria-expanded="' . esc_attr($aria_expanded) . '" aria-controls="' . esc_attr($section_id) . '">'; | |
| 1172 | 1203 | echo '<div class="metasync-accordion-title">'; |
| 1173 | 1204 | echo '<span class="metasync-accordion-icon"><span class="dashicons dashicons-' . esc_attr($section_data['icon']) . '"></span></span>'; |
| 1174 | 1205 | echo '<div class="metasync-accordion-text">'; |
| 1175 | 1206 | echo '<h3>' . esc_html($section_data['title']) . '</h3>'; |
| @@ -1180,9 +1211,9 @@ | ||
| 1180 | 1211 | echo '<span class="toggle-icon">▼</span>'; |
| 1181 | 1212 | echo '</button>'; |
| 1182 | 1213 | echo '</div>'; |
| 1183 | 1214 | |
| 1184 | - echo '<div class="metasync-accordion-content" id="' . $section_id . '" data-state="' . $content_state . '">'; | |
| 1215 | + echo '<div class="metasync-accordion-content" id="' . esc_attr($section_id) . '" data-state="' . esc_attr($content_state) . '">'; | |
| 1185 | 1216 | |
| 1186 | 1217 | if (isset($section_data['render_callback']) && is_callable($section_data['render_callback'])) { |
| 1187 | 1218 | call_user_func($section_data['render_callback']); |
| 1188 | 1219 | } elseif (isset($section_data['fields']) && is_array($section_data['fields'])) { |
| @@ -1197,9 +1228,9 @@ | ||
| 1197 | 1228 | echo '<tr>'; |
| 1198 | 1229 | echo '<th scope="row">'; |
| 1199 | 1230 | if (!empty($field['title'])) { |
| 1200 | 1231 | echo '<div class="metasync-field-label-wrapper">'; |
| 1201 | - echo '<label for="' . esc_attr($field['id']) . '">' . $field['title'] . '</label>'; | |
| 1232 | + echo '<label for="' . esc_attr($field['id']) . '">' . esc_html($field['title']) . '</label>'; | |
| 1202 | 1233 | |
| 1203 | 1234 | if (isset($tooltips[$field_id])) { |
| 1204 | 1235 | echo '<button type="button" class="metasync-tooltip-trigger" data-tooltip-id="' . esc_attr($field_id) . '" aria-label="More information">'; |
| 1205 | 1236 | echo '<svg class="metasync-info-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">'; |
| @@ -1254,9 +1285,9 @@ | ||
| 1254 | 1285 | echo '<tr>'; |
| 1255 | 1286 | echo '<th scope="row">'; |
| 1256 | 1287 | if (!empty($field['title'])) { |
| 1257 | 1288 | echo '<div class="metasync-field-label-wrapper">'; |
| 1258 | - echo '<label for="' . esc_attr($field['id']) . '">' . $field['title'] . '</label>'; | |
| 1289 | + echo '<label for="' . esc_attr($field['id']) . '">' . esc_html($field['title']) . '</label>'; | |
| 1259 | 1290 | if (isset($llms_tooltips[$field['id']])) { |
| 1260 | 1291 | Metasync::render_tooltip_icon($field['id'], $llms_tooltips[$field['id']]); |
| 1261 | 1292 | } |
| 1262 | 1293 | echo '</div>'; |
| @@ -1310,32 +1341,32 @@ | ||
| 1310 | 1341 | $display_value = $current_token; |
| 1311 | 1342 | $status_message = 'Plugin Auth Token is active and ready for authentication.'; |
| 1312 | 1343 | $refresh_help = 'Click refresh to generate a new token and update the heartbeat API.'; |
| 1313 | 1344 | } else { |
| 1314 | - $display_value = 'Auto-generated when connecting to ' . esc_html(Metasync::get_effective_plugin_name()); | |
| 1315 | - $status_message = 'Plugin Auth Token will be automatically generated when you click "Connect to ' . esc_html(Metasync::get_effective_plugin_name()) . '".'; | |
| 1345 | + $display_value = 'Auto-generated when connecting to ' . Metasync::get_effective_plugin_name(); | |
| 1346 | + $status_message = 'Plugin Auth Token will be automatically generated when you click "Connect to ' . Metasync::get_effective_plugin_name() . '".'; | |
| 1316 | 1347 | $refresh_help = 'You can also manually generate a token by clicking refresh.'; |
| 1317 | 1348 | } |
| 1318 | 1349 | |
| 1319 | 1350 | printf('<div class="metasync-auth-token-row">'); |
| 1320 | 1351 | printf( |
| 1321 | - '<input type="text" id="apikey" name="' . Metasync_Admin::option_key . '[general][apikey]" value="%s" size="40" class="regular-text" readonly="readonly" />', | |
| 1352 | + '<input type="text" id="apikey" name="' . esc_attr(Metasync_Admin::option_key) . '[general][apikey]" value="%s" size="40" class="regular-text" readonly="readonly" />', | |
| 1322 | 1353 | esc_attr($display_value) |
| 1323 | 1354 | ); |
| 1324 | 1355 | printf('<button type="button" id="refresh-plugin-auth-token" class="button button-secondary metasync-refresh-token-btn"><span class="dashicons dashicons-controls-repeat"></span> Refresh Token</button>'); |
| 1325 | 1356 | printf('</div>'); |
| 1326 | - printf('<p class="description">%s %s</p>', $status_message, $refresh_help); | |
| 1357 | + printf('<p class="description">%s %s</p>', esc_html($status_message), esc_html($refresh_help)); | |
| 1327 | 1358 | } |
| 1328 | 1359 | |
| 1329 | 1360 | public function linkgraph_token_callback() |
| 1330 | 1361 | { |
| 1331 | 1362 | printf( |
| 1332 | - '<input type="text" id="linkgraph_token" name="' . Metasync_Admin::option_key . '[general][linkgraph_token]" value="%s" size="25" readonly="readonly" />', | |
| 1363 | + '<input type="text" id="linkgraph_token" name="' . esc_attr(Metasync_Admin::option_key) . '[general][linkgraph_token]" value="%s" size="25" readonly="readonly" />', | |
| 1333 | 1364 | isset(Metasync::get_option('general')['linkgraph_token']) ? esc_attr(Metasync::get_option('general')['linkgraph_token']) : '' |
| 1334 | 1365 | ); |
| 1335 | 1366 | |
| 1336 | 1367 | printf( |
| 1337 | - '<input type="text" id="linkgraph_customer_id" name="' . Metasync_Admin::option_key . '[general][linkgraph_customer_id]" value="%s" size="25" readonly="readonly" />', | |
| 1368 | + '<input type="text" id="linkgraph_customer_id" name="' . esc_attr(Metasync_Admin::option_key) . '[general][linkgraph_customer_id]" value="%s" size="25" readonly="readonly" />', | |
| 1338 | 1369 | isset(Metasync::get_option('general')['linkgraph_customer_id']) ? esc_attr(Metasync::get_option('general')['linkgraph_customer_id']) : '' |
| 1339 | 1370 | ); |
| 1340 | 1371 | |
| 1341 | 1372 | ?> |
| @@ -1460,9 +1491,9 @@ | ||
| 1460 | 1491 | printf('• The authentication window will open in a popup - please allow popups<br/>'); |
| 1461 | 1492 | printf('• The process typically takes 15-30 seconds to complete<br/>'); |
| 1462 | 1493 | printf('• Your API key will be stored securely and shown masked below<br/>'); |
| 1463 | 1494 | printf('• If you encounter issues, try disabling ad blockers temporarily<br/>'); |
| 1464 | - printf('• Contact <a href="mailto:%s">%s</a> if you need assistance', Metasync::SUPPORT_EMAIL, Metasync::SUPPORT_EMAIL); | |
| 1495 | + printf('• Contact <a href="mailto:%s">%s</a> if you need assistance', esc_attr(Metasync::SUPPORT_EMAIL), esc_html(Metasync::SUPPORT_EMAIL)); | |
| 1465 | 1496 | printf('</div>'); |
| 1466 | 1497 | printf('</details>'); |
| 1467 | 1498 | printf('</div>'); |
| 1468 | 1499 | |
| @@ -1514,9 +1545,9 @@ | ||
| 1514 | 1545 | $timestamp = @Metasync::get_option('general')['send_auth_token_timestamp']; |
| 1515 | 1546 | printf( |
| 1516 | 1547 | '<p id="sendAuthTokenTimestamp" class="descriptionValue">%s (%s)</p>', |
| 1517 | 1548 | esc_attr($timestamp), |
| 1518 | - $this->time_elapsed_string($timestamp) | |
| 1549 | + esc_html($this->time_elapsed_string($timestamp)) | |
| 1519 | 1550 | ); |
| 1520 | 1551 | |
| 1521 | 1552 | |
| 1522 | 1553 | } |
| @@ -1524,9 +1555,9 @@ | ||
| 1524 | 1555 | |
| 1525 | 1556 | public function bing_site_verification_callback() |
| 1526 | 1557 | { |
| 1527 | 1558 | printf( |
| 1528 | - '<input type="text" id="bing_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][bing_site_verification]" value="%s" size="50" />', | |
| 1559 | + '<input type="text" id="bing_site_verification" name="' . esc_attr(Metasync_Admin::option_key) . '[searchengines][bing_site_verification]" value="%s" size="50" />', | |
| 1529 | 1560 | isset(Metasync::get_option('searchengines')['bing_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['bing_site_verification']) : '' |
| 1530 | 1561 | ); |
| 1531 | 1562 | |
| 1532 | 1563 | printf(' <br> <span class="description"> Enter Bing Webmaster Tools verification code: </span> '); |
| @@ -1535,9 +1566,9 @@ | ||
| 1535 | 1566 | |
| 1536 | 1567 | public function yandex_site_verification_callback() |
| 1537 | 1568 | { |
| 1538 | 1569 | printf( |
| 1539 | - '<input type="text" id="yandex_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][yandex_site_verification]" value="%s" size="50" />', | |
| 1570 | + '<input type="text" id="yandex_site_verification" name="' . esc_attr(Metasync_Admin::option_key) . '[searchengines][yandex_site_verification]" value="%s" size="50" />', | |
| 1540 | 1571 | isset(Metasync::get_option('searchengines')['yandex_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['yandex_site_verification']) : '' |
| 1541 | 1572 | ); |
| 1542 | 1573 | |
| 1543 | 1574 | printf(' <br> <span class="description"> Enter Yandex verification code: </span>'); |
| @@ -1546,9 +1577,9 @@ | ||
| 1546 | 1577 | |
| 1547 | 1578 | public function google_site_verification_callback() |
| 1548 | 1579 | { |
| 1549 | 1580 | printf( |
| 1550 | - '<input type="text" id="google_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][google_site_verification]" value="%s" size="50" />', | |
| 1581 | + '<input type="text" id="google_site_verification" name="' . esc_attr(Metasync_Admin::option_key) . '[searchengines][google_site_verification]" value="%s" size="50" />', | |
| 1551 | 1582 | isset(Metasync::get_option('searchengines')['google_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['google_site_verification']) : '' |
| 1552 | 1583 | ); |
| 1553 | 1584 | |
| 1554 | 1585 | printf(' <br> <span class="description"> Enter Google Search Console verification code: </span>'); |
| @@ -1557,9 +1588,9 @@ | ||
| 1557 | 1588 | |
| 1558 | 1589 | public function pinterest_site_verification_callback() |
| 1559 | 1590 | { |
| 1560 | 1591 | printf( |
| 1561 | - '<input type="text" id="pinterest_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][pinterest_site_verification]" value="%s" size="50" />', | |
| 1592 | + '<input type="text" id="pinterest_site_verification" name="' . esc_attr(Metasync_Admin::option_key) . '[searchengines][pinterest_site_verification]" value="%s" size="50" />', | |
| 1562 | 1593 | isset(Metasync::get_option('searchengines')['pinterest_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['pinterest_site_verification']) : '' |
| 1563 | 1594 | ); |
| 1564 | 1595 | |
| 1565 | 1596 | printf(' <br> <span class="description"> Enter Pinterest verification code: </span>'); |
| @@ -1588,10 +1619,10 @@ | ||
| 1588 | 1619 | |
| 1589 | 1620 | public function local_seo_name_callback() |
| 1590 | 1621 | { |
| 1591 | 1622 | printf( |
| 1592 | - '<input type="text" id="local_seo_name" name="' . Metasync_Admin::option_key . '[localseo][local_seo_name]" value="%s" size="50" />', | |
| 1593 | - isset(Metasync::get_option('localseo')['local_seo_name']) ? esc_attr(Metasync::get_option('localseo')['local_seo_name']) : get_bloginfo() | |
| 1623 | + '<input type="text" id="local_seo_name" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_name]" value="%s" size="50" />', | |
| 1624 | + isset(Metasync::get_option('localseo')['local_seo_name']) ? esc_attr(Metasync::get_option('localseo')['local_seo_name']) : esc_attr(get_bloginfo()) | |
| 1594 | 1625 | ); |
| 1595 | 1626 | |
| 1596 | 1627 | printf(' <br> <span class="description"> Your name or company name </span>'); |
| 1597 | 1628 | } |
| @@ -1607,9 +1638,9 @@ | ||
| 1607 | 1638 | // would otherwise survive every subsequent Save Settings. |
| 1608 | 1639 | $local_seo_logo = metasync_repair_scheme_prefixed_media_id($local_seo_logo); |
| 1609 | 1640 | |
| 1610 | 1641 | printf( |
| 1611 | - '<input type="hidden" id="local_seo_logo" name="' . Metasync_Admin::option_key . '[localseo][local_seo_logo]" value="%s" size="50" />', | |
| 1642 | + '<input type="hidden" id="local_seo_logo" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_logo]" value="%s" size="50" />', | |
| 1612 | 1643 | esc_attr((string) $local_seo_logo) |
| 1613 | 1644 | ); |
| 1614 | 1645 | |
| 1615 | 1646 | printf(' <br> <input class="button-secondary no-loading" type="button" id="logo_upload_button" value="Add or Upload File">'); |
| @@ -1631,9 +1662,9 @@ | ||
| 1631 | 1662 | $logo_url ? '' : ' style="display:none"' |
| 1632 | 1663 | ); |
| 1633 | 1664 | |
| 1634 | 1665 | $button_type = $logo_url ? 'button' : 'hidden'; |
| 1635 | - printf('<input type="%s" class="button-secondary no-loading metasync-logo-remove-btn" id="local_seo_logo_close_btn" value="X">', $button_type); | |
| 1666 | + printf('<input type="%s" class="button-secondary no-loading metasync-logo-remove-btn" id="local_seo_logo_close_btn" value="X">', esc_attr($button_type)); | |
| 1636 | 1667 | printf('</span>'); |
| 1637 | 1668 | } |
| 1638 | 1669 | |
| 1639 | 1670 | /** |
| @@ -1671,10 +1702,10 @@ | ||
| 1671 | 1702 | |
| 1672 | 1703 | public function local_seo_url_callback() |
| 1673 | 1704 | { |
| 1674 | 1705 | printf( |
| 1675 | - '<input type="text" id="local_seo_url" name="' . Metasync_Admin::option_key . '[localseo][local_seo_url]" value="%s" size="50" />', | |
| 1676 | - isset(Metasync::get_option('localseo')['local_seo_url']) ? esc_attr(Metasync::get_option('localseo')['local_seo_url']) : home_url() | |
| 1706 | + '<input type="text" id="local_seo_url" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_url]" value="%s" size="50" />', | |
| 1707 | + isset(Metasync::get_option('localseo')['local_seo_url']) ? esc_attr(Metasync::get_option('localseo')['local_seo_url']) : esc_attr(home_url()) | |
| 1677 | 1708 | ); |
| 1678 | 1709 | |
| 1679 | 1710 | printf(' <br> <span class="description"> URL of the item. </span>'); |
| 1680 | 1711 | } |
| @@ -1681,9 +1712,9 @@ | ||
| 1681 | 1712 | |
| 1682 | 1713 | public function local_seo_email_callback() |
| 1683 | 1714 | { |
| 1684 | 1715 | printf( |
| 1685 | - '<input type="text" id="local_seo_email" name="' . Metasync_Admin::option_key . '[localseo][local_seo_email]" value="%s" size="50" />', | |
| 1716 | + '<input type="text" id="local_seo_email" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_email]" value="%s" size="50" />', | |
| 1686 | 1717 | isset(Metasync::get_option('localseo')['local_seo_email']) ? esc_attr(Metasync::get_option('localseo')['local_seo_email']) : '' |
| 1687 | 1718 | ); |
| 1688 | 1719 | |
| 1689 | 1720 | printf(' <br> <span class="description"> Search engines display your email address. </span>'); |
| @@ -1691,9 +1722,9 @@ | ||
| 1691 | 1722 | |
| 1692 | 1723 | public function local_seo_phone_callback() |
| 1693 | 1724 | { |
| 1694 | 1725 | printf( |
| 1695 | - '<input type="text" id="local_seo_phone" name="' . Metasync_Admin::option_key . '[localseo][local_seo_phone]" value="%s" size="50" />', | |
| 1726 | + '<input type="text" id="local_seo_phone" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_phone]" value="%s" size="50" />', | |
| 1696 | 1727 | isset(Metasync::get_option('localseo')['local_seo_phone']) ? esc_attr(Metasync::get_option('localseo')['local_seo_phone']) : '' |
| 1697 | 1728 | ); |
| 1698 | 1729 | |
| 1699 | 1730 | printf(' <br> <span class="description"> Search engines may prominently display your contact phone number for mobile users. </span>'); |
| @@ -1701,29 +1732,29 @@ | ||
| 1701 | 1732 | |
| 1702 | 1733 | public function local_seo_address_callback() |
| 1703 | 1734 | { |
| 1704 | 1735 | printf( |
| 1705 | - '<input type="text" id="local_seo_address_street" name="' . Metasync_Admin::option_key . '[localseo][address][street]" value="%s" size="50" placeholder="Street Address"/> <br>', | |
| 1736 | + '<input type="text" id="local_seo_address_street" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][address][street]" value="%s" size="50" placeholder="Street Address"/> <br>', | |
| 1706 | 1737 | isset(Metasync::get_option('localseo')['address']['street']) ? esc_attr(Metasync::get_option('localseo')['address']['street']) : '' |
| 1707 | 1738 | ); |
| 1708 | 1739 | |
| 1709 | 1740 | printf( |
| 1710 | - '<input type="text" id="local_seo_address_locality" name="' . Metasync_Admin::option_key . '[localseo][address][locality]" value="%s" size="50" placeholder="Locality"/> <br>', | |
| 1741 | + '<input type="text" id="local_seo_address_locality" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][address][locality]" value="%s" size="50" placeholder="Locality"/> <br>', | |
| 1711 | 1742 | isset(Metasync::get_option('localseo')['address']['locality']) ? esc_attr(Metasync::get_option('localseo')['address']['locality']) : '' |
| 1712 | 1743 | ); |
| 1713 | 1744 | |
| 1714 | 1745 | printf( |
| 1715 | - '<input type="text" id="local_seo_address_region" name="' . Metasync_Admin::option_key . '[localseo][address][region]" value="%s" size="50" placeholder="Region"/> <br>', | |
| 1746 | + '<input type="text" id="local_seo_address_region" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][address][region]" value="%s" size="50" placeholder="Region"/> <br>', | |
| 1716 | 1747 | isset(Metasync::get_option('localseo')['address']['region']) ? esc_attr(Metasync::get_option('localseo')['address']['region']) : '' |
| 1717 | 1748 | ); |
| 1718 | 1749 | |
| 1719 | 1750 | printf( |
| 1720 | - '<input type="text" id="local_seo_address_postalcode" name="' . Metasync_Admin::option_key . '[localseo][address][postalcode]" value="%s" size="50" placeholder="Postal Code"/> <br>', | |
| 1751 | + '<input type="text" id="local_seo_address_postalcode" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][address][postalcode]" value="%s" size="50" placeholder="Postal Code"/> <br>', | |
| 1721 | 1752 | isset(Metasync::get_option('localseo')['address']['postalcode']) ? esc_attr(Metasync::get_option('localseo')['address']['postalcode']) : '' |
| 1722 | 1753 | ); |
| 1723 | 1754 | |
| 1724 | 1755 | printf( |
| 1725 | - '<input type="text" id="local_seo_address_country" name="' . Metasync_Admin::option_key . '[localseo][address][country]" value="%s" size="50" placeholder="Country"/> <br>', | |
| 1756 | + '<input type="text" id="local_seo_address_country" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][address][country]" value="%s" size="50" placeholder="Country"/> <br>', | |
| 1726 | 1757 | isset(Metasync::get_option('localseo')['address']['country']) ? esc_attr(Metasync::get_option('localseo')['address']['country']) : '' |
| 1727 | 1758 | ); |
| 1728 | 1759 | } |
| 1729 | 1760 | |
| @@ -1738,9 +1769,9 @@ | ||
| 1738 | 1769 | <select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][local_seo_business_type]') ?>"> |
| 1739 | 1770 | <option value='0'>Select Business Type</option> |
| 1740 | 1771 | <?php |
| 1741 | 1772 | foreach ($types as $type) { |
| 1742 | - printf('<option value="%s" %s >%s</option>', $type, selected($type, esc_attr($business_type)), $type); | |
| 1773 | + printf('<option value="%s" %s >%s</option>', esc_attr($type), selected($type, $business_type, false), esc_html($type)); | |
| 1743 | 1774 | } |
| 1744 | 1775 | ?> |
| 1745 | 1776 | </select> |
| 1746 | 1777 | <?php |
| @@ -1764,9 +1795,9 @@ | ||
| 1764 | 1795 | <li> |
| 1765 | 1796 | <select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][days][]') ?>"> |
| 1766 | 1797 | <?php |
| 1767 | 1798 | foreach ($days_name as $name) { |
| 1768 | - printf('<option value="%s" %s >%s</option>', $name, selected(esc_attr($name), esc_attr($day_name)), esc_attr($name)); | |
| 1799 | + printf('<option value="%s" %s >%s</option>', esc_attr($name), selected($name, $day_name, false), esc_html($name)); | |
| 1769 | 1800 | } |
| 1770 | 1801 | ?> |
| 1771 | 1802 | </select> |
| 1772 | 1803 | <input type="text" name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][times][]') ?>" value="<?php echo esc_attr($day_time) ?>"> |
| @@ -1845,9 +1876,9 @@ | ||
| 1845 | 1876 | |
| 1846 | 1877 | public function local_seo_price_range_callback() |
| 1847 | 1878 | { |
| 1848 | 1879 | printf( |
| 1849 | - '<input type="text" id="local_seo_price_range" name="' . Metasync_Admin::option_key . '[localseo][local_seo_price_range]" value="%s" size="50" />', | |
| 1880 | + '<input type="text" id="local_seo_price_range" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_price_range]" value="%s" size="50" />', | |
| 1850 | 1881 | isset(Metasync::get_option('localseo')['local_seo_price_range']) ? esc_attr(Metasync::get_option('localseo')['local_seo_price_range']) : '' |
| 1851 | 1882 | ); |
| 1852 | 1883 | printf(' <br> <span class="description"> The price range of the business, for example $$$. </span>'); |
| 1853 | 1884 | } |
| @@ -1860,9 +1891,9 @@ | ||
| 1860 | 1891 | <?php |
| 1861 | 1892 | $about_page = Metasync::get_option('localseo')['local_seo_about_page'] ?? ''; |
| 1862 | 1893 | $pages = get_pages(); |
| 1863 | 1894 | foreach ($pages as $page) { |
| 1864 | - printf('<option value="%s" %s >%s</option>', $page->ID, selected($page->ID, esc_attr($about_page)), $page->post_title); | |
| 1895 | + printf('<option value="%s" %s >%s</option>', absint($page->ID), selected($page->ID, $about_page, false), esc_html($page->post_title)); | |
| 1865 | 1896 | } |
| 1866 | 1897 | ?> |
| 1867 | 1898 | </select> |
| 1868 | 1899 | <?php |
| @@ -1877,9 +1908,9 @@ | ||
| 1877 | 1908 | <?php |
| 1878 | 1909 | $contact_page = Metasync::get_option('localseo')['local_seo_contact_page'] ?? ''; |
| 1879 | 1910 | $pages = get_pages(); |
| 1880 | 1911 | foreach ($pages as $page) { |
| 1881 | - printf('<option value="%s" %s >%s</option>', $page->ID, selected($page->ID, esc_attr($contact_page)), $page->post_title); | |
| 1912 | + printf('<option value="%s" %s >%s</option>', absint($page->ID), selected($page->ID, $contact_page, false), esc_html($page->post_title)); | |
| 1882 | 1913 | } |
| 1883 | 1914 | ?> |
| 1884 | 1915 | </select> |
| 1885 | 1916 | <?php |
| @@ -1888,9 +1919,9 @@ | ||
| 1888 | 1919 | |
| 1889 | 1920 | public function local_seo_map_key_callback() |
| 1890 | 1921 | { |
| 1891 | 1922 | printf( |
| 1892 | - '<input type="text" id="local_seo_map_key" name="' . Metasync_Admin::option_key . '[localseo][local_seo_map_key]" value="%s" size="50" />', | |
| 1923 | + '<input type="text" id="local_seo_map_key" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_map_key]" value="%s" size="50" />', | |
| 1893 | 1924 | isset(Metasync::get_option('localseo')['local_seo_map_key']) ? esc_attr(Metasync::get_option('localseo')['local_seo_map_key']) : '' |
| 1894 | 1925 | ); |
| 1895 | 1926 | |
| 1896 | 1927 | printf(' <br> <span class="description"> An API Key is required to display embedded Google Maps on your site. </span>'); |
| @@ -1898,9 +1929,9 @@ | ||
| 1898 | 1929 | |
| 1899 | 1930 | public function local_seo_geo_coordinates_callback() |
| 1900 | 1931 | { |
| 1901 | 1932 | printf( |
| 1902 | - '<input type="text" id="local_seo_geo_coordinates" name="' . Metasync_Admin::option_key . '[localseo][local_seo_geo_coordinates]" value="%s" size="50" />', | |
| 1933 | + '<input type="text" id="local_seo_geo_coordinates" name="' . esc_attr(Metasync_Admin::option_key) . '[localseo][local_seo_geo_coordinates]" value="%s" size="50" />', | |
| 1903 | 1934 | isset(Metasync::get_option('localseo')['local_seo_geo_coordinates']) ? esc_attr(Metasync::get_option('localseo')['local_seo_geo_coordinates']) : '' |
| 1904 | 1935 | ); |
| 1905 | 1936 | |
| 1906 | 1937 | printf(' <br> <span class="description"> Latitude and longitude values separated by comma. </span>'); |
| @@ -1908,9 +1939,9 @@ | ||
| 1908 | 1939 | |
| 1909 | 1940 | public function header_snippets_callback() |
| 1910 | 1941 | { |
| 1911 | 1942 | printf( |
| 1912 | - '<textarea class="wide-text" id="header_snippets" rows="8" name="' . Metasync_Admin::option_key . '[codesnippets][header_snippet]" >%s</textarea>', | |
| 1943 | + '<textarea class="wide-text" id="header_snippets" rows="8" name="' . esc_attr(Metasync_Admin::option_key) . '[codesnippets][header_snippet]" >%s</textarea>', | |
| 1913 | 1944 | isset(Metasync::get_option('codesnippets')['header_snippet']) ? esc_attr(Metasync::get_option('codesnippets')['header_snippet']) : '' |
| 1914 | 1945 | ); |
| 1915 | 1946 | } |
| 1916 | 1947 | |
| @@ -1916,9 +1947,9 @@ | ||
| 1916 | 1947 | |
| 1917 | 1948 | public function footer_snippets_callback() |
| 1918 | 1949 | { |
| 1919 | 1950 | printf( |
| 1920 | - '<textarea class="wide-text" id="footer_snippets" rows="8" name="' . Metasync_Admin::option_key . '[codesnippets][footer_snippet]" >%s</textarea>', | |
| 1951 | + '<textarea class="wide-text" id="footer_snippets" rows="8" name="' . esc_attr(Metasync_Admin::option_key) . '[codesnippets][footer_snippet]" >%s</textarea>', | |
| 1921 | 1952 | isset(Metasync::get_option('codesnippets')['footer_snippet']) ? esc_attr(Metasync::get_option('codesnippets')['footer_snippet']) : '' |
| 1922 | 1953 | ); |
| 1923 | 1954 | } |
| 1924 | 1955 | |
| @@ -2055,9 +2086,9 @@ | ||
| 2055 | 2086 | |
| 2056 | 2087 | public function global_open_graph_meta_callback() |
| 2057 | 2088 | { |
| 2058 | 2089 | printf( |
| 2059 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][open_graph_meta_tags]" value="true" %s />', | |
| 2090 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][open_graph_meta_tags]" value="true" %s />', | |
| 2060 | 2091 | isset(Metasync::get_option('common_meta_settings')['open_graph_meta_tags']) && Metasync::get_option('common_meta_settings')['open_graph_meta_tags'] == 'true' ? 'checked' : '' |
| 2061 | 2092 | ); |
| 2062 | 2093 | printf(' <br> <span class="description"> Automatically add the Open Graph meta tags in a page or post.</span>'); |
| 2063 | 2094 | } |
| @@ -2064,9 +2095,9 @@ | ||
| 2064 | 2095 | |
| 2065 | 2096 | public function global_facebook_meta_callback() |
| 2066 | 2097 | { |
| 2067 | 2098 | printf( |
| 2068 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][facebook_meta_tags]" value="true" %s />', | |
| 2099 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][facebook_meta_tags]" value="true" %s />', | |
| 2069 | 2100 | isset(Metasync::get_option('common_meta_settings')['facebook_meta_tags']) && Metasync::get_option('common_meta_settings')['facebook_meta_tags'] == 'true' ? 'checked' : '' |
| 2070 | 2101 | ); |
| 2071 | 2102 | printf(' <br> <span class="description"> Automatically add the Facebook meta tags in a page or post.</span>'); |
| 2072 | 2103 | } |
| @@ -2073,9 +2104,9 @@ | ||
| 2073 | 2104 | |
| 2074 | 2105 | public function global_twitter_meta_callback() |
| 2075 | 2106 | { |
| 2076 | 2107 | printf( |
| 2077 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][twitter_meta_tags]" value="true" %s />', | |
| 2108 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][twitter_meta_tags]" value="true" %s />', | |
| 2078 | 2109 | isset(Metasync::get_option('common_meta_settings')['twitter_meta_tags']) && Metasync::get_option('common_meta_settings')['twitter_meta_tags'] == 'true' ? 'checked' : '' |
| 2079 | 2110 | ); |
| 2080 | 2111 | printf(' <br> <span class="description"> Automatically add the Twitter meta tags in a page or post.</span>'); |
| 2081 | 2112 | } |
| @@ -2083,9 +2114,9 @@ | ||
| 2083 | 2114 | public function og_image_dimensions_callback() |
| 2084 | 2115 | { |
| 2085 | 2116 | $val = Metasync::get_option('common_meta_settings')['og_image_dimensions'] ?? 'true'; |
| 2086 | 2117 | printf( |
| 2087 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][og_image_dimensions]" value="true" %s />', | |
| 2118 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][og_image_dimensions]" value="true" %s />', | |
| 2088 | 2119 | $val === 'true' ? 'checked' : '' |
| 2089 | 2120 | ); |
| 2090 | 2121 | printf('<span class="description"> Output og:image:width, og:image:height, and og:image:type when OG image metadata is available.</span>'); |
| 2091 | 2122 | } |
| @@ -2093,9 +2124,9 @@ | ||
| 2093 | 2124 | public function article_timestamps_callback() |
| 2094 | 2125 | { |
| 2095 | 2126 | $val = Metasync::get_option('common_meta_settings')['article_timestamps'] ?? 'true'; |
| 2096 | 2127 | printf( |
| 2097 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_timestamps]" value="true" %s />', | |
| 2128 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][article_timestamps]" value="true" %s />', | |
| 2098 | 2129 | $val === 'true' ? 'checked' : '' |
| 2099 | 2130 | ); |
| 2100 | 2131 | printf('<span class="description"> Output article:published_time and article:modified_time from the post publish and modified dates (ISO 8601).</span>'); |
| 2101 | 2132 | } |
| @@ -2103,9 +2134,9 @@ | ||
| 2103 | 2134 | public function article_author_callback() |
| 2104 | 2135 | { |
| 2105 | 2136 | $val = Metasync::get_option('common_meta_settings')['article_author'] ?? 'true'; |
| 2106 | 2137 | printf( |
| 2107 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_author]" value="true" %s />', | |
| 2138 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][article_author]" value="true" %s />', | |
| 2108 | 2139 | $val === 'true' ? 'checked' : '' |
| 2109 | 2140 | ); |
| 2110 | 2141 | printf('<span class="description"> Output article:author using the post author website URL or archive URL (overridable per-post via _metasync_og_article_author meta).</span>'); |
| 2111 | 2142 | } |
| @@ -2113,9 +2144,9 @@ | ||
| 2113 | 2144 | public function article_section_callback() |
| 2114 | 2145 | { |
| 2115 | 2146 | $val = Metasync::get_option('common_meta_settings')['article_section'] ?? 'true'; |
| 2116 | 2147 | printf( |
| 2117 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_section]" value="true" %s />', | |
| 2148 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][article_section]" value="true" %s />', | |
| 2118 | 2149 | $val === 'true' ? 'checked' : '' |
| 2119 | 2150 | ); |
| 2120 | 2151 | printf('<span class="description"> Output article:section from the primary category (falls back to first category).</span>'); |
| 2121 | 2152 | } |
| @@ -2123,9 +2154,9 @@ | ||
| 2123 | 2154 | public function article_tags_callback() |
| 2124 | 2155 | { |
| 2125 | 2156 | $val = Metasync::get_option('common_meta_settings')['article_tags'] ?? 'true'; |
| 2126 | 2157 | printf( |
| 2127 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_tags]" value="true" %s />', | |
| 2158 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][article_tags]" value="true" %s />', | |
| 2128 | 2159 | $val === 'true' ? 'checked' : '' |
| 2129 | 2160 | ); |
| 2130 | 2161 | printf('<span class="description"> Output one article:tag meta tag per WordPress post tag.</span>'); |
| 2131 | 2162 | } |
| @@ -2133,9 +2164,9 @@ | ||
| 2133 | 2164 | public function twitter_image_alt_callback() |
| 2134 | 2165 | { |
| 2135 | 2166 | $val = Metasync::get_option('common_meta_settings')['twitter_image_alt'] ?? 'true'; |
| 2136 | 2167 | printf( |
| 2137 | - '<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][twitter_image_alt]" value="true" %s />', | |
| 2168 | + '<input type="checkbox" name="' . esc_attr(Metasync_Admin::option_key) . '[common_meta_settings][twitter_image_alt]" value="true" %s />', | |
| 2138 | 2169 | $val === 'true' ? 'checked' : '' |
| 2139 | 2170 | ); |
| 2140 | 2171 | printf('<span class="description"> Output twitter:image:alt using the stored alt text or the OG image attachment alt attribute.</span>'); |
| 2141 | 2172 | } |
| @@ -2142,9 +2173,9 @@ | ||
| 2142 | 2173 | |
| 2143 | 2174 | public function facebook_page_url_callback() |
| 2144 | 2175 | { |
| 2145 | 2176 | $facebook_page_url = Metasync::get_option('social_meta')['facebook_page_url'] ?? ''; |
| 2146 | - printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_page_url]" value="%s" size="50" />', esc_attr($facebook_page_url)); | |
| 2177 | + printf('<input type="text" name="' . esc_attr(Metasync_Admin::option_key) . '[social_meta][facebook_page_url]" value="%s" size="50" />', esc_attr($facebook_page_url)); | |
| 2147 | 2178 | printf('<br><span class="description"> Enter your Facebook page URL. eg: <code>https://www.facebook.com/MetaSync/</code> </span>'); |
| 2148 | 2179 | } |
| 2149 | 2180 | |
| 2150 | 2181 | public function facebook_authorship_callback() |
| @@ -2149,9 +2180,9 @@ | ||
| 2149 | 2180 | |
| 2150 | 2181 | public function facebook_authorship_callback() |
| 2151 | 2182 | { |
| 2152 | 2183 | $facebook_authorship = Metasync::get_option('social_meta')['facebook_authorship'] ?? ''; |
| 2153 | - printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_authorship]" value="%s" size="50" />', esc_attr($facebook_authorship)); | |
| 2184 | + printf('<input type="text" name="' . esc_attr(Metasync_Admin::option_key) . '[social_meta][facebook_authorship]" value="%s" size="50" />', esc_attr($facebook_authorship)); | |
| 2154 | 2185 | printf('<br><span class="description"> Enter Facebook profile URL to show Facebook Authorship when your articles are being shared on Facebook. eg: <code>https://www.facebook.com/shahrukh/</code> </span>'); |
| 2155 | 2186 | } |
| 2156 | 2187 | |
| 2157 | 2188 | public function facebook_admin_callback() |
| @@ -2156,9 +2187,9 @@ | ||
| 2156 | 2187 | |
| 2157 | 2188 | public function facebook_admin_callback() |
| 2158 | 2189 | { |
| 2159 | 2190 | $facebook_admin = Metasync::get_option('social_meta')['facebook_admin'] ?? ''; |
| 2160 | - printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_admin]" value="%s" size="50" />', esc_attr($facebook_admin)); | |
| 2191 | + printf('<input type="text" name="' . esc_attr(Metasync_Admin::option_key) . '[social_meta][facebook_admin]" value="%s" size="50" />', esc_attr($facebook_admin)); | |
| 2161 | 2192 | printf(' <br> <span class="description"> Enter numeric user ID of Facebook. </span>'); |
| 2162 | 2193 | } |
| 2163 | 2194 | |
| 2164 | 2195 | public function facebook_app_callback() |
| @@ -2163,9 +2194,9 @@ | ||
| 2163 | 2194 | |
| 2164 | 2195 | public function facebook_app_callback() |
| 2165 | 2196 | { |
| 2166 | 2197 | $facebook_app = Metasync::get_option('social_meta')['facebook_app'] ?? ''; |
| 2167 | - printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_app]" value="%s" size="50" />', esc_attr($facebook_app)); | |
| 2198 | + printf('<input type="text" name="' . esc_attr(Metasync_Admin::option_key) . '[social_meta][facebook_app]" value="%s" size="50" />', esc_attr($facebook_app)); | |
| 2168 | 2199 | printf(' <br> <span class="description"> Enter numeric app ID of Facebook </span>'); |
| 2169 | 2200 | } |
| 2170 | 2201 | |
| 2171 | 2202 | public function facebook_secret_callback() |
| @@ -2170,9 +2201,9 @@ | ||
| 2170 | 2201 | |
| 2171 | 2202 | public function facebook_secret_callback() |
| 2172 | 2203 | { |
| 2173 | 2204 | $facebook_secret = Metasync::get_option('social_meta')['facebook_secret'] ?? ''; |
| 2174 | - printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_secret]" value="%s" size="50" />', esc_attr($facebook_secret)); | |
| 2205 | + printf('<input type="text" name="' . esc_attr(Metasync_Admin::option_key) . '[social_meta][facebook_secret]" value="%s" size="50" />', esc_attr($facebook_secret)); | |
| 2175 | 2206 | printf(' <br> <span class="description"> Enter alphanumeric access token from Facebook. </span>'); |
| 2176 | 2207 | } |
| 2177 | 2208 | |
| 2178 | 2209 | public function twitter_username_callback() |
| @@ -2177,9 +2208,9 @@ | ||
| 2177 | 2208 | |
| 2178 | 2209 | public function twitter_username_callback() |
| 2179 | 2210 | { |
| 2180 | 2211 | $twitter_username = Metasync::get_option('social_meta')['twitter_username'] ?? ''; |
| 2181 | - printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][twitter_username]" value="%s" size="50" />', esc_attr($twitter_username)); | |
| 2212 | + printf('<input type="text" name="' . esc_attr(Metasync_Admin::option_key) . '[social_meta][twitter_username]" value="%s" size="50" />', esc_attr($twitter_username)); | |
| 2182 | 2213 | printf(' <br> <span class="description"> Twitter username of the author to add <code>twitter:creator</code> tag to post. eg: <code>MetaSync</code> </span>'); |
| 2183 | 2214 | } |
| 2184 | 2215 | |
| 2185 | 2216 | public static function get_business_types() |
| @@ -2354,8 +2385,14 @@ | ||
| 2354 | 2385 | } |
| 2355 | 2386 | |
| 2356 | 2387 | /** |
| 2357 | 2388 | * Render breadcrumbs settings section |
| 2389 | + * | |
| 2390 | + * Rendered by the dedicated Breadcrumbs admin page. The three checkbox | |
| 2391 | + * fields each ship a hidden companion input so their keys are always | |
| 2392 | + * present in the submitted payload, which lets the save handlers treat an | |
| 2393 | + * absent key as "this form does not manage that field" instead of | |
| 2394 | + * "unchecked". | |
| 2358 | 2395 | */ |
| 2359 | 2396 | public function render_breadcrumbs_section() { |
| 2360 | 2397 | $options = Metasync::get_option('breadcrumbs', array()); |
| 2361 | 2398 | |
| @@ -2360,9 +2397,9 @@ | ||
| 2360 | 2397 | $options = Metasync::get_option('breadcrumbs', array()); |
| 2361 | 2398 | |
| 2362 | 2399 | $defaults = array( |
| 2363 | 2400 | 'enabled' => true, |
| 2364 | - 'separator' => '»', | |
| 2401 | + 'separator' => '»', | |
| 2365 | 2402 | 'home_label' => 'Home', |
| 2366 | 2403 | 'home_url' => '', |
| 2367 | 2404 | 'show_current_page' => true, |
| 2368 | 2405 | 'prefix_text' => '', |
| @@ -2370,8 +2407,19 @@ | ||
| 2370 | 2407 | 'disable_schema' => false, |
| 2371 | 2408 | ); |
| 2372 | 2409 | |
| 2373 | 2410 | $options = wp_parse_args($options, $defaults); |
| 2411 | + | |
| 2412 | + # Older builds stored the separator as an HTML entity (e.g. "»"). | |
| 2413 | + # Decode before matching so the saved choice still lights up its radio. | |
| 2414 | + $separator_presets = array('»', '/', '>', '·'); | |
| 2415 | + $separator_current = html_entity_decode((string) $options['separator'], ENT_QUOTES, 'UTF-8'); | |
| 2416 | + if ($separator_current === '') { | |
| 2417 | + $separator_current = '»'; | |
| 2418 | + } | |
| 2419 | + # A separator that predates the radio picker (or came from the old free | |
| 2420 | + # text field) gets its own option so it stays selected and round-trips. | |
| 2421 | + $separator_custom = in_array($separator_current, $separator_presets, true) ? '' : $separator_current; | |
| 2374 | 2422 | ?> |
| 2375 | 2423 | <div style="background: var(--dashboard-card-bg); padding: 20px; border-radius: 8px;"> |
| 2376 | 2424 | |
| 2377 | 2425 | <!-- Enable/Disable --> |
| @@ -2376,8 +2424,9 @@ | ||
| 2376 | 2424 | |
| 2377 | 2425 | <!-- Enable/Disable --> |
| 2378 | 2426 | <div style="margin-bottom: 24px;"> |
| 2379 | 2427 | <label style="display: flex; align-items: center; gap: 12px; cursor: pointer;"> |
| 2428 | + <input type="hidden" name="metasync_options[breadcrumbs][enabled]" value="0"> | |
| 2380 | 2429 | <input type="checkbox" |
| 2381 | 2430 | name="metasync_options[breadcrumbs][enabled]" |
| 2382 | 2431 | value="1" |
| 2383 | 2432 | <?php checked($options['enabled'], 1); ?> |
| @@ -2392,8 +2441,9 @@ | ||
| 2392 | 2441 | |
| 2393 | 2442 | <!-- Disable Schema Markup --> |
| 2394 | 2443 | <div style="margin-bottom: 24px;"> |
| 2395 | 2444 | <label style="display: flex; align-items: center; gap: 12px; cursor: pointer;"> |
| 2445 | + <input type="hidden" name="metasync_options[breadcrumbs][disable_schema]" value="0"> | |
| 2396 | 2446 | <input type="checkbox" |
| 2397 | 2447 | name="metasync_options[breadcrumbs][disable_schema]" |
| 2398 | 2448 | value="1" |
| 2399 | 2449 | <?php checked($options['disable_schema'], 1); ?> |
| @@ -2411,24 +2461,21 @@ | ||
| 2411 | 2461 | <label for="breadcrumb_separator" style="display: block; margin-bottom: 8px; font-weight: 500; color: var(--dashboard-text);"> |
| 2412 | 2462 | Separator Character |
| 2413 | 2463 | </label> |
| 2414 | 2464 | <div style="display: flex; gap: 12px; flex-wrap: wrap;"> |
| 2465 | + <?php foreach ($separator_presets as $separator_option) : ?> | |
| 2415 | 2466 | <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> |
| 2416 | - <input type="radio" name="metasync_options[breadcrumbs][separator]" value="»" <?php checked($options['separator'], '»'); ?>> | |
| 2417 | - <span style="color: var(--dashboard-text);">»</span> | |
| 2467 | + <input type="radio" name="metasync_options[breadcrumbs][separator]" value="<?php echo esc_attr($separator_option); ?>" <?php checked($separator_current, $separator_option); ?>> | |
| 2468 | + <span style="color: var(--dashboard-text);"><?php echo esc_html($separator_option); ?></span> | |
| 2418 | 2469 | </label> |
| 2419 | - <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> | |
| 2420 | - <input type="radio" name="metasync_options[breadcrumbs][separator]" value="/" <?php checked($options['separator'], '/'); ?>> | |
| 2421 | - <span style="color: var(--dashboard-text);">/</span> | |
| 2422 | - </label> | |
| 2423 | - <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> | |
| 2424 | - <input type="radio" name="metasync_options[breadcrumbs][separator]" value=">" <?php checked($options['separator'], '>'); ?>> | |
| 2425 | - <span style="color: var(--dashboard-text);">></span> | |
| 2426 | - </label> | |
| 2427 | - <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> | |
| 2428 | - <input type="radio" name="metasync_options[breadcrumbs][separator]" value="·" <?php checked($options['separator'], '·'); ?>> | |
| 2429 | - <span style="color: var(--dashboard-text);">·</span> | |
| 2430 | - </label> | |
| 2470 | + <?php endforeach; ?> | |
| 2471 | + <div style="display: flex; align-items: center; gap: 8px;"> | |
| 2472 | + <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> | |
| 2473 | + <input type="radio" id="metasync-breadcrumb-separator-custom" name="metasync_options[breadcrumbs][separator]" value="<?php echo esc_attr($separator_custom); ?>" <?php checked($separator_custom !== ''); ?>> | |
| 2474 | + <span style="color: var(--dashboard-text);">Custom</span> | |
| 2475 | + </label> | |
| 2476 | + <input type="text" value="<?php echo esc_attr($separator_custom); ?>" placeholder="~" maxlength="16" aria-label="Custom separator character" oninput="var r=document.getElementById('metasync-breadcrumb-separator-custom');r.value=this.value;r.checked=true" style="width: 80px; padding: 8px 10px; background: var(--dashboard-input-bg); border: 1px solid var(--dashboard-border); border-radius: 6px; color: var(--dashboard-text); font-size: 14px;"> | |
| 2477 | + </div> | |
| 2431 | 2478 | </div> |
| 2432 | 2479 | <p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2433 | 2480 | Choose how to separate breadcrumb items |
| 2434 | 2481 | </p> |
| @@ -2468,8 +2515,9 @@ | ||
| 2468 | 2515 | |
| 2469 | 2516 | <!-- Show Current Page --> |
| 2470 | 2517 | <div style="margin-bottom: 24px;"> |
| 2471 | 2518 | <label style="display: flex; align-items: center; gap: 12px; cursor: pointer;"> |
| 2519 | + <input type="hidden" name="metasync_options[breadcrumbs][show_current_page]" value="0"> | |
| 2472 | 2520 | <input type="checkbox" |
| 2473 | 2521 | name="metasync_options[breadcrumbs][show_current_page]" |
| 2474 | 2522 | value="1" |
| 2475 | 2523 | <?php checked($options['show_current_page'], 1); ?> |