| 1 |
<?php |
| 2 |
// If this file is called directly, abort. |
| 3 |
if (!defined('ABSPATH')) { |
| 4 |
exit; |
| 5 |
} |
| 6 |
|
| 7 |
/** |
| 8 |
* Settings field callbacks and accordion/section helpers extracted from Metasync_Admin. |
| 9 |
* |
| 10 |
* @package Metasync |
| 11 |
* @subpackage Metasync/includes |
| 12 |
*/ |
| 13 |
class Metasync_Settings_Fields { |
| 14 |
|
| 15 |
private static $instance = null; |
| 16 |
|
| 17 |
/** |
| 18 |
* Reference to the admin instance for callbacks to non-extracted admin methods. |
| 19 |
* |
| 20 |
* @var Metasync_Admin|null |
| 21 |
*/ |
| 22 |
private $admin_instance = null; |
| 23 |
|
| 24 |
private function __construct() {} |
| 25 |
|
| 26 |
/** |
| 27 |
* @return self |
| 28 |
*/ |
| 29 |
public static function instance() { |
| 30 |
if (null === self::$instance) { |
| 31 |
self::$instance = new self(); |
| 32 |
} |
| 33 |
return self::$instance; |
| 34 |
} |
| 35 |
|
| 36 |
/** |
| 37 |
* Inject the admin instance so callbacks to non-extracted methods still work. |
| 38 |
* |
| 39 |
* @param Metasync_Admin $admin |
| 40 |
*/ |
| 41 |
public function set_admin_instance($admin) { |
| 42 |
$this->admin_instance = $admin; |
| 43 |
} |
| 44 |
|
| 45 |
// ──────────────────────────────────────────────────────────────── |
| 46 |
// Accordion / Section helpers |
| 47 |
// ──────────────────────────────────────────────────────────────── |
| 48 |
|
| 49 |
public function get_accordion_sections_config() { |
| 50 |
return array( |
| 51 |
'connection' => array( |
| 52 |
'title' => 'Connection & Authentication', |
| 53 |
'description' => 'Manage your API connection and authentication settings', |
| 54 |
'icon' => 'admin-network', |
| 55 |
'priority' => 10, |
| 56 |
'default_open' => true, |
| 57 |
'fields' => array( |
| 58 |
'searchatlas_api_key', |
| 59 |
'apikey' |
| 60 |
) |
| 61 |
), |
| 62 |
'otto_ssr' => array( |
| 63 |
'title' => Metasync::get_whitelabel_otto_name() . ' Server-Side Rendering', |
| 64 |
'description' => 'Configure ' . Metasync::get_whitelabel_otto_name() . ' rendering and display options', |
| 65 |
'icon' => 'performance', |
| 66 |
'priority' => 20, |
| 67 |
'default_open' => false, |
| 68 |
'fields' => array( |
| 69 |
'otto_pixel_uuid', |
| 70 |
'otto_disable_on_loggedin', |
| 71 |
'otto_disable_preview_button', |
| 72 |
'otto_wp_rocket_compat', |
| 73 |
) |
| 74 |
), |
| 75 |
'edge_cache' => array( |
| 76 |
'title' => 'Edge Cache / CDN', |
| 77 |
'description' => 'Configure CDN credentials for cache-tag purging', |
| 78 |
'icon' => 'admin-site-alt3', |
| 79 |
'priority' => 22, |
| 80 |
'default_open' => false, |
| 81 |
'render_callback' => array('Metasync_Edge_Cache_Settings', 'render'), |
| 82 |
), |
| 83 |
'bot_detection' => array( |
| 84 |
'title' => 'Bot Detection & Filtering', |
| 85 |
'description' => 'Manage bot traffic and reduce unnecessary API calls', |
| 86 |
'icon' => 'filter', |
| 87 |
'priority' => 25, |
| 88 |
'default_open' => false, |
| 89 |
'fields' => array( |
| 90 |
'otto_disable_for_bots', |
| 91 |
'otto_bot_whitelist', |
| 92 |
'otto_bot_blacklist', |
| 93 |
'otto_bot_statistics_link' |
| 94 |
) |
| 95 |
), |
| 96 |
'breadcrumbs' => array( |
| 97 |
'title' => 'Breadcrumbs', |
| 98 |
'description' => 'Configure breadcrumb navigation display', |
| 99 |
'icon' => 'format-links', |
| 100 |
'priority' => 35, |
| 101 |
'default_open' => false, |
| 102 |
'render_callback' => array($this, 'render_breadcrumbs_section') |
| 103 |
), |
| 104 |
'open_graph' => array( |
| 105 |
'title' => 'Open Graph', |
| 106 |
'description' => 'Control which Open Graph and article meta tags are output', |
| 107 |
'icon' => 'share', |
| 108 |
'priority' => 38, |
| 109 |
'default_open' => false, |
| 110 |
'fields' => array( |
| 111 |
'og_image_dimensions', |
| 112 |
'article_timestamps', |
| 113 |
'article_author', |
| 114 |
'article_section', |
| 115 |
'article_tags', |
| 116 |
'twitter_image_alt' |
| 117 |
) |
| 118 |
), |
| 119 |
'editor_settings' => array( |
| 120 |
'title' => 'Post/Page Editor Settings', |
| 121 |
'description' => 'Customize meta boxes and editor functionality', |
| 122 |
'icon' => 'edit', |
| 123 |
'priority' => 40, |
| 124 |
'default_open' => false, |
| 125 |
'fields' => array( |
| 126 |
'disable_common_robots_metabox', |
| 127 |
'disable_advance_robots_metabox', |
| 128 |
'disable_redirection_metabox', |
| 129 |
'disable_canonical_metabox', |
| 130 |
'disable_social_opengraph_metabox', |
| 131 |
'disable_schema_markup_metabox', |
| 132 |
'disable_seo_metabox', |
| 133 |
'open_external_links' |
| 134 |
) |
| 135 |
), |
| 136 |
'user_management' => array( |
| 137 |
'title' => 'User Management for Content', |
| 138 |
'description' => 'Configure which users are allowed to be authors of content synced.', |
| 139 |
'icon' => 'groups', |
| 140 |
'priority' => 50, |
| 141 |
'default_open' => false, |
| 142 |
'fields' => array( |
| 143 |
'content_genius_sync_roles' |
| 144 |
) |
| 145 |
), |
| 146 |
'content_rendering' => array( |
| 147 |
'title' => 'Content Rendering', |
| 148 |
'description' => 'Configure how synced content is stored and rendered by your page builder', |
| 149 |
'icon' => 'admin-appearance', |
| 150 |
'priority' => 55, |
| 151 |
'default_open' => false, |
| 152 |
'fields' => array( |
| 153 |
'default_page_builder' |
| 154 |
) |
| 155 |
), |
| 156 |
'llms_txt' => array( |
| 157 |
'title' => 'LLMs.txt', |
| 158 |
'description' => 'Publish a standards-compliant /llms.txt so AI search engines and assistants can discover your content', |
| 159 |
'icon' => 'media-text', |
| 160 |
'priority' => 56, |
| 161 |
'default_open' => false, |
| 162 |
'render_callback' => array($this, 'render_llms_txt_section'), |
| 163 |
), |
| 164 |
'advanced' => array( |
| 165 |
'title' => 'Plugin Settings', |
| 166 |
'description' => 'System configuration and maintenance options', |
| 167 |
'icon' => 'admin-settings', |
| 168 |
'priority' => 60, |
| 169 |
'default_open' => false, |
| 170 |
'fields' => array( |
| 171 |
'permalink_structure', |
| 172 |
'hide_dashboard_framework', |
| 173 |
'show_admin_bar_status', |
| 174 |
'enable_auto_updates', |
| 175 |
'import_external_data' |
| 176 |
) |
| 177 |
) |
| 178 |
); |
| 179 |
} |
| 180 |
|
| 181 |
public function get_advanced_accordion_config() { |
| 182 |
$config = array(); |
| 183 |
|
| 184 |
$user = wp_get_current_user(); |
| 185 |
if (in_array('administrator', (array) $user->roles)) { |
| 186 |
$config['plugin_access'] = array( |
| 187 |
'title' => 'User Roles with Plugin Access', |
| 188 |
'description' => 'Control which user roles can see and access this plugin', |
| 189 |
'icon' => 'admin-users', |
| 190 |
'priority' => 5, |
| 191 |
'default_open' => false, |
| 192 |
'render_callback' => array($this, 'render_plugin_access_roles_section') |
| 193 |
); |
| 194 |
} |
| 195 |
|
| 196 |
$config['debug_mode'] = array( |
| 197 |
'title' => 'Debug Mode', |
| 198 |
'description' => 'Manage debug mode with automatic disable and safety limits', |
| 199 |
'icon' => 'info', |
| 200 |
'priority' => 8, |
| 201 |
'default_open' => false, |
| 202 |
'render_callback' => array($this->admin_instance, 'render_debug_mode_section') |
| 203 |
); |
| 204 |
|
| 205 |
$config['error_logs'] = array( |
| 206 |
'title' => 'Error Logs', |
| 207 |
'description' => 'View and manage error logs to troubleshoot issues', |
| 208 |
'icon' => 'warning', |
| 209 |
'priority' => 10, |
| 210 |
'default_open' => true, |
| 211 |
'render_callback' => array($this->admin_instance, 'render_error_log_content') |
| 212 |
); |
| 213 |
|
| 214 |
$config['execution_settings'] = array( |
| 215 |
'title' => 'Execution Settings', |
| 216 |
'description' => 'Configure resource limits and execution parameters', |
| 217 |
'icon' => 'controls-play', |
| 218 |
'priority' => 15, |
| 219 |
'default_open' => false, |
| 220 |
'render_callback' => array($this, 'render_execution_settings_section') |
| 221 |
); |
| 222 |
|
| 223 |
$config['otto_cache'] = array( |
| 224 |
'title' => 'Cache Management', |
| 225 |
'description' => 'Manage ' . Metasync::get_whitelabel_otto_name() . ' cache and clear all cache plugins', |
| 226 |
'icon' => 'database', |
| 227 |
'priority' => 20, |
| 228 |
'default_open' => false, |
| 229 |
'render_callback' => array($this->admin_instance, 'render_otto_cache_management') |
| 230 |
); |
| 231 |
|
| 232 |
$config['db_cleanup'] = array( |
| 233 |
'title' => 'Database Cleanup', |
| 234 |
'description' => 'Remove orphaned data and schedule automated weekly cleanup', |
| 235 |
'icon' => 'trash', |
| 236 |
'priority' => 25, |
| 237 |
'default_open' => false, |
| 238 |
'render_callback' => array($this->admin_instance, 'render_db_cleanup_section') |
| 239 |
); |
| 240 |
|
| 241 |
$config['performance'] = array( |
| 242 |
'title' => 'Performance & CPU Load', |
| 243 |
'description' => 'Configure CPU load thresholds to prevent processing during peak server load', |
| 244 |
'icon' => 'chart-line', |
| 245 |
'priority' => 27, |
| 246 |
'default_open' => false, |
| 247 |
'render_callback' => array($this->admin_instance, 'render_cpu_monitor_section') |
| 248 |
); |
| 249 |
|
| 250 |
$config['reset_settings'] = array( |
| 251 |
'title' => 'Reset Plugin Settings', |
| 252 |
'description' => 'Reset all plugin settings to default values', |
| 253 |
'icon' => 'update', |
| 254 |
'priority' => 30, |
| 255 |
'default_open' => false, |
| 256 |
'render_callback' => array($this, 'render_reset_settings_section') |
| 257 |
); |
| 258 |
|
| 259 |
return $config; |
| 260 |
} |
| 261 |
|
| 262 |
public function render_advanced_accordion() { |
| 263 |
$sections_config = $this->get_advanced_accordion_config(); |
| 264 |
|
| 265 |
uasort($sections_config, function($a, $b) { |
| 266 |
return $a['priority'] - $b['priority']; |
| 267 |
}); |
| 268 |
|
| 269 |
echo '<div class="metasync-settings-accordion">'; |
| 270 |
|
| 271 |
foreach ($sections_config as $section_key => $section_data) { |
| 272 |
$section_id = 'metasync-advanced-section-' . $section_key; |
| 273 |
$is_open = $section_data['default_open']; |
| 274 |
$aria_expanded = $is_open ? 'true' : 'false'; |
| 275 |
$content_state = $is_open ? 'open' : 'closed'; |
| 276 |
|
| 277 |
echo '<div class="metasync-accordion-section" data-section="' . esc_attr($section_key) . '">'; |
| 278 |
|
| 279 |
echo '<div class="metasync-accordion-header" role="button" tabindex="0" aria-expanded="' . $aria_expanded . '" aria-controls="' . $section_id . '">'; |
| 280 |
echo '<div class="metasync-accordion-title">'; |
| 281 |
echo '<span class="metasync-accordion-icon"><span class="dashicons dashicons-' . esc_attr($section_data['icon']) . '"></span></span>'; |
| 282 |
echo '<div class="metasync-accordion-text">'; |
| 283 |
echo '<h3>' . esc_html($section_data['title']) . '</h3>'; |
| 284 |
echo '<p class="metasync-accordion-description">' . esc_html($section_data['description']) . '</p>'; |
| 285 |
echo '</div>'; |
| 286 |
echo '</div>'; |
| 287 |
echo '<button type="button" class="metasync-accordion-toggle" aria-label="Toggle section">'; |
| 288 |
echo '<span class="toggle-icon">▼</span>'; |
| 289 |
echo '</button>'; |
| 290 |
echo '</div>'; |
| 291 |
|
| 292 |
echo '<div class="metasync-accordion-content" id="' . $section_id . '" data-state="' . $content_state . '">'; |
| 293 |
|
| 294 |
if (isset($section_data['render_callback']) && is_callable($section_data['render_callback'])) { |
| 295 |
call_user_func($section_data['render_callback']); |
| 296 |
} |
| 297 |
|
| 298 |
echo '</div>'; |
| 299 |
echo '</div>'; |
| 300 |
} |
| 301 |
|
| 302 |
echo '</div>'; |
| 303 |
} |
| 304 |
|
| 305 |
public function render_reset_settings_section() { |
| 306 |
?> |
| 307 |
<div style="background: var(--dashboard-card-bg); padding: 20px; border-radius: 8px;"> |
| 308 |
<div style="background: rgba(255, 243, 205, 0.1); border: 1px solid rgba(255, 234, 167, 0.3); border-radius: 8px; padding: 20px; margin-bottom: 20px;"> |
| 309 |
<h4 style="color: var(--dashboard-warning, #f59e0b); margin: 0 0 12px 0; display: flex; align-items: center; gap: 8px;"> |
| 310 |
<span class="dashicons dashicons-warning" style="color:var(--dashboard-warning,#f59e0b);font-size:18px;width:18px;height:18px;"></span> |
| 311 |
<span>Important Warning</span> |
| 312 |
</h4> |
| 313 |
<p style="color: var(--dashboard-text-secondary); margin: 0 0 12px 0;">This action will permanently delete:</p> |
| 314 |
<ul style="color: var(--dashboard-text-secondary); margin: 0 0 12px 20px; line-height: 1.8;"> |
| 315 |
<li>All API keys and authentication tokens</li> |
| 316 |
<li>White label branding settings</li> |
| 317 |
<li>Plugin configuration and preferences</li> |
| 318 |
<li>Instant indexing settings</li> |
| 319 |
<li>Media optimization settings and cache</li> |
| 320 |
<li>Code minification settings</li> |
| 321 |
<li>All cached data and crawl information</li> |
| 322 |
</ul> |
| 323 |
<p style="color: var(--dashboard-warning, #f59e0b); margin: 0; font-weight: 600;">You will need to reconfigure the plugin completely after this reset.</p> |
| 324 |
</div> |
| 325 |
<form method="post" action="" onsubmit="return confirmClearSettings(event)"> |
| 326 |
<?php wp_nonce_field('metasync_clear_all_settings_nonce', 'clear_all_settings_nonce'); ?> |
| 327 |
<input type="hidden" name="clear_all_settings" value="yes" /> |
| 328 |
<button type="submit" class="metasync-btn-danger" style="background: var(--dashboard-error, #ef4444); color: #ffffff; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 500; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 2px 4px rgba(239, 68, 68, 0.2);" onmouseover="this.style.background='#dc2626'; this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 8px rgba(239, 68, 68, 0.3)';" onmouseout="this.style.background='var(--dashboard-error, #ef4444)'; this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 4px rgba(239, 68, 68, 0.2)';"> |
| 329 |
<span class="dashicons dashicons-trash" style="margin-top:3px;font-size:15px;width:15px;height:15px;"></span> Clear All Settings |
| 330 |
</button> |
| 331 |
</form> |
| 332 |
</div> |
| 333 |
<script> |
| 334 |
function confirmClearSettings(event) { |
| 335 |
event.preventDefault(); |
| 336 |
|
| 337 |
var firstConfirm = confirm("⚠️ WARNING: This will permanently delete ALL plugin settings!\n\nThis action cannot be undone. Are you sure you want to continue?"); |
| 338 |
if (!firstConfirm) { |
| 339 |
return false; |
| 340 |
} |
| 341 |
|
| 342 |
var secondConfirm = confirm("🚨 FINAL WARNING 🚨\n\nThis will delete:\n• All API keys and authentication tokens\n• White label branding settings\n• Plugin configuration and preferences\n• Instant indexing settings\n• Media optimization settings and cache\n• Code minification settings\n• All cached data\n\nYou will need to reconfigure the entire plugin from scratch.\n\nType 'DELETE' in the next prompt to confirm."); |
| 343 |
if (!secondConfirm) { |
| 344 |
return false; |
| 345 |
} |
| 346 |
|
| 347 |
var typeConfirm = prompt("Type 'DELETE' (in capital letters) to confirm you want to permanently clear all settings:"); |
| 348 |
if (typeConfirm !== 'DELETE') { |
| 349 |
alert("Settings reset cancelled. Type 'DELETE' exactly to confirm."); |
| 350 |
return false; |
| 351 |
} |
| 352 |
|
| 353 |
event.target.submit(); |
| 354 |
return false; |
| 355 |
} |
| 356 |
</script> |
| 357 |
<?php |
| 358 |
} |
| 359 |
|
| 360 |
public function render_google_index_section() { |
| 361 |
if (!function_exists('google_index_direct')) { |
| 362 |
if (file_exists(plugin_dir_path(dirname(__FILE__)) . 'google-index/google-index-init.php')) { |
| 363 |
require_once plugin_dir_path(dirname(__FILE__)) . 'google-index/google-index-init.php'; |
| 364 |
} else { |
| 365 |
error_log('MetaSync Google Index: google-index-init.php not found at ' . plugin_dir_path(dirname(__FILE__)) . 'google-index/google-index-init.php'); |
| 366 |
return; |
| 367 |
} |
| 368 |
} |
| 369 |
|
| 370 |
$google_index = google_index_direct(); |
| 371 |
$service_info = $google_index->get_service_account_info(); |
| 372 |
$is_configured = !isset($service_info['error']); |
| 373 |
|
| 374 |
$saved_json_display = $is_configured ? $google_index->get_redacted_config_json() : ''; |
| 375 |
|
| 376 |
include plugin_dir_path(dirname(__FILE__)) . 'views/metasync-google-index-api-settings.php'; |
| 377 |
|
| 378 |
// Render post types selection |
| 379 |
$options = get_option('metasync_options_instant_indexing', ['post_types' => []]); |
| 380 |
$post_types_settings = isset($options['post_types']) && is_array($options['post_types']) ? $options['post_types'] : []; |
| 381 |
include plugin_dir_path(dirname(__FILE__)) . 'views/metasync-google-instant-post-types.php'; |
| 382 |
} |
| 383 |
|
| 384 |
public function render_bing_index_section() { |
| 385 |
require_once plugin_dir_path(dirname(__FILE__)) . 'bing-index/class-metasync-bing-instant-index.php'; |
| 386 |
$bing_index = new Metasync_Bing_Instant_Index(); |
| 387 |
$api_key = $bing_index->get_setting('api_key'); |
| 388 |
$endpoint = $bing_index->get_setting('endpoint', 'indexnow'); |
| 389 |
$post_types_settings = $bing_index->get_setting('post_types', []); |
| 390 |
$is_configured = !empty($api_key); |
| 391 |
|
| 392 |
$post_types = get_post_types(['public' => true], 'objects'); |
| 393 |
|
| 394 |
?> |
| 395 |
<div style="padding: 20px;"> |
| 396 |
<!-- About IndexNow (Collapsible) --> |
| 397 |
<details style="margin-bottom: 20px;"> |
| 398 |
<summary style="cursor: pointer; font-weight: 600; color: var(--dashboard-text-primary);"> |
| 399 |
About IndexNow Protocol |
| 400 |
</summary> |
| 401 |
<div style="margin-top: 10px; padding: 15px; background: rgba(255, 255, 255, 0.03); border-radius: 4px;"> |
| 402 |
<p style="color: var(--dashboard-text-secondary); margin: 0 0 10px 0;"> |
| 403 |
IndexNow is a simple protocol that allows websites to instantly notify search engines about URL changes. |
| 404 |
It's supported by Bing, Yandex, Naver, Seznam, and other search engines. |
| 405 |
</p> |
| 406 |
<ul style="color: var(--dashboard-text-secondary); margin: 0 0 10px 20px;"> |
| 407 |
<li>✓ Instant notification to multiple search engines</li> |
| 408 |
<li>✓ Simple API key authentication (no OAuth required)</li> |
| 409 |
<li>✓ Supports batch URL submissions (up to 10,000 URLs)</li> |
| 410 |
<li>✓ Free to use with no quotas</li> |
| 411 |
<li>✓ Fire-and-forget protocol (no status checking needed)</li> |
| 412 |
</ul> |
| 413 |
<p style="color: var(--dashboard-text-secondary); margin: 0;"> |
| 414 |
<strong>Resources:</strong> |
| 415 |
<a href="https://www.indexnow.org/documentation" target="_blank" style="color: var(--dashboard-accent);">IndexNow Documentation</a> | |
| 416 |
<a href="https://www.bing.com/webmasters" target="_blank" style="color: var(--dashboard-accent);">Bing Webmaster Tools</a> |
| 417 |
</p> |
| 418 |
</div> |
| 419 |
</details> |
| 420 |
|
| 421 |
<!-- Configuration Status --> |
| 422 |
<div style="margin-bottom: 20px;"> |
| 423 |
<?php if ($is_configured): ?> |
| 424 |
<div style="padding: 12px; background: rgba(76, 175, 80, 0.1); border-left: 4px solid #4caf50; border-radius: 4px;"> |
| 425 |
<p style="margin: 0; color: var(--dashboard-text-primary);"> |
| 426 |
<strong style="color: #4caf50;">IndexNow API Configured</strong><br> |
| 427 |
<span style="color: var(--dashboard-text-secondary); font-size: 0.95em;"> |
| 428 |
API Key: <code style="padding: 2px 6px; background: rgba(0,0,0,0.1); border-radius: 3px;"><?php echo esc_html(substr($api_key, 0, 8) . '...' . substr($api_key, -8)); ?></code> |
| 429 |
</span> |
| 430 |
</p> |
| 431 |
</div> |
| 432 |
<?php else: ?> |
| 433 |
<div style="padding: 12px; background: rgba(255, 152, 0, 0.1); border-left: 4px solid #ff9800; border-radius: 4px;"> |
| 434 |
<p style="margin: 0; color: var(--dashboard-text-primary);"> |
| 435 |
<strong style="color: #ff9800;">Configuration Required</strong><br> |
| 436 |
<span style="color: var(--dashboard-text-secondary); font-size: 0.95em;"> |
| 437 |
Configure your IndexNow API key below to enable instant indexing with Bing and other search engines. |
| 438 |
</span> |
| 439 |
</p> |
| 440 |
</div> |
| 441 |
<?php endif; ?> |
| 442 |
</div> |
| 443 |
|
| 444 |
<!-- Settings Fields --> |
| 445 |
<table class="form-table" style="margin-top: 0;"> |
| 446 |
<tr> |
| 447 |
<th scope="row" style="width: 200px; padding-top: 15px;"> |
| 448 |
<label for="metasync_bing_api_key_inline">IndexNow API Key <span style="color: #d63638;">*</span></label> |
| 449 |
</th> |
| 450 |
<td style="padding-top: 15px;"> |
| 451 |
<input type="text" |
| 452 |
name="metasync_bing_api_key_inline" |
| 453 |
id="metasync_bing_api_key_inline" |
| 454 |
class="large-text" |
| 455 |
value="<?php echo esc_attr($api_key); ?>" |
| 456 |
placeholder="Enter your IndexNow API key (32+ character hexadecimal string)" /> |
| 457 |
<br> |
| 458 |
<button type="button" |
| 459 |
id="generate-bing-api-key-inline" |
| 460 |
class="button button-secondary" |
| 461 |
style="margin-top: 8px;"> |
| 462 |
Generate Random API Key |
| 463 |
</button> |
| 464 |
<p class="description" style="margin-top: 8px;"> |
| 465 |
Your IndexNow API key is required to submit URLs for instant indexing. You can generate a random key or use your own (32+ character hexadecimal string). |
| 466 |
After saving, a verification file will be automatically created at your site root. |
| 467 |
</p> |
| 468 |
</td> |
| 469 |
</tr> |
| 470 |
|
| 471 |
<tr> |
| 472 |
<th scope="row" style="padding-top: 15px;"> |
| 473 |
<label>API Endpoint</label> |
| 474 |
</th> |
| 475 |
<td style="padding-top: 15px;"> |
| 476 |
<fieldset> |
| 477 |
<label style="display: block; margin-bottom: 8px;"> |
| 478 |
<input type="radio" |
| 479 |
name="metasync_bing_endpoint_inline" |
| 480 |
value="indexnow" |
| 481 |
<?php checked($endpoint, 'indexnow'); ?>> |
| 482 |
<strong>IndexNow.org</strong> (Recommended) |
| 483 |
<span style="color: var(--dashboard-text-secondary); font-size: 0.9em; display: block; margin-left: 24px;"> |
| 484 |
Notifies Bing, Yandex, Naver, Seznam, and other participating search engines |
| 485 |
</span> |
| 486 |
</label> |
| 487 |
<label style="display: block;"> |
| 488 |
<input type="radio" |
| 489 |
name="metasync_bing_endpoint_inline" |
| 490 |
value="bing" |
| 491 |
<?php checked($endpoint, 'bing'); ?>> |
| 492 |
<strong>Bing.com</strong> (Bing-specific) |
| 493 |
<span style="color: var(--dashboard-text-secondary); font-size: 0.9em; display: block; margin-left: 24px;"> |
| 494 |
Direct submission to Bing only |
| 495 |
</span> |
| 496 |
</label> |
| 497 |
</fieldset> |
| 498 |
<p class="description"> |
| 499 |
Select which endpoint to use for submitting URLs. The IndexNow.org endpoint is recommended as it notifies multiple search engines at once. |
| 500 |
</p> |
| 501 |
</td> |
| 502 |
</tr> |
| 503 |
|
| 504 |
<tr> |
| 505 |
<th scope="row" style="padding-top: 15px;"> |
| 506 |
<label>Auto-Submit Post Types</label> |
| 507 |
</th> |
| 508 |
<td style="padding-top: 15px;"> |
| 509 |
<fieldset> |
| 510 |
<?php foreach ($post_types as $post_type): ?> |
| 511 |
<label style="display: inline-block; margin-right: 20px; margin-bottom: 8px;"> |
| 512 |
<input type="checkbox" |
| 513 |
name="metasync_bing_post_types_inline[<?php echo esc_attr($post_type->name); ?>]" |
| 514 |
value="<?php echo esc_attr($post_type->name); ?>" |
| 515 |
<?php checked(in_array($post_type->name, $post_types_settings, true)); ?>> |
| 516 |
<?php echo esc_html($post_type->label); ?> |
| 517 |
</label> |
| 518 |
<?php endforeach; ?> |
| 519 |
</fieldset> |
| 520 |
<p class="description"> |
| 521 |
Selected post types will be automatically submitted to IndexNow when published or updated. |
| 522 |
</p> |
| 523 |
</td> |
| 524 |
</tr> |
| 525 |
|
| 526 |
<tr> |
| 527 |
<th scope="row" style="padding-top: 15px;"> |
| 528 |
<label>Plugin Source Control</label> |
| 529 |
</th> |
| 530 |
<td style="padding-top: 15px;"> |
| 531 |
<fieldset> |
| 532 |
<label style="display: flex; align-items: flex-start; gap: 8px;"> |
| 533 |
<input type="checkbox" |
| 534 |
name="metasync_bing_disable_other_plugins_inline" |
| 535 |
value="1" |
| 536 |
<?php checked($bing_index->get_setting('disable_other_plugins', true), true); ?> |
| 537 |
style="margin-top: 2px;"> |
| 538 |
<span> |
| 539 |
<strong>Disable other IndexNow plugins</strong> |
| 540 |
<span style="display: block; color: var(--dashboard-text-secondary); font-size: 0.9em; margin-top: 4px; font-weight: normal;"> |
| 541 |
When enabled, Our plugin will be the exclusive source for IndexNow submissions in Bing Webmaster Tools. |
| 542 |
This disables IndexNow features in Yoast SEO, Rank Math, and other competing plugins to prevent duplicate submissions. |
| 543 |
</span> |
| 544 |
</span> |
| 545 |
</label> |
| 546 |
</fieldset> |
| 547 |
</td> |
| 548 |
</tr> |
| 549 |
</table> |
| 550 |
|
| 551 |
</div> |
| 552 |
|
| 553 |
<script> |
| 554 |
jQuery(document).ready(function($) { |
| 555 |
$('#generate-bing-api-key-inline').on('click', function() { |
| 556 |
const array = new Uint8Array(16); |
| 557 |
crypto.getRandomValues(array); |
| 558 |
const hexString = Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(''); |
| 559 |
$('#metasync_bing_api_key_inline').val(hexString); |
| 560 |
|
| 561 |
$('#enable_binginstantindex').prop('checked', true); |
| 562 |
|
| 563 |
$('#metasync_bing_api_key_inline').trigger('change'); |
| 564 |
}); |
| 565 |
|
| 566 |
$('#metasync_bing_api_key_inline').on('input', function() { |
| 567 |
const apiKey = $(this).val().trim(); |
| 568 |
if (apiKey.length >= 8) { |
| 569 |
$('#enable_binginstantindex').prop('checked', true); |
| 570 |
} |
| 571 |
}); |
| 572 |
|
| 573 |
function toggleBingConfig() { |
| 574 |
const isEnabled = $('#enable_binginstantindex').is(':checked'); |
| 575 |
const $apiConfig = $('#enable_binginstantindex').closest('tr').nextAll('tr').first(); |
| 576 |
if (isEnabled) { |
| 577 |
$apiConfig.show(); |
| 578 |
} else { |
| 579 |
$apiConfig.hide(); |
| 580 |
} |
| 581 |
} |
| 582 |
|
| 583 |
toggleBingConfig(); |
| 584 |
|
| 585 |
$('#enable_binginstantindex').on('change', toggleBingConfig); |
| 586 |
}); |
| 587 |
</script> |
| 588 |
|
| 589 |
<style> |
| 590 |
.form-table th { |
| 591 |
color: var(--dashboard-text-primary); |
| 592 |
} |
| 593 |
|
| 594 |
.form-table td { |
| 595 |
color: var(--dashboard-text-secondary); |
| 596 |
} |
| 597 |
|
| 598 |
.form-table code { |
| 599 |
padding: 2px 6px; |
| 600 |
background: rgba(0, 0, 0, 0.1); |
| 601 |
border-radius: 3px; |
| 602 |
font-size: 0.9em; |
| 603 |
} |
| 604 |
|
| 605 |
details summary { |
| 606 |
transition: color 0.2s; |
| 607 |
} |
| 608 |
|
| 609 |
details summary:hover { |
| 610 |
color: var(--dashboard-accent); |
| 611 |
} |
| 612 |
|
| 613 |
details[open] summary { |
| 614 |
margin-bottom: 10px; |
| 615 |
} |
| 616 |
</style> |
| 617 |
<?php |
| 618 |
} |
| 619 |
|
| 620 |
public function render_plugin_access_roles_section() { |
| 621 |
$general_options = Metasync::get_option('general'); |
| 622 |
|
| 623 |
$setting_exists = isset($general_options['plugin_access_roles']); |
| 624 |
$selected_roles = $general_options['plugin_access_roles'] ?? null; |
| 625 |
|
| 626 |
if (is_string($selected_roles)) { |
| 627 |
$selected_roles = array($selected_roles); |
| 628 |
} elseif (!is_array($selected_roles)) { |
| 629 |
$selected_roles = null; |
| 630 |
} |
| 631 |
|
| 632 |
if (!function_exists('wp_roles')) { |
| 633 |
require_once(ABSPATH . 'wp-admin/includes/user.php'); |
| 634 |
} |
| 635 |
global $wp_roles; |
| 636 |
|
| 637 |
if (!isset($wp_roles) || !is_object($wp_roles)) { |
| 638 |
$wp_roles = new WP_Roles(); |
| 639 |
} |
| 640 |
|
| 641 |
$all_roles = $wp_roles->roles; |
| 642 |
|
| 643 |
$all_roles_checked = is_array($selected_roles) && in_array('all', $selected_roles); |
| 644 |
?> |
| 645 |
<div style="background: var(--dashboard-card-bg); padding: 20px; border-radius: 8px;"> |
| 646 |
<p style="color: var(--dashboard-text-secondary); margin: 0 0 20px 0;"> |
| 647 |
Select which user roles can see and access this plugin's menu, settings, and options in the WordPress admin area. |
| 648 |
</p> |
| 649 |
|
| 650 |
<form method="post" action="<?php echo admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '&tab=advanced'); ?>" id="plugin-access-roles-form"> |
| 651 |
<?php wp_nonce_field('metasync_plugin_access_roles_nonce', 'plugin_access_roles_nonce'); ?> |
| 652 |
<input type="hidden" name="save_plugin_access_roles" value="yes" /> |
| 653 |
|
| 654 |
<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;"> |
| 655 |
|
| 656 |
<!-- All Roles Option --> |
| 657 |
<label class="metasync-role-option-all" style="display: flex; align-items: center; gap: 10px; padding: 12px; cursor: pointer; border-radius: 6px; transition: background 0.2s ease;"> |
| 658 |
<input type="checkbox" |
| 659 |
id="plugin-access-all-roles" |
| 660 |
name="plugin_access_roles[]" |
| 661 |
value="all" |
| 662 |
style="width: 18px; height: 18px; cursor: pointer;" |
| 663 |
<?php checked($all_roles_checked, true); ?> /> |
| 664 |
<strong style="color: var(--dashboard-text-primary);">All Roles</strong> |
| 665 |
</label> |
| 666 |
|
| 667 |
<!-- Divider --> |
| 668 |
<hr style="border: none; border-top: 1px solid var(--dashboard-border); margin: 12px 0;"> |
| 669 |
|
| 670 |
<?php |
| 671 |
if (!empty($all_roles) && is_array($all_roles)) { |
| 672 |
foreach ($all_roles as $role_key => $role_details) { |
| 673 |
if ($role_key === 'administrator') { |
| 674 |
continue; |
| 675 |
} |
| 676 |
|
| 677 |
if (!isset($role_details['name'])) { |
| 678 |
continue; |
| 679 |
} |
| 680 |
|
| 681 |
$is_checked = is_array($selected_roles) && in_array($role_key, $selected_roles); |
| 682 |
$role_name = translate_user_role($role_details['name']); |
| 683 |
?> |
| 684 |
<label class="metasync-role-option" style="display: flex; align-items: center; gap: 10px; padding: 10px 12px; cursor: pointer; border-radius: 6px; transition: background 0.2s ease;"> |
| 685 |
<input type="checkbox" |
| 686 |
class="plugin-access-individual-role" |
| 687 |
name="plugin_access_roles[]" |
| 688 |
value="<?php echo esc_attr($role_key); ?>" |
| 689 |
style="width: 18px; height: 18px; cursor: pointer;" |
| 690 |
<?php checked($is_checked, true); ?> /> |
| 691 |
<span style="color: var(--dashboard-text-primary);"><?php echo esc_html($role_name); ?></span> |
| 692 |
</label> |
| 693 |
<?php |
| 694 |
} |
| 695 |
} |
| 696 |
?> |
| 697 |
|
| 698 |
</div> |
| 699 |
|
| 700 |
<!-- Description --> |
| 701 |
<div style="background: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.3); border-radius: 8px; padding: 16px; margin: 20px 0;"> |
| 702 |
<p style="color: var(--dashboard-text-secondary); margin: 0; font-size: 13px;"> |
| 703 |
<strong style="color: var(--dashboard-info, #3b82f6);">How it works:</strong><br> |
| 704 |
<strong>Administrators always have access</strong> to this plugin regardless of settings.<br> |
| 705 |
<strong>By default</strong>, only Administrators can access the plugin (no roles selected).<br> |
| 706 |
If <strong>"All Roles"</strong> is selected, all users will see the plugin.<br> |
| 707 |
Users with unchecked roles will not see the plugin in their WordPress admin area. |
| 708 |
</p> |
| 709 |
</div> |
| 710 |
|
| 711 |
<button type="submit" class="metasync-btn-primary" style="background: var(--dashboard-gradient-primary); color: #ffffff; border: none; padding: 12px 24px; border-radius: 8px; font-weight: 500; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 8px rgba(0, 0, 0, 0.15)';" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 2px 4px rgba(0, 0, 0, 0.1)';"> |
| 712 |
Save Access Settings |
| 713 |
</button> |
| 714 |
</form> |
| 715 |
</div> |
| 716 |
<script> |
| 717 |
jQuery(document).ready(function($) { |
| 718 |
var $allRolesCheckbox = $('#plugin-access-all-roles'); |
| 719 |
var $individualRoles = $('.plugin-access-individual-role'); |
| 720 |
|
| 721 |
$allRolesCheckbox.on('change', function() { |
| 722 |
if ($(this).is(':checked')) { |
| 723 |
$individualRoles.prop('checked', false); |
| 724 |
} |
| 725 |
}); |
| 726 |
|
| 727 |
$individualRoles.on('change', function() { |
| 728 |
if ($(this).is(':checked')) { |
| 729 |
$allRolesCheckbox.prop('checked', false); |
| 730 |
} |
| 731 |
}); |
| 732 |
}); |
| 733 |
</script> |
| 734 |
<?php |
| 735 |
} |
| 736 |
|
| 737 |
public function get_default_execution_settings() { |
| 738 |
return array( |
| 739 |
'max_execution_time' => 30, |
| 740 |
'max_memory_limit' => 256, |
| 741 |
'log_batch_size' => 1000, |
| 742 |
'action_scheduler_batches' => 1, |
| 743 |
'otto_rate_limit' => 10, |
| 744 |
'otto_cache_ttl' => 30, |
| 745 |
'queue_cleanup_days' => 31 |
| 746 |
); |
| 747 |
} |
| 748 |
|
| 749 |
public function get_execution_setting($key, $default = null) { |
| 750 |
$settings = get_option('metasync_execution_settings', array()); |
| 751 |
$defaults = $this->get_default_execution_settings(); |
| 752 |
|
| 753 |
if (empty($settings)) { |
| 754 |
return isset($defaults[$key]) ? $defaults[$key] : $default; |
| 755 |
} |
| 756 |
|
| 757 |
return isset($settings[$key]) ? $settings[$key] : (isset($defaults[$key]) ? $defaults[$key] : $default); |
| 758 |
} |
| 759 |
|
| 760 |
public function get_all_execution_settings() { |
| 761 |
$settings = get_option('metasync_execution_settings', array()); |
| 762 |
$defaults = $this->get_default_execution_settings(); |
| 763 |
|
| 764 |
return wp_parse_args($settings, $defaults); |
| 765 |
} |
| 766 |
|
| 767 |
public function can_change_memory_limit() { |
| 768 |
$current_limit = ini_get('memory_limit'); |
| 769 |
|
| 770 |
$test_result = @ini_set('memory_limit', $current_limit); |
| 771 |
|
| 772 |
return $test_result !== false; |
| 773 |
} |
| 774 |
|
| 775 |
public function get_server_limits() { |
| 776 |
$max_execution_time = ini_get('max_execution_time'); |
| 777 |
$memory_limit = ini_get('memory_limit'); |
| 778 |
|
| 779 |
// Prefer the server-configured value: WordPress (wp_raise_memory_limit) |
| 780 |
// or this plugin (apply_memory_limit) may have already changed the |
| 781 |
// runtime limit via ini_set, so ini_get no longer reflects the server |
| 782 |
// configuration. get_cfg_var reads the php.ini value untouched. |
| 783 |
$config_memory_limit = get_cfg_var('memory_limit'); |
| 784 |
if ($config_memory_limit !== false && $config_memory_limit !== '') { |
| 785 |
$memory_limit = $config_memory_limit; |
| 786 |
} |
| 787 |
|
| 788 |
$memory_limit_mb = $this->parse_memory_limit_to_mb($memory_limit); |
| 789 |
|
| 790 |
$can_change_memory = $this->can_change_memory_limit(); |
| 791 |
|
| 792 |
$memory_limit_display = $memory_limit_mb == -1 ? 'Unlimited' : $memory_limit_mb . ' MB'; |
| 793 |
|
| 794 |
return array( |
| 795 |
'max_execution_time' => $max_execution_time == -1 ? 'Unlimited' : $max_execution_time . ' seconds', |
| 796 |
'memory_limit' => $memory_limit_display, |
| 797 |
'max_execution_time_raw' => $max_execution_time, |
| 798 |
'memory_limit_raw' => $memory_limit_mb, |
| 799 |
'can_change_memory' => $can_change_memory |
| 800 |
); |
| 801 |
} |
| 802 |
|
| 803 |
/** |
| 804 |
* Allowed range for the Max Memory Limit setting: 64 MB up to the |
| 805 |
* server-configured memory limit (null max when the server is unlimited). |
| 806 |
*/ |
| 807 |
public function get_memory_limit_allowed_range() { |
| 808 |
$server_limits = $this->get_server_limits(); |
| 809 |
$max = $server_limits['memory_limit_raw'] == -1 ? null : max(64, (int) $server_limits['memory_limit_raw']); |
| 810 |
|
| 811 |
return array( |
| 812 |
'min' => 64, |
| 813 |
'max' => $max |
| 814 |
); |
| 815 |
} |
| 816 |
|
| 817 |
public function apply_memory_limit() { |
| 818 |
if (!$this->can_change_memory_limit()) { |
| 819 |
return false; |
| 820 |
} |
| 821 |
|
| 822 |
$memory_limit_mb = $this->get_execution_setting('max_memory_limit'); |
| 823 |
|
| 824 |
$result = @ini_set('memory_limit', $memory_limit_mb . 'M'); |
| 825 |
|
| 826 |
return $result !== false; |
| 827 |
} |
| 828 |
|
| 829 |
public function parse_memory_limit_to_mb($memory_limit) { |
| 830 |
if ($memory_limit == -1 || $memory_limit == '-1') { |
| 831 |
return -1; |
| 832 |
} |
| 833 |
|
| 834 |
$memory_limit = trim($memory_limit); |
| 835 |
$last = strtolower(substr($memory_limit, -1)); |
| 836 |
$value = (int) $memory_limit; |
| 837 |
|
| 838 |
switch ($last) { |
| 839 |
case 'g': |
| 840 |
$value *= 1024; |
| 841 |
break; |
| 842 |
case 'm': |
| 843 |
break; |
| 844 |
case 'k': |
| 845 |
$value /= 1024; |
| 846 |
break; |
| 847 |
} |
| 848 |
|
| 849 |
return $value; |
| 850 |
} |
| 851 |
|
| 852 |
public function render_execution_settings_section() { |
| 853 |
$settings = $this->get_all_execution_settings(); |
| 854 |
$server_limits = $this->get_server_limits(); |
| 855 |
$memory_range = $this->get_memory_limit_allowed_range(); |
| 856 |
|
| 857 |
$warnings = array(); |
| 858 |
if ((int)$server_limits['max_execution_time_raw'] !== -1 && (int)$settings['max_execution_time'] > (int)$server_limits['max_execution_time_raw']) { |
| 859 |
$warnings['max_execution_time'] = true; |
| 860 |
} |
| 861 |
if ($server_limits['memory_limit_raw'] != -1 && $settings['max_memory_limit'] > $server_limits['memory_limit_raw']) { |
| 862 |
$warnings['max_memory_limit'] = true; |
| 863 |
} |
| 864 |
?> |
| 865 |
<div style="background: var(--dashboard-card-bg); padding: 20px; border-radius: 8px;"> |
| 866 |
<p style="color: var(--dashboard-text-secondary); margin: 0 0 20px 0;"> |
| 867 |
Configure resource limits and execution parameters for plugin operations. Adjust these settings based on your server capabilities. |
| 868 |
</p> |
| 869 |
|
| 870 |
<form id="metasync-execution-settings-form" method="post"> |
| 871 |
<?php wp_nonce_field('metasync_execution_settings_nonce', 'execution_settings_nonce'); ?> |
| 872 |
|
| 873 |
<!-- Execution & Memory Section --> |
| 874 |
<div style="background: var(--dashboard-card-bg-alt, rgba(255,255,255,0.05)); border: 1px solid var(--dashboard-border); border-radius: 8px; padding: 20px; margin-bottom: 20px;"> |
| 875 |
<h3 style="color: var(--dashboard-text-primary); margin: 0 0 16px 0; font-size: 16px; font-weight: 600;">Execution & Memory</h3> |
| 876 |
|
| 877 |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px;"> |
| 878 |
<div> |
| 879 |
<label style="display: block; color: var(--dashboard-text-primary); margin-bottom: 8px; font-weight: 500;"> |
| 880 |
Max Execution Time: |
| 881 |
</label> |
| 882 |
<div style="display: flex; align-items: center; gap: 10px;"> |
| 883 |
<input type="number" |
| 884 |
id="max_execution_time" |
| 885 |
name="max_execution_time" |
| 886 |
value="<?php echo esc_attr($settings['max_execution_time']); ?>" |
| 887 |
min="1" |
| 888 |
max="300" |
| 889 |
required |
| 890 |
style="width: 100px; padding: 8px; border: 1px solid var(--dashboard-border); border-radius: 6px; background: var(--dashboard-card-bg); color: var(--dashboard-text-primary);" /> |
| 891 |
<span style="color: var(--dashboard-text-secondary);">seconds</span> |
| 892 |
</div> |
| 893 |
<p style="color: var(--dashboard-text-secondary); font-size: 12px; margin: 4px 0 0 0;"> |
| 894 |
Server Limit: <?php echo esc_html($server_limits['max_execution_time']); ?> |
| 895 |
</p> |
| 896 |
<p id="max_execution_time_warning" style="display: none; color: #f59e0b; font-size: 12px; margin: 4px 0 0 0;"> |
| 897 |
<span class="dashicons dashicons-warning" style="margin-right:4px;font-size:14px;width:14px;height:14px;color:#f59e0b;"></span> |
| 898 |
<span>Configured value exceeds server limit</span> |
| 899 |
</p> |
| 900 |
<?php if (isset($warnings['max_execution_time'])): ?> |
| 901 |
<script> |
| 902 |
jQuery(document).ready(function($) { |
| 903 |
$('#max_execution_time_warning').show(); |
| 904 |
}); |
| 905 |
</script> |
| 906 |
<?php endif; ?> |
| 907 |
</div> |
| 908 |
|
| 909 |
<div> |
| 910 |
<label style="display: block; color: var(--dashboard-text-primary); margin-bottom: 8px; font-weight: 500;"> |
| 911 |
Max Memory Limit: |
| 912 |
</label> |
| 913 |
<div style="display: flex; align-items: center; gap: 10px;"> |
| 914 |
<input type="number" |
| 915 |
id="max_memory_limit" |
| 916 |
name="max_memory_limit" |
| 917 |
value="<?php echo esc_attr($settings['max_memory_limit']); ?>" |
| 918 |
min="<?php echo esc_attr($memory_range['min']); ?>" |
| 919 |
<?php if ($memory_range['max'] !== null): ?>max="<?php echo esc_attr($memory_range['max']); ?>"<?php endif; ?> |
| 920 |
<?php if (!$server_limits['can_change_memory']): ?> |
| 921 |
readonly |
| 922 |
disabled |
| 923 |
<?php endif; ?> |
| 924 |
required |
| 925 |
style="width: 100px; padding: 8px; border: 1px solid var(--dashboard-border); border-radius: 6px; background: <?php echo $server_limits['can_change_memory'] ? 'var(--dashboard-card-bg)' : 'rgba(128, 128, 128, 0.1)'; ?>; color: <?php echo $server_limits['can_change_memory'] ? 'var(--dashboard-text-primary)' : 'var(--dashboard-text-secondary)'; ?>; cursor: <?php echo $server_limits['can_change_memory'] ? 'text' : 'not-allowed'; ?>;" /> |
| 926 |
<span style="color: var(--dashboard-text-secondary);">MB</span> |
| 927 |
</div> |
| 928 |
<p style="color: var(--dashboard-text-secondary); font-size: 12px; margin: 4px 0 0 0;"> |
| 929 |
Server Limit: <?php echo esc_html($server_limits['memory_limit']); ?> · Allowed: <?php echo $memory_range['max'] !== null ? esc_html($memory_range['min'] . '–' . $memory_range['max'] . ' MB') : esc_html($memory_range['min'] . ' MB or higher'); ?> |
| 930 |
</p> |
| 931 |
<?php if (!$server_limits['can_change_memory']): ?> |
| 932 |
<p style="color: #f59e0b; font-size: 12px; margin: 4px 0 0 0; display: flex; align-items: center; gap: 4px;"> |
| 933 |
<span class="dashicons dashicons-lock" style="font-size:14px;width:14px;height:14px;color:#f59e0b;"></span> |
| 934 |
<span>Server does not allow changing memory limit. This setting is read-only.</span> |
| 935 |
</p> |
| 936 |
<?php else: ?> |
| 937 |
<p id="max_memory_limit_warning" style="display: none; color: #f59e0b; font-size: 12px; margin: 4px 0 0 0;"> |
| 938 |
<span class="dashicons dashicons-warning" style="margin-right:4px;font-size:14px;width:14px;height:14px;color:#f59e0b;"></span> |
| 939 |
<span>Configured value exceeds server limit</span> |
| 940 |
</p> |
| 941 |
<?php if (isset($warnings['max_memory_limit'])): ?> |
| 942 |
<script> |
| 943 |
jQuery(document).ready(function($) { |
| 944 |
$('#max_memory_limit_warning').show(); |
| 945 |
}); |
| 946 |
</script> |
| 947 |
<?php endif; ?> |
| 948 |
<?php endif; ?> |
| 949 |
</div> |
| 950 |
</div> |
| 951 |
</div> |
| 952 |
|
| 953 |
<!-- Batch Processing Section --> |
| 954 |
<div style="background: var(--dashboard-card-bg-alt, rgba(255,255,255,0.05)); border: 1px solid var(--dashboard-border); border-radius: 8px; padding: 20px; margin-bottom: 20px;"> |
| 955 |
<h3 style="color: var(--dashboard-text-primary); margin: 0 0 16px 0; font-size: 16px; font-weight: 600;">Batch Processing</h3> |
| 956 |
|
| 957 |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px;"> |
| 958 |
<div> |
| 959 |
<label style="display: block; color: var(--dashboard-text-primary); margin-bottom: 8px; font-weight: 500;"> |
| 960 |
Log Processing Batch Size: |
| 961 |
</label> |
| 962 |
<div style="display: flex; align-items: center; gap: 10px;"> |
| 963 |
<input type="number" |
| 964 |
id="log_batch_size" |
| 965 |
name="log_batch_size" |
| 966 |
value="<?php echo esc_attr($settings['log_batch_size']); ?>" |
| 967 |
min="100" |
| 968 |
max="5000" |
| 969 |
required |
| 970 |
style="width: 100px; padding: 8px; border: 1px solid var(--dashboard-border); border-radius: 6px; background: var(--dashboard-card-bg); color: var(--dashboard-text-primary);" /> |
| 971 |
<span style="color: var(--dashboard-text-secondary);">lines</span> |
| 972 |
</div> |
| 973 |
</div> |
| 974 |
|
| 975 |
<div> |
| 976 |
<label style="display: block; color: var(--dashboard-text-primary); margin-bottom: 8px; font-weight: 500;"> |
| 977 |
Action Scheduler Concurrent Batches: |
| 978 |
</label> |
| 979 |
<div style="display: flex; align-items: center; gap: 10px;"> |
| 980 |
<input type="number" |
| 981 |
id="action_scheduler_batches" |
| 982 |
name="action_scheduler_batches" |
| 983 |
value="<?php echo esc_attr($settings['action_scheduler_batches']); ?>" |
| 984 |
min="1" |
| 985 |
max="10" |
| 986 |
required |
| 987 |
style="width: 100px; padding: 8px; border: 1px solid var(--dashboard-border); border-radius: 6px; background: var(--dashboard-card-bg); color: var(--dashboard-text-primary);" /> |
| 988 |
</div> |
| 989 |
<p style="color: #f59e0b; font-size: 12px; margin: 4px 0 0 0; display: flex; align-items: center; gap: 4px;"> |
| 990 |
<span class="dashicons dashicons-warning" style="font-size:14px;width:14px;height:14px;color:#f59e0b;"></span> |
| 991 |
<span>Higher values increase server load</span> |
| 992 |
</p> |
| 993 |
</div> |
| 994 |
</div> |
| 995 |
</div> |
| 996 |
|
| 997 |
<!-- API Rate Limiting Section --> |
| 998 |
<div style="background: var(--dashboard-card-bg-alt, rgba(255,255,255,0.05)); border: 1px solid var(--dashboard-border); border-radius: 8px; padding: 20px; margin-bottom: 20px;"> |
| 999 |
<h3 style="color: var(--dashboard-text-primary); margin: 0 0 16px 0; font-size: 16px; font-weight: 600;">API Rate Limiting</h3> |
| 1000 |
|
| 1001 |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px;"> |
| 1002 |
<div> |
| 1003 |
<label style="display: block; color: var(--dashboard-text-primary); margin-bottom: 8px; font-weight: 500;"> |
| 1004 |
<?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> API Calls Per Minute: |
| 1005 |
</label> |
| 1006 |
<div style="display: flex; align-items: center; gap: 10px;"> |
| 1007 |
<input type="number" |
| 1008 |
id="otto_rate_limit" |
| 1009 |
name="otto_rate_limit" |
| 1010 |
value="<?php echo esc_attr($settings['otto_rate_limit']); ?>" |
| 1011 |
min="1" |
| 1012 |
max="60" |
| 1013 |
required |
| 1014 |
style="width: 100px; padding: 8px; border: 1px solid var(--dashboard-border); border-radius: 6px; background: var(--dashboard-card-bg); color: var(--dashboard-text-primary);" /> |
| 1015 |
</div> |
| 1016 |
</div> |
| 1017 |
|
| 1018 |
<div> |
| 1019 |
<label style="display: block; color: var(--dashboard-text-primary); margin-bottom: 8px; font-weight: 500;"> |
| 1020 |
Queue Auto-Cleanup: |
| 1021 |
</label> |
| 1022 |
<div style="display: flex; align-items: center; gap: 10px;"> |
| 1023 |
<input type="number" |
| 1024 |
id="queue_cleanup_days" |
| 1025 |
name="queue_cleanup_days" |
| 1026 |
value="<?php echo esc_attr($settings['queue_cleanup_days']); ?>" |
| 1027 |
min="7" |
| 1028 |
max="90" |
| 1029 |
required |
| 1030 |
style="width: 100px; padding: 8px; border: 1px solid var(--dashboard-border); border-radius: 6px; background: var(--dashboard-card-bg); color: var(--dashboard-text-primary);" /> |
| 1031 |
<span style="color: var(--dashboard-text-secondary);">days</span> |
| 1032 |
</div> |
| 1033 |
</div> |
| 1034 |
</div> |
| 1035 |
</div> |
| 1036 |
|
| 1037 |
<!-- Save Button --> |
| 1038 |
<div style="margin-top: 20px;"> |
| 1039 |
<button type="submit" |
| 1040 |
id="metasync-execution-settings-save-btn" |
| 1041 |
class="button button-primary" |
| 1042 |
style="padding: 10px 20px; font-size: 14px; font-weight: 500;"> |
| 1043 |
<span class="save-text">Save Settings</span> |
| 1044 |
<span class="save-spinner" style="display: none; margin-left: 8px;">⏳</span> |
| 1045 |
</button> |
| 1046 |
</div> |
| 1047 |
|
| 1048 |
<!-- Success/Error Messages --> |
| 1049 |
<div id="metasync-execution-settings-message" style="display: none; margin-top: 16px; padding: 12px; border-radius: 6px;"></div> |
| 1050 |
</form> |
| 1051 |
</div> |
| 1052 |
|
| 1053 |
<?php |
| 1054 |
// Real-time validation and AJAX save for this form live in |
| 1055 |
// admin/js/metasync-execution-settings.js (enqueued on this page). |
| 1056 |
// The previous inline duplicate was removed to avoid a double-bound |
| 1057 |
// submit handler that fired the save request twice (WP-430). |
| 1058 |
?> |
| 1059 |
<?php |
| 1060 |
} |
| 1061 |
|
| 1062 |
public function get_field_tooltips() { |
| 1063 |
$plugin_name = Metasync::get_effective_plugin_name(); |
| 1064 |
$otto_name = Metasync::get_whitelabel_otto_name(); |
| 1065 |
|
| 1066 |
return array( |
| 1067 |
'searchatlas_api_key' => sprintf('Connect your WordPress site to your %1$s dashboard to retrieve your API key and %2$s UUID. This does not create a WordPress login session.', $plugin_name, $otto_name), |
| 1068 |
'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), |
| 1069 |
'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), |
| 1070 |
'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), |
| 1071 |
'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), |
| 1072 |
'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), |
| 1073 |
'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), |
| 1074 |
'otto_bot_whitelist' => sprintf('Enter bot names or user-agent patterns (one per line) that should always be processed by %s, even when "Disable for Bots" is enabled. For example: Googlebot, Bingbot. This allows you to ensure specific search engines always see your optimized content.', $otto_name), |
| 1075 |
'otto_bot_blacklist' => sprintf('Enter bot names or user-agent patterns (one per line) that should always be blocked from %s processing, regardless of other settings. For example: BadBot, MaliciousCrawler. Use this to exclude problematic crawlers or unwanted traffic sources.', $otto_name), |
| 1076 |
'otto_bot_statistics_link' => 'View detailed bot detection statistics including total hits, API calls saved, breakdown by bot type, and unique bot entries with hit counts.', |
| 1077 |
'disable_common_robots_metabox' => 'Hide the Common Robots meta box from post and page edit screens. This removes the robots meta tag controls (index/noindex, follow/nofollow) from the editor interface.', |
| 1078 |
'disable_advance_robots_metabox' => 'Hide the Advanced Robots meta box from post and page edit screens. This removes advanced robots directives like max-snippet, max-image-preview, and max-video-preview settings.', |
| 1079 |
'disable_redirection_metabox' => 'Hide the Redirection meta box from post and page edit screens. This removes the URL redirect configuration options from the editor interface.', |
| 1080 |
'disable_canonical_metabox' => 'Hide the Canonical URL meta box from post and page edit screens. This removes the canonical URL override field from the editor interface.', |
| 1081 |
'disable_social_opengraph_metabox' => 'Hide the Social Media & Open Graph meta box from post and page edit screens. This removes Facebook, Twitter, and other social media meta tag controls from the editor.', |
| 1082 |
'disable_schema_markup_metabox' => 'Hide the Schema Markup meta box from post and page edit screens. This removes the structured data (Article, FAQ, Product, Recipe, etc.) configuration from the editor interface.', |
| 1083 |
'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).', |
| 1084 |
'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), |
| 1085 |
'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.', |
| 1086 |
'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), |
| 1087 |
'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), |
| 1088 |
'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), |
| 1089 |
'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), |
| 1090 |
'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), |
| 1091 |
'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), |
| 1092 |
'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.' |
| 1093 |
); |
| 1094 |
} |
| 1095 |
|
| 1096 |
public function get_field_section($field_id) { |
| 1097 |
$sections = $this->get_accordion_sections_config(); |
| 1098 |
|
| 1099 |
foreach ($sections as $section_key => $section_data) { |
| 1100 |
if (in_array($field_id, $section_data['fields'])) { |
| 1101 |
return $section_key; |
| 1102 |
} |
| 1103 |
} |
| 1104 |
|
| 1105 |
return null; |
| 1106 |
} |
| 1107 |
|
| 1108 |
public function render_accordion_sections($page) { |
| 1109 |
global $wp_settings_sections, $wp_settings_fields; |
| 1110 |
|
| 1111 |
if (!isset($wp_settings_fields[$page])) { |
| 1112 |
return; |
| 1113 |
} |
| 1114 |
|
| 1115 |
$sections_config = $this->get_accordion_sections_config(); |
| 1116 |
|
| 1117 |
echo '<div class="metasync-settings-accordion">'; |
| 1118 |
|
| 1119 |
uasort($sections_config, function($a, $b) { |
| 1120 |
return $a['priority'] - $b['priority']; |
| 1121 |
}); |
| 1122 |
|
| 1123 |
foreach ($sections_config as $section_key => $section_data) { |
| 1124 |
$section_id = 'metasync-section-' . $section_key; |
| 1125 |
$is_open = $section_data['default_open']; |
| 1126 |
$aria_expanded = $is_open ? 'true' : 'false'; |
| 1127 |
$content_state = $is_open ? 'open' : 'closed'; |
| 1128 |
|
| 1129 |
echo '<div class="metasync-accordion-section" data-section="' . esc_attr($section_key) . '">'; |
| 1130 |
|
| 1131 |
echo '<div class="metasync-accordion-header" role="button" tabindex="0" aria-expanded="' . $aria_expanded . '" aria-controls="' . $section_id . '">'; |
| 1132 |
echo '<div class="metasync-accordion-title">'; |
| 1133 |
echo '<span class="metasync-accordion-icon"><span class="dashicons dashicons-' . esc_attr($section_data['icon']) . '"></span></span>'; |
| 1134 |
echo '<div class="metasync-accordion-text">'; |
| 1135 |
echo '<h3>' . esc_html($section_data['title']) . '</h3>'; |
| 1136 |
echo '<p class="metasync-accordion-description">' . esc_html($section_data['description']) . '</p>'; |
| 1137 |
echo '</div>'; |
| 1138 |
echo '</div>'; |
| 1139 |
echo '<button type="button" class="metasync-accordion-toggle" aria-label="Toggle section">'; |
| 1140 |
echo '<span class="toggle-icon">▼</span>'; |
| 1141 |
echo '</button>'; |
| 1142 |
echo '</div>'; |
| 1143 |
|
| 1144 |
echo '<div class="metasync-accordion-content" id="' . $section_id . '" data-state="' . $content_state . '">'; |
| 1145 |
|
| 1146 |
if (isset($section_data['render_callback']) && is_callable($section_data['render_callback'])) { |
| 1147 |
call_user_func($section_data['render_callback']); |
| 1148 |
} elseif (isset($section_data['fields']) && is_array($section_data['fields'])) { |
| 1149 |
echo '<table class="form-table" role="presentation">'; |
| 1150 |
|
| 1151 |
$tooltips = $this->get_field_tooltips(); |
| 1152 |
|
| 1153 |
foreach ($section_data['fields'] as $field_id) { |
| 1154 |
if (isset($wp_settings_fields[$page]['metasync_settings'][$field_id])) { |
| 1155 |
$field = $wp_settings_fields[$page]['metasync_settings'][$field_id]; |
| 1156 |
|
| 1157 |
echo '<tr>'; |
| 1158 |
echo '<th scope="row">'; |
| 1159 |
if (!empty($field['title'])) { |
| 1160 |
echo '<div class="metasync-field-label-wrapper">'; |
| 1161 |
echo '<label for="' . esc_attr($field['id']) . '">' . $field['title'] . '</label>'; |
| 1162 |
|
| 1163 |
if (isset($tooltips[$field_id])) { |
| 1164 |
echo '<button type="button" class="metasync-tooltip-trigger" data-tooltip-id="' . esc_attr($field_id) . '" aria-label="More information">'; |
| 1165 |
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">'; |
| 1166 |
echo '<circle cx="12" cy="12" r="10"></circle>'; |
| 1167 |
echo '<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>'; |
| 1168 |
echo '<line x1="12" y1="17" x2="12.01" y2="17"></line>'; |
| 1169 |
echo '</svg>'; |
| 1170 |
echo '</button>'; |
| 1171 |
|
| 1172 |
echo '<div class="metasync-tooltip" id="tooltip-' . esc_attr($field_id) . '" role="tooltip">'; |
| 1173 |
echo '<div class="metasync-tooltip-arrow"></div>'; |
| 1174 |
echo '<div class="metasync-tooltip-content">' . esc_html($tooltips[$field_id]) . '</div>'; |
| 1175 |
echo '</div>'; |
| 1176 |
} |
| 1177 |
|
| 1178 |
echo '</div>'; |
| 1179 |
} |
| 1180 |
echo '</th>'; |
| 1181 |
echo '<td>'; |
| 1182 |
call_user_func($field['callback'], $field['args']); |
| 1183 |
echo '</td>'; |
| 1184 |
echo '</tr>'; |
| 1185 |
} |
| 1186 |
} |
| 1187 |
|
| 1188 |
echo '</table>'; |
| 1189 |
} |
| 1190 |
|
| 1191 |
echo '</div>'; |
| 1192 |
echo '</div>'; |
| 1193 |
} |
| 1194 |
|
| 1195 |
echo '</div>'; |
| 1196 |
} |
| 1197 |
|
| 1198 |
public function render_llms_txt_section() { |
| 1199 |
global $wp_settings_fields; |
| 1200 |
|
| 1201 |
$page = Metasync_Admin::$page_slug . '_general'; |
| 1202 |
$section = Metasync_Admin::SECTION_LLMS_TXT; |
| 1203 |
|
| 1204 |
if (empty($wp_settings_fields[$page][$section])) { |
| 1205 |
return; |
| 1206 |
} |
| 1207 |
|
| 1208 |
echo '<table class="form-table" role="presentation">'; |
| 1209 |
foreach ($wp_settings_fields[$page][$section] as $field) { |
| 1210 |
echo '<tr>'; |
| 1211 |
echo '<th scope="row">'; |
| 1212 |
if (!empty($field['title'])) { |
| 1213 |
echo '<label for="' . esc_attr($field['id']) . '">' . $field['title'] . '</label>'; |
| 1214 |
} |
| 1215 |
echo '</th>'; |
| 1216 |
echo '<td>'; |
| 1217 |
call_user_func($field['callback'], $field['args']); |
| 1218 |
echo '</td>'; |
| 1219 |
echo '</tr>'; |
| 1220 |
} |
| 1221 |
echo '</table>'; |
| 1222 |
?> |
| 1223 |
<script> |
| 1224 |
(function(){ |
| 1225 |
function toggleLlms(){ |
| 1226 |
var enabled = document.getElementById('llms_txt_enabled'); |
| 1227 |
var fullEnabled = document.getElementById('llms_full_enabled'); |
| 1228 |
var deps = document.querySelectorAll('.llms-txt-dependent'); |
| 1229 |
var fullDeps = document.querySelectorAll('.llms-full-dependent'); |
| 1230 |
var i; |
| 1231 |
for(i = 0; i < deps.length; i++){ |
| 1232 |
var row = deps[i].closest('tr'); |
| 1233 |
if(row) row.style.display = enabled && enabled.checked ? '' : 'none'; |
| 1234 |
} |
| 1235 |
for(i = 0; i < fullDeps.length; i++){ |
| 1236 |
var row = fullDeps[i].closest('tr'); |
| 1237 |
if(row) row.style.display = (enabled && enabled.checked && fullEnabled && fullEnabled.checked) ? '' : 'none'; |
| 1238 |
} |
| 1239 |
} |
| 1240 |
document.addEventListener('DOMContentLoaded', function(){ |
| 1241 |
var enabled = document.getElementById('llms_txt_enabled'); |
| 1242 |
var fullEnabled = document.getElementById('llms_full_enabled'); |
| 1243 |
if(enabled) enabled.addEventListener('change', toggleLlms); |
| 1244 |
if(fullEnabled) fullEnabled.addEventListener('change', toggleLlms); |
| 1245 |
toggleLlms(); |
| 1246 |
}); |
| 1247 |
})(); |
| 1248 |
</script> |
| 1249 |
<?php |
| 1250 |
} |
| 1251 |
|
| 1252 |
// ──────────────────────────────────────────────────────────────── |
| 1253 |
// Settings field callbacks |
| 1254 |
// ──────────────────────────────────────────────────────────────── |
| 1255 |
|
| 1256 |
public function metasync_settings_genkey_callback() |
| 1257 |
{ |
| 1258 |
$current_token = Metasync::get_option('general')['apikey'] ?? ''; |
| 1259 |
|
| 1260 |
if (!empty($current_token)) { |
| 1261 |
$display_value = $current_token; |
| 1262 |
$status_message = 'Plugin Auth Token is active and ready for authentication.'; |
| 1263 |
$refresh_help = 'Click refresh to generate a new token and update the heartbeat API.'; |
| 1264 |
} else { |
| 1265 |
$display_value = 'Auto-generated when connecting to ' . esc_html(Metasync::get_effective_plugin_name()); |
| 1266 |
$status_message = 'Plugin Auth Token will be automatically generated when you click "Connect to ' . esc_html(Metasync::get_effective_plugin_name()) . '".'; |
| 1267 |
$refresh_help = 'You can also manually generate a token by clicking refresh.'; |
| 1268 |
} |
| 1269 |
|
| 1270 |
printf( |
| 1271 |
'<input type="text" id="apikey" name="' . Metasync_Admin::option_key . '[general][apikey]" value="%s" size="40" readonly="readonly" /> ', |
| 1272 |
esc_attr($display_value) |
| 1273 |
); |
| 1274 |
|
| 1275 |
printf('<button type="button" id="refresh-plugin-auth-token" class="button button-secondary" style="margin-left: 10px; margin-top: 8px;"><span class="dashicons dashicons-controls-repeat"></span> Refresh Token</button>'); |
| 1276 |
printf('<p class="description">%s %s</p>', $status_message, $refresh_help); |
| 1277 |
} |
| 1278 |
|
| 1279 |
public function linkgraph_token_callback() |
| 1280 |
{ |
| 1281 |
printf( |
| 1282 |
'<input type="text" id="linkgraph_token" name="' . Metasync_Admin::option_key . '[general][linkgraph_token]" value="%s" size="25" readonly="readonly" />', |
| 1283 |
isset(Metasync::get_option('general')['linkgraph_token']) ? esc_attr(Metasync::get_option('general')['linkgraph_token']) : '' |
| 1284 |
); |
| 1285 |
|
| 1286 |
printf( |
| 1287 |
'<input type="text" id="linkgraph_customer_id" name="' . Metasync_Admin::option_key . '[general][linkgraph_customer_id]" value="%s" size="25" readonly="readonly" />', |
| 1288 |
isset(Metasync::get_option('general')['linkgraph_customer_id']) ? esc_attr(Metasync::get_option('general')['linkgraph_customer_id']) : '' |
| 1289 |
); |
| 1290 |
|
| 1291 |
?> |
| 1292 |
<button type="button" class="button button-primary" id="lgloginbtn">Fetch Token</button> |
| 1293 |
<input type="text" id="lgusername" class="input lguser hidden" placeholder="username" /> |
| 1294 |
<input type="text" id="lgpassword" class="input lguser hidden" placeholder="password" /> |
| 1295 |
<p id="lgerror" class="notice notice-error hidden" style="display: none;"></p> |
| 1296 |
<?php |
| 1297 |
} |
| 1298 |
|
| 1299 |
|
| 1300 |
public function time_elapsed_string($datetime, $full = false) |
| 1301 |
{ |
| 1302 |
if(empty($datetime)){ |
| 1303 |
return ""; |
| 1304 |
} |
| 1305 |
# Stored timestamps use current_time('mysql') which is the WP site's |
| 1306 |
# local timezone (no offset marker on the string). Constructing |
| 1307 |
# DateTime without a timezone would default to UTC and produce a |
| 1308 |
# bogus diff equal to the WP timezone offset (WP-350 QA: "4 hours ago" |
| 1309 |
# after a 4-minute sync on non-UTC sites). |
| 1310 |
$wp_tz = function_exists('wp_timezone') ? wp_timezone() : new DateTimeZone('UTC'); |
| 1311 |
$now = new DateTime('now', $wp_tz); |
| 1312 |
$ago = new DateTime($datetime, $wp_tz); |
| 1313 |
|
| 1314 |
$diff = $now->diff($ago); |
| 1315 |
|
| 1316 |
$string = [ |
| 1317 |
'y' => 'year', |
| 1318 |
'm' => 'month', |
| 1319 |
'w' => 'week', |
| 1320 |
'd' => 'day', |
| 1321 |
'h' => 'hour', |
| 1322 |
'i' => 'minute', |
| 1323 |
's' => 'second', |
| 1324 |
]; |
| 1325 |
|
| 1326 |
foreach ($string as $k => &$v) { |
| 1327 |
if (isset($diff->$k) && $diff->$k) { |
| 1328 |
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); |
| 1329 |
} else { |
| 1330 |
unset($string[$k]); |
| 1331 |
} |
| 1332 |
} |
| 1333 |
if (!$full) $string = array_slice($string, 0, 1); |
| 1334 |
return $string ? implode(', ', $string) . ' ago' : 'just now'; |
| 1335 |
} |
| 1336 |
|
| 1337 |
public function searchatlas_api_key_callback() |
| 1338 |
{ |
| 1339 |
$current_api_key = isset(Metasync::get_option('general')['searchatlas_api_key']) ? esc_attr(Metasync::get_option('general')['searchatlas_api_key']) : ''; |
| 1340 |
$otto_uuid = isset(Metasync::get_option('general')['otto_pixel_uuid']) ? Metasync::get_option('general')['otto_pixel_uuid'] : ''; |
| 1341 |
|
| 1342 |
$has_api_key = !empty($current_api_key); |
| 1343 |
$has_otto_uuid = !empty($otto_uuid); |
| 1344 |
|
| 1345 |
$is_fully_connected = $this->admin_instance->is_heartbeat_connected(); |
| 1346 |
|
| 1347 |
printf('<div class="metasync-sa-connect-container">'); |
| 1348 |
|
| 1349 |
printf('<div class="metasync-sa-connect-title">'); |
| 1350 |
printf('One-Click Authentication'); |
| 1351 |
printf('</div>'); |
| 1352 |
|
| 1353 |
printf('<div class="metasync-sa-connect-description">'); |
| 1354 |
if ($is_fully_connected) { |
| 1355 |
printf('Your %s account is fully synced with active heartbeat API. You can re-authenticate to refresh your connection or connect a different account.', esc_html(Metasync::get_effective_plugin_name())); |
| 1356 |
} elseif ($has_api_key && !$has_otto_uuid) { |
| 1357 |
printf('Your %s API key is configured, but %s UUID is missing. Please re-authenticate to complete the setup.', esc_html(Metasync::get_effective_plugin_name()), esc_html(Metasync::get_whitelabel_otto_name())); |
| 1358 |
} else { |
| 1359 |
printf('Connect your %s account with one click. This will automatically configure your API key and %s UUID below, enabling all plugin features.', esc_html(Metasync::get_effective_plugin_name()), esc_html(Metasync::get_whitelabel_otto_name())); |
| 1360 |
} |
| 1361 |
printf('</div>'); |
| 1362 |
|
| 1363 |
?> |
| 1364 |
<div class="metasync-mcp-consent" style="margin-top: 15px; padding: 12px 15px; background: #f0f9ff; border-left: 3px solid #0ea5e9; border-radius: 4px;"> |
| 1365 |
<p style="margin: 0; color: #334155; font-size: 13px; line-height: 1.6;"> |
| 1366 |
<strong>AI-Powered SEO Automation:</strong> By authenticating, you authorize <strong><?php echo esc_html(Metasync::get_effective_plugin_name()); ?> Brain</strong> (our AI assistant) to access your WordPress admin capabilities through the Model Context Protocol (MCP). This enables intelligent automation for SEO optimizations, content enhancements, and performance improvements. |
| 1367 |
</p> |
| 1368 |
</div> |
| 1369 |
<?php |
| 1370 |
|
| 1371 |
printf('<div class="metasync-sa-connect-buttons">'); |
| 1372 |
|
| 1373 |
printf('<button type="button" id="connect-searchatlas-btn" class="metasync-sa-connect-btn">'); |
| 1374 |
if ($is_fully_connected) { |
| 1375 |
printf('Re-authenticate with %s', esc_html(Metasync::get_effective_plugin_name())); |
| 1376 |
} elseif ($has_api_key && !$has_otto_uuid) { |
| 1377 |
printf('Complete Authentication Setup'); |
| 1378 |
} else { |
| 1379 |
printf('Connect to %s', esc_html(Metasync::get_effective_plugin_name())); |
| 1380 |
} |
| 1381 |
printf('</button>'); |
| 1382 |
|
| 1383 |
if ($has_api_key) { |
| 1384 |
printf('<button type="button" id="reset-searchatlas-auth" class="metasync-sa-reset-btn" style="margin-left: 10px;">'); |
| 1385 |
printf('Disconnect Account'); |
| 1386 |
printf('</button>'); |
| 1387 |
} |
| 1388 |
|
| 1389 |
printf('</div>'); |
| 1390 |
|
| 1391 |
printf('<div style="margin-top: 15px;">'); |
| 1392 |
printf('<details style="margin-top: 10px;">'); |
| 1393 |
printf('<summary style="cursor: pointer; color: #666; font-size: 13px;">Authentication Tips</summary>'); |
| 1394 |
printf('<div style="padding: 10px 0; color: #666; font-size: 13px; line-height: 1.5;">'); |
| 1395 |
printf('• Make sure you have a %s account before connecting<br/>', esc_html(Metasync::get_effective_plugin_name())); |
| 1396 |
printf('• The authentication window will open in a popup - please allow popups<br/>'); |
| 1397 |
printf('• The process typically takes 15-30 seconds to complete<br/>'); |
| 1398 |
printf('• Your API key will be automatically filled in the field below<br/>'); |
| 1399 |
printf('• If you encounter issues, try disabling ad blockers temporarily<br/>'); |
| 1400 |
printf('• Contact <a href="mailto:%s">%s</a> if you need assistance', Metasync::SUPPORT_EMAIL, Metasync::SUPPORT_EMAIL); |
| 1401 |
printf('</div>'); |
| 1402 |
printf('</details>'); |
| 1403 |
printf('</div>'); |
| 1404 |
|
| 1405 |
printf('</div>'); |
| 1406 |
|
| 1407 |
printf('<div style="margin-top: 20px;">'); |
| 1408 |
printf('<label for="searchatlas-api-key" style="font-weight: 600; display: block; margin-bottom: 8px;">'); |
| 1409 |
printf('%s API Key', esc_html(Metasync::get_effective_plugin_name())); |
| 1410 |
if ($is_fully_connected) { |
| 1411 |
printf('<span style="color: #46b450; margin-left: 10px; font-weight: normal;">✓ Synced</span>'); |
| 1412 |
} elseif ($has_api_key && !$has_otto_uuid) { |
| 1413 |
printf('<span style="color: #ff8c00; margin-left: 10px; font-weight: normal;">Partial Connection (Missing %s UUID)</span>', esc_html(Metasync::get_whitelabel_otto_name())); |
| 1414 |
} |
| 1415 |
printf('</label>'); |
| 1416 |
|
| 1417 |
printf( |
| 1418 |
'<input type="text" id="searchatlas-api-key" name="' . Metasync_Admin::option_key . '[general][searchatlas_api_key]" value="%s" size="40" class="regular-text" placeholder="Your API key will appear here after authentication" />', |
| 1419 |
$current_api_key |
| 1420 |
); |
| 1421 |
|
| 1422 |
printf('<p class="description" style="margin-top: 8px;">'); |
| 1423 |
if ($is_fully_connected) { |
| 1424 |
printf('Your %s API key for secure communication with the platform. Use the authentication button above to refresh or change accounts.', esc_html(Metasync::get_effective_plugin_name())); |
| 1425 |
} elseif ($has_api_key && !$has_otto_uuid) { |
| 1426 |
printf('Your API key is configured but %s UUID is missing. Re-authenticate above to complete the setup and enable dashboard access.', esc_html(Metasync::get_whitelabel_otto_name())); |
| 1427 |
} else { |
| 1428 |
printf('This field will be automatically populated when you authenticate using the button above. You can also manually enter your API key if you have one.'); |
| 1429 |
} |
| 1430 |
printf('</p>'); |
| 1431 |
|
| 1432 |
?> |
| 1433 |
<p class="description" style="margin-top: 10px; padding: 8px 12px; background: #fff9e6; border-left: 3px solid #f0b849; border-radius: 4px; font-size: 12px;"> |
| 1434 |
<strong>Manual Authentication:</strong> If you manually enter your <?php echo esc_html(Metasync::get_effective_plugin_name()); ?> API Key and <?php echo esc_html(Metasync::get_whitelabel_otto_name()); ?> UUID, you also consent to the same AI-powered automation permissions described above. |
| 1435 |
</p> |
| 1436 |
<?php |
| 1437 |
|
| 1438 |
printf('</div>'); |
| 1439 |
|
| 1440 |
if( isset(Metasync::get_option('general')['searchatlas_api_key'])&&Metasync::get_option('general')['searchatlas_api_key']!=''){ |
| 1441 |
$timestamp = @Metasync::get_option('general')['send_auth_token_timestamp']; |
| 1442 |
printf( |
| 1443 |
'<p id="sendAuthTokenTimestamp" class="descriptionValue">%s (%s)</p>', |
| 1444 |
esc_attr($timestamp), |
| 1445 |
$this->time_elapsed_string($timestamp) |
| 1446 |
); |
| 1447 |
|
| 1448 |
|
| 1449 |
} |
| 1450 |
} |
| 1451 |
|
| 1452 |
public function bing_site_verification_callback() |
| 1453 |
{ |
| 1454 |
printf( |
| 1455 |
'<input type="text" id="bing_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][bing_site_verification]" value="%s" size="50" />', |
| 1456 |
isset(Metasync::get_option('searchengines')['bing_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['bing_site_verification']) : '' |
| 1457 |
); |
| 1458 |
|
| 1459 |
printf(' <br> <span class="description"> Enter Bing Webmaster Tools verification code: </span> '); |
| 1460 |
printf(' <a href="https://www.bing.com/webmasters/about" target="_blank">Get from here</a> <br> '); |
| 1461 |
} |
| 1462 |
|
| 1463 |
public function yandex_site_verification_callback() |
| 1464 |
{ |
| 1465 |
printf( |
| 1466 |
'<input type="text" id="yandex_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][yandex_site_verification]" value="%s" size="50" />', |
| 1467 |
isset(Metasync::get_option('searchengines')['yandex_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['yandex_site_verification']) : '' |
| 1468 |
); |
| 1469 |
|
| 1470 |
printf(' <br> <span class="description"> Enter Yandex verification code: </span>'); |
| 1471 |
printf(' <a href="https://passport.yandex.com/auth" target="_blank">Get from here</a> <br> '); |
| 1472 |
} |
| 1473 |
|
| 1474 |
public function google_site_verification_callback() |
| 1475 |
{ |
| 1476 |
printf( |
| 1477 |
'<input type="text" id="google_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][google_site_verification]" value="%s" size="50" />', |
| 1478 |
isset(Metasync::get_option('searchengines')['google_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['google_site_verification']) : '' |
| 1479 |
); |
| 1480 |
|
| 1481 |
printf(' <br> <span class="description"> Enter Google Search Console verification code: </span>'); |
| 1482 |
printf(' <a href="https://www.google.com/webmasters/verification" target="_blank">Get from here</a> <br> '); |
| 1483 |
} |
| 1484 |
|
| 1485 |
public function pinterest_site_verification_callback() |
| 1486 |
{ |
| 1487 |
printf( |
| 1488 |
'<input type="text" id="pinterest_site_verification" name="' . Metasync_Admin::option_key . '[searchengines][pinterest_site_verification]" value="%s" size="50" />', |
| 1489 |
isset(Metasync::get_option('searchengines')['pinterest_site_verification']) ? esc_attr(Metasync::get_option('searchengines')['pinterest_site_verification']) : '' |
| 1490 |
); |
| 1491 |
|
| 1492 |
printf(' <br> <span class="description"> Enter Pinterest verification code: </span>'); |
| 1493 |
printf(' <a href="https://in.pinterest.com/" target="_blank">Get from here</a> <br> '); |
| 1494 |
} |
| 1495 |
|
| 1496 |
public function local_seo_person_organization_callback() |
| 1497 |
{ |
| 1498 |
$person_organization = Metasync::get_option('localseo')['local_seo_person_organization'] ?? ''; |
| 1499 |
?> |
| 1500 |
<div class="metasync-type-select-wrap"> |
| 1501 |
<select id="local_seo_person_organization" name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][local_seo_person_organization]') ?>"> |
| 1502 |
<?php |
| 1503 |
printf('<option value="Person" %s >Person</option>', selected('Person', esc_attr($person_organization))); |
| 1504 |
printf('<option value="Organization" %s >Organization</option>', selected('Organization', esc_attr($person_organization))); |
| 1505 |
?> |
| 1506 |
</select> |
| 1507 |
</div> |
| 1508 |
<?php |
| 1509 |
printf(' <br> <span class="description"> Choose whether the site represents a person or an organization. </span>'); |
| 1510 |
} |
| 1511 |
|
| 1512 |
public function local_seo_name_callback() |
| 1513 |
{ |
| 1514 |
printf( |
| 1515 |
'<input type="text" id="local_seo_name" name="' . Metasync_Admin::option_key . '[localseo][local_seo_name]" value="%s" size="50" />', |
| 1516 |
isset(Metasync::get_option('localseo')['local_seo_name']) ? esc_attr(Metasync::get_option('localseo')['local_seo_name']) : get_bloginfo() |
| 1517 |
); |
| 1518 |
|
| 1519 |
printf(' <br> <span class="description"> Your name or company name </span>'); |
| 1520 |
} |
| 1521 |
|
| 1522 |
public function local_seo_logo_callback() |
| 1523 |
{ |
| 1524 |
$local_seo_logo = Metasync::get_option('localseo')['local_seo_logo'] ?? ''; |
| 1525 |
|
| 1526 |
printf( |
| 1527 |
'<input type="hidden" id="local_seo_logo" name="' . Metasync_Admin::option_key . '[localseo][local_seo_logo]" value="%s" size="50" />', |
| 1528 |
isset(Metasync::get_option('localseo')['local_seo_logo']) ? esc_attr(Metasync::get_option('localseo')['local_seo_logo']) : '' |
| 1529 |
); |
| 1530 |
|
| 1531 |
printf(' <br> <input class="button-secondary" type="button" id="logo_upload_button" value="Add or Upload File">'); |
| 1532 |
|
| 1533 |
printf(' <br><br> <span class="description bold"> Min Size: 160Χ90px, Max Size: 1920X1080px. </span> <br> <span class="description"> A squared image is preferred by the search engines. </span> <br><br> '); |
| 1534 |
|
| 1535 |
printf('<img src="%s" id="local_seo_business_logo" width="300">', wp_get_attachment_image_src($local_seo_logo, 'medium')[0] ?? ''); |
| 1536 |
|
| 1537 |
$button_type = 'hidden'; |
| 1538 |
if ($local_seo_logo) { |
| 1539 |
$button_type = 'button'; |
| 1540 |
} |
| 1541 |
printf('<input type="%s" class="button-secondary" id="local_seo_logo_close_btn" value="X">', $button_type); |
| 1542 |
} |
| 1543 |
|
| 1544 |
public function local_seo_url_callback() |
| 1545 |
{ |
| 1546 |
printf( |
| 1547 |
'<input type="text" id="local_seo_url" name="' . Metasync_Admin::option_key . '[localseo][local_seo_url]" value="%s" size="50" />', |
| 1548 |
isset(Metasync::get_option('localseo')['local_seo_url']) ? esc_attr(Metasync::get_option('localseo')['local_seo_url']) : home_url() |
| 1549 |
); |
| 1550 |
|
| 1551 |
printf(' <br> <span class="description"> URL of the item. </span>'); |
| 1552 |
} |
| 1553 |
|
| 1554 |
public function local_seo_email_callback() |
| 1555 |
{ |
| 1556 |
printf( |
| 1557 |
'<input type="text" id="local_seo_email" name="' . Metasync_Admin::option_key . '[localseo][local_seo_email]" value="%s" size="50" />', |
| 1558 |
isset(Metasync::get_option('localseo')['local_seo_email']) ? esc_attr(Metasync::get_option('localseo')['local_seo_email']) : '' |
| 1559 |
); |
| 1560 |
|
| 1561 |
printf(' <br> <span class="description"> Search engines display your email address. </span>'); |
| 1562 |
} |
| 1563 |
|
| 1564 |
public function local_seo_phone_callback() |
| 1565 |
{ |
| 1566 |
printf( |
| 1567 |
'<input type="text" id="local_seo_phone" name="' . Metasync_Admin::option_key . '[localseo][local_seo_phone]" value="%s" size="50" />', |
| 1568 |
isset(Metasync::get_option('localseo')['local_seo_phone']) ? esc_attr(Metasync::get_option('localseo')['local_seo_phone']) : '' |
| 1569 |
); |
| 1570 |
|
| 1571 |
printf(' <br> <span class="description"> Search engines may prominently display your contact phone number for mobile users. </span>'); |
| 1572 |
} |
| 1573 |
|
| 1574 |
public function local_seo_address_callback() |
| 1575 |
{ |
| 1576 |
printf( |
| 1577 |
'<input type="text" id="local_seo_address_street" name="' . Metasync_Admin::option_key . '[localseo][address][street]" value="%s" size="50" placeholder="Street Address"/> <br>', |
| 1578 |
isset(Metasync::get_option('localseo')['address']['street']) ? esc_attr(Metasync::get_option('localseo')['address']['street']) : '' |
| 1579 |
); |
| 1580 |
|
| 1581 |
printf( |
| 1582 |
'<input type="text" id="local_seo_address_locality" name="' . Metasync_Admin::option_key . '[localseo][address][locality]" value="%s" size="50" placeholder="Locality"/> <br>', |
| 1583 |
isset(Metasync::get_option('localseo')['address']['locality']) ? esc_attr(Metasync::get_option('localseo')['address']['locality']) : '' |
| 1584 |
); |
| 1585 |
|
| 1586 |
printf( |
| 1587 |
'<input type="text" id="local_seo_address_region" name="' . Metasync_Admin::option_key . '[localseo][address][region]" value="%s" size="50" placeholder="Region"/> <br>', |
| 1588 |
isset(Metasync::get_option('localseo')['address']['region']) ? esc_attr(Metasync::get_option('localseo')['address']['region']) : '' |
| 1589 |
); |
| 1590 |
|
| 1591 |
printf( |
| 1592 |
'<input type="text" id="local_seo_address_postalcode" name="' . Metasync_Admin::option_key . '[localseo][address][postalcode]" value="%s" size="50" placeholder="Postal Code"/> <br>', |
| 1593 |
isset(Metasync::get_option('localseo')['address']['postalcode']) ? esc_attr(Metasync::get_option('localseo')['address']['postalcode']) : '' |
| 1594 |
); |
| 1595 |
|
| 1596 |
printf( |
| 1597 |
'<input type="text" id="local_seo_address_country" name="' . Metasync_Admin::option_key . '[localseo][address][country]" value="%s" size="50" placeholder="Country"/> <br>', |
| 1598 |
isset(Metasync::get_option('localseo')['address']['country']) ? esc_attr(Metasync::get_option('localseo')['address']['country']) : '' |
| 1599 |
); |
| 1600 |
} |
| 1601 |
|
| 1602 |
public function local_seo_business_type_callback() |
| 1603 |
{ |
| 1604 |
$types = self::get_business_types(); |
| 1605 |
sort($types); |
| 1606 |
|
| 1607 |
$business_type = Metasync::get_option('localseo')['local_seo_business_type'] ?? ''; |
| 1608 |
|
| 1609 |
?> |
| 1610 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][local_seo_business_type]') ?>"> |
| 1611 |
<option value='0'>Select Business Type</option> |
| 1612 |
<?php |
| 1613 |
foreach ($types as $type) { |
| 1614 |
printf('<option value="%s" %s >%s</option>', $type, selected($type, esc_attr($business_type)), $type); |
| 1615 |
} |
| 1616 |
?> |
| 1617 |
</select> |
| 1618 |
<?php |
| 1619 |
} |
| 1620 |
|
| 1621 |
public function local_seo_opening_hours_callback() |
| 1622 |
{ |
| 1623 |
$days_name = ['Monday', 'Tuseday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; |
| 1624 |
$days = isset(Metasync::get_option('localseo')['days']) ? Metasync::get_option('localseo')['days'] : ''; |
| 1625 |
$times = isset(Metasync::get_option('localseo')['times']) ? Metasync::get_option('localseo')['times'] : ''; |
| 1626 |
|
| 1627 |
?> |
| 1628 |
<ul id="daysTime"> |
| 1629 |
<?php |
| 1630 |
$opening_days = []; |
| 1631 |
if ($days && $times) { |
| 1632 |
$opening_days = array_combine($days, $times); |
| 1633 |
} |
| 1634 |
foreach ($opening_days as $day_name => $day_time) { |
| 1635 |
?> |
| 1636 |
<li> |
| 1637 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][days][]') ?>"> |
| 1638 |
<?php |
| 1639 |
foreach ($days_name as $name) { |
| 1640 |
printf('<option value="%s" %s >%s</option>', $name, selected(esc_attr($name), esc_attr($day_name)), esc_attr($name)); |
| 1641 |
} |
| 1642 |
?> |
| 1643 |
</select> |
| 1644 |
<input type="text" name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][times][]') ?>" value="<?php echo esc_attr($day_time) ?>"> |
| 1645 |
<button id="timeDelete">Delete</button> |
| 1646 |
</li> |
| 1647 |
<?php } ?> |
| 1648 |
<?php if (empty($opening_days)) { ?> |
| 1649 |
<li> |
| 1650 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][days][]') ?>"> |
| 1651 |
<?php |
| 1652 |
foreach ($days_name as $name) { |
| 1653 |
printf('<option value="%s" >%s</option>', esc_attr($name), esc_attr($name)); |
| 1654 |
} |
| 1655 |
?> |
| 1656 |
</select> |
| 1657 |
<input type="text" name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][times][]') ?>" value=""> |
| 1658 |
<button id="timeDelete">Delete</button> |
| 1659 |
</li> |
| 1660 |
<?php } ?> |
| 1661 |
</ul> |
| 1662 |
<?php |
| 1663 |
|
| 1664 |
printf(' <input type="hidden" id="days_time_count" value="%s"/>', count($opening_days)); |
| 1665 |
printf(' <input class="button-secondary" type="button" id="addNewTime" value="Add Time">'); |
| 1666 |
printf(' <br> <span class="description"> Select opening hours. You can add multiple sets if you have different opening or closing hours on some days or if you have a mid-day break. Times are specified using 24:00 time. </span>'); |
| 1667 |
} |
| 1668 |
|
| 1669 |
public function local_seo_phone_numbers_callback() |
| 1670 |
{ |
| 1671 |
$number_types = ['Customer Service', 'Technical Support', 'Billing Support', 'Bill Payment', 'Sales', 'Reservations', 'Credit Card Support', 'Emergency', 'Baggage Tracking', 'Roadside Assistance', 'Package Tracking']; |
| 1672 |
$types = isset(Metasync::get_option('localseo')['phonetype']) ? Metasync::get_option('localseo')['phonetype'] : ''; |
| 1673 |
$numbers = isset(Metasync::get_option('localseo')['phonenumber']) ? Metasync::get_option('localseo')['phonenumber'] : ''; |
| 1674 |
|
| 1675 |
?> |
| 1676 |
|
| 1677 |
<ul id="phone-numbers"> |
| 1678 |
<?php |
| 1679 |
$phone_numbers = []; |
| 1680 |
if ($types && $numbers) { |
| 1681 |
$phone_numbers = array_combine($types, $numbers); |
| 1682 |
} |
| 1683 |
foreach ($phone_numbers as $phone_type => $phone_number) { |
| 1684 |
?> |
| 1685 |
<li> |
| 1686 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][phonetype][]') ?>"> |
| 1687 |
<?php |
| 1688 |
foreach ($number_types as $type) { |
| 1689 |
printf('<option value="%s" %s >%s</option>', esc_attr($type), selected(esc_attr($type), esc_attr($phone_type)), esc_attr($type)); |
| 1690 |
} |
| 1691 |
?> |
| 1692 |
</select> |
| 1693 |
<input type="text" name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][phonenumber][]') ?>" value="<?php echo esc_attr($phone_number) ?>"> |
| 1694 |
<button id="number-delete">Delete</button> |
| 1695 |
</li> |
| 1696 |
<?php } ?> |
| 1697 |
<?php if (empty($phone_numbers)) { ?> |
| 1698 |
<li> |
| 1699 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][phonetype][]') ?>"> |
| 1700 |
<?php |
| 1701 |
foreach ($number_types as $type) { |
| 1702 |
printf('<option value="%s" >%s</option>', esc_attr($type), esc_attr($type)); |
| 1703 |
} |
| 1704 |
?> |
| 1705 |
</select> |
| 1706 |
<input type="text" name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][phonenumber][]') ?>" value=""> |
| 1707 |
<button id="number-delete">Delete</button> |
| 1708 |
</li> |
| 1709 |
<?php } ?> |
| 1710 |
</ul> |
| 1711 |
<?php |
| 1712 |
|
| 1713 |
printf(' <input type="hidden" id="phone_number_count" value="%s"/>', count($phone_numbers)); |
| 1714 |
printf(' <input class="button-secondary" type="button" id="addNewNumber" value="Add Number">'); |
| 1715 |
printf(' <br> <span class="description"> Search engines may prominently display your contact phone number for mobile users. </span>'); |
| 1716 |
} |
| 1717 |
|
| 1718 |
public function local_seo_price_range_callback() |
| 1719 |
{ |
| 1720 |
printf( |
| 1721 |
'<input type="text" id="local_seo_price_range" name="' . Metasync_Admin::option_key . '[localseo][local_seo_price_range]" value="%s" size="50" />', |
| 1722 |
isset(Metasync::get_option('localseo')['local_seo_price_range']) ? esc_attr(Metasync::get_option('localseo')['local_seo_price_range']) : '' |
| 1723 |
); |
| 1724 |
printf(' <br> <span class="description"> The price range of the business, for example $$$. </span>'); |
| 1725 |
} |
| 1726 |
|
| 1727 |
public function local_seo_about_page_callback() |
| 1728 |
{ |
| 1729 |
?> |
| 1730 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][local_seo_about_page]') ?>"> |
| 1731 |
<option value='0'>Select About Page</option> |
| 1732 |
<?php |
| 1733 |
$about_page = Metasync::get_option('localseo')['local_seo_about_page'] ?? ''; |
| 1734 |
$pages = get_pages(); |
| 1735 |
foreach ($pages as $page) { |
| 1736 |
printf('<option value="%s" %s >%s</option>', $page->ID, selected($page->ID, esc_attr($about_page)), $page->post_title); |
| 1737 |
} |
| 1738 |
?> |
| 1739 |
</select> |
| 1740 |
<?php |
| 1741 |
printf(' <br> <span class="description"> Search engines tag your about us page. </span>'); |
| 1742 |
} |
| 1743 |
|
| 1744 |
public function local_seo_contact_page_callback() |
| 1745 |
{ |
| 1746 |
?> |
| 1747 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[localseo][local_seo_contact_page]') ?>"> |
| 1748 |
<option value='0'>Select Contact Page</option> |
| 1749 |
<?php |
| 1750 |
$contact_page = Metasync::get_option('localseo')['local_seo_contact_page'] ?? ''; |
| 1751 |
$pages = get_pages(); |
| 1752 |
foreach ($pages as $page) { |
| 1753 |
printf('<option value="%s" %s >%s</option>', $page->ID, selected($page->ID, esc_attr($contact_page)), $page->post_title); |
| 1754 |
} |
| 1755 |
?> |
| 1756 |
</select> |
| 1757 |
<?php |
| 1758 |
printf(' <br> <span class="description"> Search engines tag your contact page. </span>'); |
| 1759 |
} |
| 1760 |
|
| 1761 |
public function local_seo_map_key_callback() |
| 1762 |
{ |
| 1763 |
printf( |
| 1764 |
'<input type="text" id="local_seo_map_key" name="' . Metasync_Admin::option_key . '[localseo][local_seo_map_key]" value="%s" size="50" />', |
| 1765 |
isset(Metasync::get_option('localseo')['local_seo_map_key']) ? esc_attr(Metasync::get_option('localseo')['local_seo_map_key']) : '' |
| 1766 |
); |
| 1767 |
|
| 1768 |
printf(' <br> <span class="description"> An API Key is required to display embedded Google Maps on your site. </span>'); |
| 1769 |
} |
| 1770 |
|
| 1771 |
public function local_seo_geo_coordinates_callback() |
| 1772 |
{ |
| 1773 |
printf( |
| 1774 |
'<input type="text" id="local_seo_geo_coordinates" name="' . Metasync_Admin::option_key . '[localseo][local_seo_geo_coordinates]" value="%s" size="50" />', |
| 1775 |
isset(Metasync::get_option('localseo')['local_seo_geo_coordinates']) ? esc_attr(Metasync::get_option('localseo')['local_seo_geo_coordinates']) : '' |
| 1776 |
); |
| 1777 |
|
| 1778 |
printf(' <br> <span class="description"> Latitude and longitude values separated by comma. </span>'); |
| 1779 |
} |
| 1780 |
|
| 1781 |
public function header_snippets_callback() |
| 1782 |
{ |
| 1783 |
printf( |
| 1784 |
'<textarea class="wide-text" id="header_snippets" rows="8" name="' . Metasync_Admin::option_key . '[codesnippets][header_snippet]" >%s</textarea>', |
| 1785 |
isset(Metasync::get_option('codesnippets')['header_snippet']) ? esc_attr(Metasync::get_option('codesnippets')['header_snippet']) : '' |
| 1786 |
); |
| 1787 |
} |
| 1788 |
|
| 1789 |
public function footer_snippets_callback() |
| 1790 |
{ |
| 1791 |
printf( |
| 1792 |
'<textarea class="wide-text" id="footer_snippets" rows="8" name="' . Metasync_Admin::option_key . '[codesnippets][footer_snippet]" >%s</textarea>', |
| 1793 |
isset(Metasync::get_option('codesnippets')['footer_snippet']) ? esc_attr(Metasync::get_option('codesnippets')['footer_snippet']) : '' |
| 1794 |
); |
| 1795 |
} |
| 1796 |
|
| 1797 |
public function no_index_posts_callback() |
| 1798 |
{ |
| 1799 |
printf( |
| 1800 |
'<input type="checkbox" id="no_index_posts" name="' . Metasync_Admin::option_key . '[optimal_settings][no_index_posts]" value="true" %s />', |
| 1801 |
isset(Metasync::get_option('optimal_settings')['no_index_posts']) && Metasync::get_option('optimal_settings')['no_index_posts'] == 'true' ? 'checked' : '' |
| 1802 |
); |
| 1803 |
|
| 1804 |
printf(' <br> <span class="description"> Setting empty archives to <code>noindex</code> is useful for avoiding indexation of thin content pages and dilution of page rank. As soon as a post is added, the page is updated to index. </span>'); |
| 1805 |
} |
| 1806 |
|
| 1807 |
public function no_follow_links_callback() |
| 1808 |
{ |
| 1809 |
printf( |
| 1810 |
'<input type="checkbox" id="no_follow_links" name="' . Metasync_Admin::option_key . '[optimal_settings][no_follow_links]" value="true" %s />', |
| 1811 |
isset(Metasync::get_option('optimal_settings')['no_follow_links']) && Metasync::get_option('optimal_settings')['no_follow_links'] == 'true' ? 'checked' : '' |
| 1812 |
); |
| 1813 |
|
| 1814 |
printf(' <br> <span class="description"> Automatically add <code>rel="nofollow"</code> attribute to external links appearing in your posts, pages, and other post types. The attribute is dynamically applied when the url is displayed</span>'); |
| 1815 |
} |
| 1816 |
|
| 1817 |
public function open_external_links_callback() |
| 1818 |
{ |
| 1819 |
printf( |
| 1820 |
'<input type="checkbox" id="open_external_links" name="' . Metasync_Admin::option_key . '[optimal_settings][open_external_links]" value="true" %s />', |
| 1821 |
isset(Metasync::get_option('optimal_settings')['open_external_links']) && Metasync::get_option('optimal_settings')['open_external_links'] == 'true' ? 'checked' : '' |
| 1822 |
); |
| 1823 |
|
| 1824 |
printf(' <br> <span class="description"> Automatically add <code>target="_blank"</code> attribute to external links appearing in your posts, pages, and other post types. The attribute is applied when the url is displayed.</span>'); |
| 1825 |
} |
| 1826 |
|
| 1827 |
public function add_alt_image_tags_callback() |
| 1828 |
{ |
| 1829 |
printf( |
| 1830 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[optimal_settings][add_alt_image_tags]" value="true" %s />', |
| 1831 |
isset(Metasync::get_option('optimal_settings')['add_alt_image_tags']) && Metasync::get_option('optimal_settings')['add_alt_image_tags'] == 'true' ? 'checked' : '' |
| 1832 |
); |
| 1833 |
|
| 1834 |
printf(' <br> <span class="description"> Automatically add <code>alt</code> attribute to Image Tags appearing in your posts, pages, and other post types. The attribute is applied when the content is displayed.</span>'); |
| 1835 |
} |
| 1836 |
|
| 1837 |
public function add_title_image_tags_callback() |
| 1838 |
{ |
| 1839 |
printf( |
| 1840 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[optimal_settings][add_title_image_tags]" value="true" %s />', |
| 1841 |
isset(Metasync::get_option('optimal_settings')['add_title_image_tags']) && Metasync::get_option('optimal_settings')['add_title_image_tags'] == 'true' ? 'checked' : '' |
| 1842 |
); |
| 1843 |
|
| 1844 |
printf(' <br> <span class="description"> Automatically add <code>title</code> attribute to Image Tags appearing in your posts, pages, and other post types. The attribute is applied when the content is displayed.</span>'); |
| 1845 |
} |
| 1846 |
|
| 1847 |
public function site_type_callback() |
| 1848 |
{ |
| 1849 |
|
| 1850 |
$site_type = Metasync::get_option('optimal_settings')['site_info']['type'] ?? ''; |
| 1851 |
|
| 1852 |
$types = [ |
| 1853 |
['name' => 'Personal Blog', 'value' => 'blog'], |
| 1854 |
['name' => 'Community Blog/News Site', 'value' => 'news'], |
| 1855 |
['name' => 'Personal Portfolio', 'value' => 'portfolio'], |
| 1856 |
['name' => 'Small Business Site', 'value' => 'business'], |
| 1857 |
['name' => 'Webshop', 'value' => 'webshop'], |
| 1858 |
['name' => 'Other Personal Website', 'value' => 'otherpersonal'], |
| 1859 |
['name' => 'Other Business Website', 'value' => 'otherbusiness'], |
| 1860 |
]; |
| 1861 |
|
| 1862 |
?> |
| 1863 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[optimal_settings][site_info][type]') ?>" id="site_info_type"> |
| 1864 |
<?php |
| 1865 |
foreach ($types as $type) { |
| 1866 |
printf('<option value="%s" %s >%s</option>', esc_attr($type['value']), selected(esc_attr($type['value']), esc_attr($site_type)), ($type['name'])); |
| 1867 |
} |
| 1868 |
?> |
| 1869 |
</select> |
| 1870 |
<?php |
| 1871 |
|
| 1872 |
} |
| 1873 |
|
| 1874 |
public function site_business_type_callback() |
| 1875 |
{ |
| 1876 |
|
| 1877 |
$business_type = Metasync::get_option('optimal_settings')['site_info']['business_type'] ?? ''; |
| 1878 |
|
| 1879 |
$types = self::get_business_types(); |
| 1880 |
sort($types); |
| 1881 |
|
| 1882 |
?> |
| 1883 |
<select name="<?php echo esc_attr(Metasync_Admin::option_key . '[optimal_settings][site_info][business_type]') ?>"> |
| 1884 |
<option value='0'>Select Business Type</option> |
| 1885 |
<?php |
| 1886 |
foreach ($types as $type) { |
| 1887 |
printf('<option value="%s" %s >%s</option>', esc_attr($type), selected(esc_attr($type), esc_attr($business_type)), esc_attr($type)); |
| 1888 |
} |
| 1889 |
?> |
| 1890 |
</select> |
| 1891 |
<?php |
| 1892 |
} |
| 1893 |
|
| 1894 |
public function site_company_name_callback() |
| 1895 |
{ |
| 1896 |
|
| 1897 |
$company_name = Metasync::get_option('optimal_settings')['site_info']['company_name'] ?? get_bloginfo('name'); |
| 1898 |
|
| 1899 |
printf( |
| 1900 |
'<input type="text" name="' . Metasync_Admin::option_key . '[optimal_settings][site_info][company_name]" value="%s" size="50" />', |
| 1901 |
$company_name ? $company_name : get_bloginfo('name') |
| 1902 |
); |
| 1903 |
} |
| 1904 |
|
| 1905 |
public function site_google_logo_callback() |
| 1906 |
{ |
| 1907 |
|
| 1908 |
$google_logo = Metasync::get_option('optimal_settings')['site_info']['google_logo'] ?? ''; |
| 1909 |
|
| 1910 |
printf( |
| 1911 |
'<input type="hidden" id="site_google_logo" name="' . Metasync_Admin::option_key . '[optimal_settings][site_info][google_logo]" value="%s" size="50" />', |
| 1912 |
$google_logo |
| 1913 |
); |
| 1914 |
|
| 1915 |
printf(' <br> <input class="button-secondary" type="button" id="google_logo_btn" value="Add or Upload File">'); |
| 1916 |
printf(' <br><br> <span class="description bold"> Min Size: 160X90px, Max Size: 1920X1080px. </span> <br> <span class="description"> A squared image is preferred by the search engines. </span> <br><br> '); |
| 1917 |
printf('<img src="%s" id="site_google_logo_img" width="300">', wp_get_attachment_image_src($google_logo, 'medium')[0] ?? ''); |
| 1918 |
|
| 1919 |
$button_type = 'hidden'; |
| 1920 |
if ($google_logo) { |
| 1921 |
$button_type = 'button'; |
| 1922 |
} |
| 1923 |
printf('<input type="%s" class="button-secondary" id="site_google_logo_close_btn" value="X">', $button_type); |
| 1924 |
} |
| 1925 |
|
| 1926 |
public function site_social_share_image_callback() |
| 1927 |
{ |
| 1928 |
|
| 1929 |
$social_share_image = Metasync::get_option('optimal_settings')['site_info']['social_share_image'] ?? ''; |
| 1930 |
|
| 1931 |
printf( |
| 1932 |
'<input type="hidden" id="site_social_share_image" name="' . Metasync_Admin::option_key . '[optimal_settings][site_info][social_share_image]" value="%s" size="50" />', |
| 1933 |
$social_share_image |
| 1934 |
); |
| 1935 |
|
| 1936 |
printf(' <br> <input class="button-secondary" type="button" id="social_share_image_btn" value="Add or Upload File">'); |
| 1937 |
printf(' <br><br> <span class="description bold"> The recommended image size is 1200 x 630 pixels. </span> <br> <span class="description"> When a featured image or an OpenGraph Image is not set for individual posts/pages/CPTs, this image will be used as a fallback thumbnail when your post is shared on Facebook. </span> <br><br> '); |
| 1938 |
printf('<img src="%s" id="site_social_share_img" width="300">', wp_get_attachment_image_src($social_share_image, 'medium')[0] ?? ''); |
| 1939 |
|
| 1940 |
$button_type = 'hidden'; |
| 1941 |
if ($social_share_image) { |
| 1942 |
$button_type = 'button'; |
| 1943 |
} |
| 1944 |
printf('<input type="%s" class="button-secondary" id="site_social_image_close_btn" value="X">', $button_type); |
| 1945 |
} |
| 1946 |
|
| 1947 |
public function common_robot_meta_tags_callback() |
| 1948 |
{ |
| 1949 |
$common_robots_meta = Metasync::get_option('common_robots_meta') ?? Metasync::get_option('common_robots_mata') ?? ''; |
| 1950 |
|
| 1951 |
?> |
| 1952 |
<ul class="checkbox-list"> |
| 1953 |
<li> |
| 1954 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[common_robots_meta][index]') ?>" id="robots_common1" value="index" <?php isset($common_robots_meta['index']) ? checked('index', $common_robots_meta['index']) : '' ?>> |
| 1955 |
<label for="robots_common1">Index </br> |
| 1956 |
<span class="description"> |
| 1957 |
<span>Search engines to index and show these pages in the search results.</span> |
| 1958 |
</span> |
| 1959 |
</label> |
| 1960 |
</li> |
| 1961 |
<li> |
| 1962 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[common_robots_meta][noindex]') ?>" id="robots_common2" value="noindex" <?php isset($common_robots_meta['noindex']) ? checked('noindex', $common_robots_meta['noindex']) : '' ?>> |
| 1963 |
<label for="robots_common2">No Index </br> |
| 1964 |
<span class="description"> |
| 1965 |
<span>Search engines not indexed and displayed this pages in search engine results</span> |
| 1966 |
</span> |
| 1967 |
</label> |
| 1968 |
</li> |
| 1969 |
<li> |
| 1970 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[common_robots_meta][nofollow]') ?>" id="robots_common3" value="nofollow" <?php isset($common_robots_meta['nofollow']) ? checked('nofollow', $common_robots_meta['nofollow']) : '' ?>> |
| 1971 |
<label for="robots_common3">No Follow </br> |
| 1972 |
<span class="description"> |
| 1973 |
<span>Search engines not follow the links on the pages</span> |
| 1974 |
</span> |
| 1975 |
</label> |
| 1976 |
</li> |
| 1977 |
<li> |
| 1978 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[common_robots_meta][noarchive]') ?>" id="robots_common4" value="noarchive" <?php isset($common_robots_meta['noarchive']) ? checked('noarchive', $common_robots_meta['noarchive']) : '' ?>> |
| 1979 |
<label for="robots_common4">No Archive </br> |
| 1980 |
<span class="description"> |
| 1981 |
<span>Search engines not showing Cached links for pages</span> |
| 1982 |
</span> |
| 1983 |
</label> |
| 1984 |
</li> |
| 1985 |
<li> |
| 1986 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[common_robots_meta][noimageindex]') ?>" id="robots_common5" value="noimageindex" <?php isset($common_robots_meta['noimageindex']) ? checked('noimageindex', $common_robots_meta['noimageindex']) : '' ?>> |
| 1987 |
<label for="robots_common5">No Image Index </br> |
| 1988 |
<span class="description"> |
| 1989 |
<span>If you do not want to apear your pages as the referring page for images that appear in image search results</span> |
| 1990 |
</span> |
| 1991 |
</label> |
| 1992 |
</li> |
| 1993 |
<li> |
| 1994 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[common_robots_meta][nosnippet]') ?>" id="robots_common6" value="nosnippet" <?php isset($common_robots_meta['nosnippet']) ? checked('nosnippet', $common_robots_meta['nosnippet']) : '' ?>> |
| 1995 |
<label for="robots_common6">No Snippet </br> |
| 1996 |
<span class="description"> |
| 1997 |
<span>Search engines not snippet to show in the search results</span> |
| 1998 |
</span> |
| 1999 |
</label> |
| 2000 |
</li> |
| 2001 |
</ul> |
| 2002 |
<?php |
| 2003 |
} |
| 2004 |
|
| 2005 |
/** |
| 2006 |
* @deprecated Use common_robot_meta_tags_callback() instead |
| 2007 |
*/ |
| 2008 |
public function common_robot_mata_tags_callback() |
| 2009 |
{ |
| 2010 |
return $this->common_robot_meta_tags_callback(); |
| 2011 |
} |
| 2012 |
|
| 2013 |
public function advance_robot_meta_tags_callback() |
| 2014 |
{ |
| 2015 |
$advance_robots_meta = Metasync::get_option('advance_robots_meta') ?? Metasync::get_option('advance_robots_mata') ?? ''; |
| 2016 |
|
| 2017 |
$snippet_advance_robots_enable = $advance_robots_meta['max-snippet']['enable'] ?? ''; |
| 2018 |
$snippet_advance_robots_length = $advance_robots_meta['max-snippet']['length'] ?? '-1'; |
| 2019 |
$video_advance_robots_enable = $advance_robots_meta['max-video-preview']['enable'] ?? ''; |
| 2020 |
$video_advance_robots_length = $advance_robots_meta['max-video-preview']['length'] ?? '-1'; |
| 2021 |
$image_advance_robots_enable = $advance_robots_meta['max-image-preview']['enable'] ?? ''; |
| 2022 |
$image_advance_robots_length = $advance_robots_meta['max-image-preview']['length'] ?? ''; |
| 2023 |
|
| 2024 |
?> |
| 2025 |
<ul class="checkbox-list"> |
| 2026 |
<li> |
| 2027 |
<label for="advanced_robots_snippet"> |
| 2028 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[advance_robots_meta][max-snippet][enable]') ?>" id="advanced_robots_snippet" value="1" <?php checked('1', esc_attr($snippet_advance_robots_enable)) ?>> |
| 2029 |
Snippet </br> |
| 2030 |
<input type="number" class="input-length" name="<?php echo esc_attr(Metasync_Admin::option_key . '[advance_robots_meta][max-snippet][length]') ?>" id="advanced_robots_snippet_value" value="<?php echo esc_attr($snippet_advance_robots_length); ?>" min="-1"> </br> |
| 2031 |
<span class="description"> |
| 2032 |
<span>Add maximum text-length, in characters, of a snippet for your page.</span> |
| 2033 |
</span> |
| 2034 |
</label> |
| 2035 |
</li> |
| 2036 |
<li> |
| 2037 |
<label for="advanced_robots_video"> |
| 2038 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[advance_robots_meta][max-video-preview][enable]') ?>" id="advanced_robots_video" value="1" <?php checked('1', esc_attr($video_advance_robots_enable)) ?>> |
| 2039 |
Video Preview </br> |
| 2040 |
<input type="number" class="input-length" name="<?php echo esc_attr(Metasync_Admin::option_key . '[advance_robots_meta][max-video-preview][length]') ?>" id="advanced_robots_video_value" value="<?php echo esc_attr($video_advance_robots_length); ?>" min="-1"> </br> |
| 2041 |
<span class="description"> |
| 2042 |
<span>Add maximum duration in seconds of an animated video preview.</span> |
| 2043 |
</span> |
| 2044 |
</label> |
| 2045 |
</li> |
| 2046 |
<li> |
| 2047 |
<label for="advanced_robots_image"> |
| 2048 |
<input type="checkbox" name="<?php echo esc_attr(Metasync_Admin::option_key . '[advance_robots_meta][max-image-preview][enable]') ?>" id="advanced_robots_image" value="1" <?php checked('1', esc_attr($image_advance_robots_enable)); ?>> |
| 2049 |
Image Preview </br> |
| 2050 |
<select class="input-length" name="<?php echo esc_attr(Metasync_Admin::option_key . '[advance_robots_meta][max-image-preview][length]') ?>" id="advanced_robots_image_value"> |
| 2051 |
<option value="large" <?php selected('large', esc_attr($image_advance_robots_length)) ?>>Large</option> |
| 2052 |
<option value="standard" <?php selected('standard', esc_attr($image_advance_robots_length)) ?>>Standard</option> |
| 2053 |
<option value="none" <?php selected('none', esc_attr($image_advance_robots_length)) ?>>None</option> |
| 2054 |
</select> |
| 2055 |
</br> |
| 2056 |
<span class="description"> |
| 2057 |
<span>Add maximum size of image preview to show the images on this page.</span> |
| 2058 |
</span> |
| 2059 |
</label> |
| 2060 |
</li> |
| 2061 |
</ul> |
| 2062 |
<?php |
| 2063 |
} |
| 2064 |
|
| 2065 |
/** |
| 2066 |
* @deprecated Use advance_robot_meta_tags_callback() instead |
| 2067 |
*/ |
| 2068 |
public function advance_robot_mata_tags_callback() |
| 2069 |
{ |
| 2070 |
return $this->advance_robot_meta_tags_callback(); |
| 2071 |
} |
| 2072 |
|
| 2073 |
public function global_twitter_card_type_callback() |
| 2074 |
{ |
| 2075 |
$twitter_card_type = Metasync::get_option('twitter_card_type') ?? ''; |
| 2076 |
?> |
| 2077 |
|
| 2078 |
<select class="input-length" name="<?php echo esc_attr(Metasync_Admin::option_key . '[twitter_card_type]') ?>" id="twitter_card_type"> |
| 2079 |
<option value="summary_large_image" <?php selected('summary_large_image', esc_attr($twitter_card_type)) ?>>Summary Large Image</option> |
| 2080 |
<option value="summary_card" <?php selected('summary_card', esc_attr($twitter_card_type)) ?>>Summary Card</option> |
| 2081 |
</select> |
| 2082 |
|
| 2083 |
<?php |
| 2084 |
} |
| 2085 |
|
| 2086 |
public function global_open_graph_meta_callback() |
| 2087 |
{ |
| 2088 |
printf( |
| 2089 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][open_graph_meta_tags]" value="true" %s />', |
| 2090 |
isset(Metasync::get_option('common_meta_settings')['open_graph_meta_tags']) && Metasync::get_option('common_meta_settings')['open_graph_meta_tags'] == 'true' ? 'checked' : '' |
| 2091 |
); |
| 2092 |
printf(' <br> <span class="description"> Automatically add the Open Graph meta tags in a page or post.</span>'); |
| 2093 |
} |
| 2094 |
|
| 2095 |
public function global_facebook_meta_callback() |
| 2096 |
{ |
| 2097 |
printf( |
| 2098 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][facebook_meta_tags]" value="true" %s />', |
| 2099 |
isset(Metasync::get_option('common_meta_settings')['facebook_meta_tags']) && Metasync::get_option('common_meta_settings')['facebook_meta_tags'] == 'true' ? 'checked' : '' |
| 2100 |
); |
| 2101 |
printf(' <br> <span class="description"> Automatically add the Facebook meta tags in a page or post.</span>'); |
| 2102 |
} |
| 2103 |
|
| 2104 |
public function global_twitter_meta_callback() |
| 2105 |
{ |
| 2106 |
printf( |
| 2107 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][twitter_meta_tags]" value="true" %s />', |
| 2108 |
isset(Metasync::get_option('common_meta_settings')['twitter_meta_tags']) && Metasync::get_option('common_meta_settings')['twitter_meta_tags'] == 'true' ? 'checked' : '' |
| 2109 |
); |
| 2110 |
printf(' <br> <span class="description"> Automatically add the Twitter meta tags in a page or post.</span>'); |
| 2111 |
} |
| 2112 |
|
| 2113 |
public function og_image_dimensions_callback() |
| 2114 |
{ |
| 2115 |
$val = Metasync::get_option('common_meta_settings')['og_image_dimensions'] ?? 'true'; |
| 2116 |
printf( |
| 2117 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][og_image_dimensions]" value="true" %s />', |
| 2118 |
$val === 'true' ? 'checked' : '' |
| 2119 |
); |
| 2120 |
printf('<span class="description"> Output og:image:width, og:image:height, and og:image:type when OG image metadata is available.</span>'); |
| 2121 |
} |
| 2122 |
|
| 2123 |
public function article_timestamps_callback() |
| 2124 |
{ |
| 2125 |
$val = Metasync::get_option('common_meta_settings')['article_timestamps'] ?? 'true'; |
| 2126 |
printf( |
| 2127 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_timestamps]" value="true" %s />', |
| 2128 |
$val === 'true' ? 'checked' : '' |
| 2129 |
); |
| 2130 |
printf('<span class="description"> Output article:published_time and article:modified_time from the post publish and modified dates (ISO 8601).</span>'); |
| 2131 |
} |
| 2132 |
|
| 2133 |
public function article_author_callback() |
| 2134 |
{ |
| 2135 |
$val = Metasync::get_option('common_meta_settings')['article_author'] ?? 'true'; |
| 2136 |
printf( |
| 2137 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_author]" value="true" %s />', |
| 2138 |
$val === 'true' ? 'checked' : '' |
| 2139 |
); |
| 2140 |
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>'); |
| 2141 |
} |
| 2142 |
|
| 2143 |
public function article_section_callback() |
| 2144 |
{ |
| 2145 |
$val = Metasync::get_option('common_meta_settings')['article_section'] ?? 'true'; |
| 2146 |
printf( |
| 2147 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_section]" value="true" %s />', |
| 2148 |
$val === 'true' ? 'checked' : '' |
| 2149 |
); |
| 2150 |
printf('<span class="description"> Output article:section from the primary category (falls back to first category).</span>'); |
| 2151 |
} |
| 2152 |
|
| 2153 |
public function article_tags_callback() |
| 2154 |
{ |
| 2155 |
$val = Metasync::get_option('common_meta_settings')['article_tags'] ?? 'true'; |
| 2156 |
printf( |
| 2157 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][article_tags]" value="true" %s />', |
| 2158 |
$val === 'true' ? 'checked' : '' |
| 2159 |
); |
| 2160 |
printf('<span class="description"> Output one article:tag meta tag per WordPress post tag.</span>'); |
| 2161 |
} |
| 2162 |
|
| 2163 |
public function twitter_image_alt_callback() |
| 2164 |
{ |
| 2165 |
$val = Metasync::get_option('common_meta_settings')['twitter_image_alt'] ?? 'true'; |
| 2166 |
printf( |
| 2167 |
'<input type="checkbox" name="' . Metasync_Admin::option_key . '[common_meta_settings][twitter_image_alt]" value="true" %s />', |
| 2168 |
$val === 'true' ? 'checked' : '' |
| 2169 |
); |
| 2170 |
printf('<span class="description"> Output twitter:image:alt using the stored alt text or the OG image attachment alt attribute.</span>'); |
| 2171 |
} |
| 2172 |
|
| 2173 |
public function facebook_page_url_callback() |
| 2174 |
{ |
| 2175 |
$facebook_page_url = Metasync::get_option('social_meta')['facebook_page_url'] ?? ''; |
| 2176 |
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('<br><span class="description"> Enter your Facebook page URL. eg: <code>https://www.facebook.com/MetaSync/</code> </span>'); |
| 2178 |
} |
| 2179 |
|
| 2180 |
public function facebook_authorship_callback() |
| 2181 |
{ |
| 2182 |
$facebook_authorship = Metasync::get_option('social_meta')['facebook_authorship'] ?? ''; |
| 2183 |
printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_authorship]" value="%s" size="50" />', esc_attr($facebook_authorship)); |
| 2184 |
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>'); |
| 2185 |
} |
| 2186 |
|
| 2187 |
public function facebook_admin_callback() |
| 2188 |
{ |
| 2189 |
$facebook_admin = Metasync::get_option('social_meta')['facebook_admin'] ?? ''; |
| 2190 |
printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_admin]" value="%s" size="50" />', esc_attr($facebook_admin)); |
| 2191 |
printf(' <br> <span class="description"> Enter numeric user ID of Facebook. </span>'); |
| 2192 |
} |
| 2193 |
|
| 2194 |
public function facebook_app_callback() |
| 2195 |
{ |
| 2196 |
$facebook_app = Metasync::get_option('social_meta')['facebook_app'] ?? ''; |
| 2197 |
printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_app]" value="%s" size="50" />', esc_attr($facebook_app)); |
| 2198 |
printf(' <br> <span class="description"> Enter numeric app ID of Facebook </span>'); |
| 2199 |
} |
| 2200 |
|
| 2201 |
public function facebook_secret_callback() |
| 2202 |
{ |
| 2203 |
$facebook_secret = Metasync::get_option('social_meta')['facebook_secret'] ?? ''; |
| 2204 |
printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][facebook_secret]" value="%s" size="50" />', esc_attr($facebook_secret)); |
| 2205 |
printf(' <br> <span class="description"> Enter alphanumeric access token from Facebook. </span>'); |
| 2206 |
} |
| 2207 |
|
| 2208 |
public function twitter_username_callback() |
| 2209 |
{ |
| 2210 |
$twitter_username = Metasync::get_option('social_meta')['twitter_username'] ?? ''; |
| 2211 |
printf('<input type="text" name="' . Metasync_Admin::option_key . '[social_meta][twitter_username]" value="%s" size="50" />', esc_attr($twitter_username)); |
| 2212 |
printf(' <br> <span class="description"> Twitter username of the author to add <code>twitter:creator</code> tag to post. eg: <code>MetaSync</code> </span>'); |
| 2213 |
} |
| 2214 |
|
| 2215 |
public static function get_business_types() |
| 2216 |
{ |
| 2217 |
$business_type = [ |
| 2218 |
'Airline', |
| 2219 |
'Consortium', |
| 2220 |
'Corporation', |
| 2221 |
'Educational Organization', |
| 2222 |
'College Or University', |
| 2223 |
'Elementary School', |
| 2224 |
'High School', |
| 2225 |
'Middle School', |
| 2226 |
'Preschool', |
| 2227 |
'School', |
| 2228 |
'Funding Scheme', |
| 2229 |
'Government Organization', |
| 2230 |
'Library System', |
| 2231 |
'Local Business', |
| 2232 |
'Animal Shelter', |
| 2233 |
'Archive Organization', |
| 2234 |
'Automotive Business', |
| 2235 |
'Auto Body Shop', |
| 2236 |
'Auto Dealer', |
| 2237 |
'Auto Parts Store', |
| 2238 |
'Auto Rental', |
| 2239 |
'Auto Repair', |
| 2240 |
'Auto Wash', |
| 2241 |
'Gas Station', |
| 2242 |
'Motorcycle Dealer', |
| 2243 |
'Motorcycle Repair', |
| 2244 |
'Child Care', |
| 2245 |
'Dry Cleaning Or Laundry', |
| 2246 |
'Emergency Service', |
| 2247 |
'Fire Station', |
| 2248 |
'Hospital', |
| 2249 |
'Police Station', |
| 2250 |
'Employment Agency', |
| 2251 |
'Entertainment Business', |
| 2252 |
'Adult Entertainment', |
| 2253 |
'Amusement Park', |
| 2254 |
'Art Gallery', |
| 2255 |
'Casino', |
| 2256 |
'Comedy Club', |
| 2257 |
'Movie Theater', |
| 2258 |
'Night Club', |
| 2259 |
'Financial Service', |
| 2260 |
'Accounting Service', |
| 2261 |
'Automated Teller', |
| 2262 |
'Bank Or CreditUnion', |
| 2263 |
'Insurance Agency', |
| 2264 |
'Food Establishment', |
| 2265 |
'Bakery', |
| 2266 |
'Bar Or Pub', |
| 2267 |
'Brewery', |
| 2268 |
'Cafe Or CoffeeShop', |
| 2269 |
'Distillery', |
| 2270 |
'Fast Food Restaurant', |
| 2271 |
'IceCream Shop', |
| 2272 |
'Restaurant', |
| 2273 |
'Winery', |
| 2274 |
'Government Office', |
| 2275 |
'Post Office', |
| 2276 |
'Health And Beauty Business', |
| 2277 |
'Beauty Salon', |
| 2278 |
'Day Spa', |
| 2279 |
'Hair Salon', |
| 2280 |
'Health Club', |
| 2281 |
'Nail Salon', |
| 2282 |
'Tattoo Parlor', |
| 2283 |
'Home And Construction Business', |
| 2284 |
'Electrician', |
| 2285 |
'General Contractor', |
| 2286 |
'HVAC Business', |
| 2287 |
'House Painter', |
| 2288 |
'Locksmith', |
| 2289 |
'Moving Company', |
| 2290 |
'Plumber', |
| 2291 |
'Roofing Contractor', |
| 2292 |
'Internet Cafe', |
| 2293 |
'Legal Service', |
| 2294 |
'Attorney', |
| 2295 |
'Notary', |
| 2296 |
'Library', |
| 2297 |
'Lodging Business', |
| 2298 |
'Bed And Breakfast', |
| 2299 |
'Campground', |
| 2300 |
'Hostel', |
| 2301 |
'Hotel', |
| 2302 |
'Motel', |
| 2303 |
'Resort', |
| 2304 |
'Ski Resort', |
| 2305 |
'Medical Business', |
| 2306 |
'Community Health', |
| 2307 |
'Dentist', |
| 2308 |
'Dermatology', |
| 2309 |
'Diet Nutrition', |
| 2310 |
'Emergency', |
| 2311 |
'Geriatric', |
| 2312 |
'Gynecologic', |
| 2313 |
'Medical Clinic', |
| 2314 |
'Optician', |
| 2315 |
'Pharmacy', |
| 2316 |
'Physician', |
| 2317 |
'Professional Service', |
| 2318 |
'Radio Station', |
| 2319 |
'Real Estate Agent', |
| 2320 |
'Recycling Center', |
| 2321 |
'Self Storage', |
| 2322 |
'Shopping Center', |
| 2323 |
'Sports Activity Location', |
| 2324 |
'Bowling Alley', |
| 2325 |
'Exercise Gym', |
| 2326 |
'Golf Course', |
| 2327 |
'Public Swimming Pool', |
| 2328 |
'Ski Resort', |
| 2329 |
'Sports Club', |
| 2330 |
'Stadium Or Arena', |
| 2331 |
'Tennis Complex', |
| 2332 |
'Store', |
| 2333 |
'Bike Store', |
| 2334 |
'Book Store', |
| 2335 |
'Clothing Store', |
| 2336 |
'Computer Store', |
| 2337 |
'Convenience Store', |
| 2338 |
'Department Store', |
| 2339 |
'Electronics Store', |
| 2340 |
'Florist', |
| 2341 |
'Furniture Store', |
| 2342 |
'Garden Store', |
| 2343 |
'Grocery Store', |
| 2344 |
'Hardware Store', |
| 2345 |
'Hobby Shop', |
| 2346 |
'Home Goods Store', |
| 2347 |
'Jewelry Store', |
| 2348 |
'Liquor Store', |
| 2349 |
'Mens Clothing Store', |
| 2350 |
'Mobile Phone Store', |
| 2351 |
'Movie Rental Store', |
| 2352 |
'Music Store', |
| 2353 |
'Office Equipment Store', |
| 2354 |
'Outlet Store', |
| 2355 |
'Pawn Shop', |
| 2356 |
'Pet Store', |
| 2357 |
'Shoe Store', |
| 2358 |
'Sporting GoodsStore', |
| 2359 |
'Tire Shop', |
| 2360 |
'Toy Store', |
| 2361 |
'Wholesale Store', |
| 2362 |
'Television Station', |
| 2363 |
'Tourist Information Center', |
| 2364 |
'Travel Agency', |
| 2365 |
'Tree Services', |
| 2366 |
'Medical Organization', |
| 2367 |
'Diagnostic Lab', |
| 2368 |
'Veterinary Care', |
| 2369 |
'NGO', |
| 2370 |
'News Media Organization', |
| 2371 |
'Performing Group', |
| 2372 |
'Dance Group', |
| 2373 |
'Music Group', |
| 2374 |
'Theater Group', |
| 2375 |
'Project', |
| 2376 |
'Funding Agency', |
| 2377 |
'Research Project', |
| 2378 |
'Sports Organization', |
| 2379 |
'Sports Team', |
| 2380 |
'Workers Union', |
| 2381 |
]; |
| 2382 |
|
| 2383 |
return $business_type; |
| 2384 |
} |
| 2385 |
|
| 2386 |
/** |
| 2387 |
* Render breadcrumbs settings section |
| 2388 |
*/ |
| 2389 |
public function render_breadcrumbs_section() { |
| 2390 |
$options = Metasync::get_option('breadcrumbs', array()); |
| 2391 |
|
| 2392 |
$defaults = array( |
| 2393 |
'enabled' => true, |
| 2394 |
'separator' => '»', |
| 2395 |
'home_label' => 'Home', |
| 2396 |
'home_url' => '', |
| 2397 |
'show_current_page' => true, |
| 2398 |
'prefix_text' => '', |
| 2399 |
'archive_label_format' => '{name}', |
| 2400 |
'disable_schema' => false, |
| 2401 |
); |
| 2402 |
|
| 2403 |
$options = wp_parse_args($options, $defaults); |
| 2404 |
?> |
| 2405 |
<div style="background: var(--dashboard-card-bg); padding: 20px; border-radius: 8px;"> |
| 2406 |
|
| 2407 |
<!-- Enable/Disable --> |
| 2408 |
<div style="margin-bottom: 24px;"> |
| 2409 |
<label style="display: flex; align-items: center; gap: 12px; cursor: pointer;"> |
| 2410 |
<input type="checkbox" |
| 2411 |
name="metasync_options[breadcrumbs][enabled]" |
| 2412 |
value="1" |
| 2413 |
<?php checked($options['enabled'], 1); ?> |
| 2414 |
style="width: 18px; height: 18px; cursor: pointer;"> |
| 2415 |
<span style="font-weight: 500; color: var(--dashboard-text);">Enable breadcrumbs globally</span> |
| 2416 |
</label> |
| 2417 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2418 |
Enable or disable breadcrumb navigation on your site |
| 2419 |
</p> |
| 2420 |
</div> |
| 2421 |
|
| 2422 |
<!-- Disable Schema Markup --> |
| 2423 |
<div style="margin-bottom: 24px;"> |
| 2424 |
<label style="display: flex; align-items: center; gap: 12px; cursor: pointer;"> |
| 2425 |
<input type="checkbox" |
| 2426 |
name="metasync_options[breadcrumbs][disable_schema]" |
| 2427 |
value="1" |
| 2428 |
<?php checked($options['disable_schema'], 1); ?> |
| 2429 |
style="width: 18px; height: 18px; cursor: pointer;"> |
| 2430 |
<span style="font-weight: 500; color: var(--dashboard-text);">Disable breadcrumb schema markup (JSON-LD)</span> |
| 2431 |
</label> |
| 2432 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2433 |
When checked, MetaSync will not output the <code style="background: rgba(0,0,0,0.1); padding: 2px 4px; border-radius: 3px;">BreadcrumbList</code> JSON-LD in <code style="background: rgba(0,0,0,0.1); padding: 2px 4px; border-radius: 3px;"><head></code>. Use this if another SEO plugin already handles breadcrumb schema. |
| 2434 |
</p> |
| 2435 |
</div> |
| 2436 |
|
| 2437 |
<!-- Separator Character --> |
| 2438 |
<div style="margin-bottom: 24px;"> |
| 2439 |
<label for="breadcrumb_separator" style="display: block; margin-bottom: 8px; font-weight: 500; color: var(--dashboard-text);"> |
| 2440 |
Separator Character |
| 2441 |
</label> |
| 2442 |
<div style="display: flex; gap: 12px; flex-wrap: wrap;"> |
| 2443 |
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> |
| 2444 |
<input type="radio" name="metasync_options[breadcrumbs][separator]" value="»" <?php checked($options['separator'], '»'); ?>> |
| 2445 |
<span style="color: var(--dashboard-text);">»</span> |
| 2446 |
</label> |
| 2447 |
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> |
| 2448 |
<input type="radio" name="metasync_options[breadcrumbs][separator]" value="/" <?php checked($options['separator'], '/'); ?>> |
| 2449 |
<span style="color: var(--dashboard-text);">/</span> |
| 2450 |
</label> |
| 2451 |
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> |
| 2452 |
<input type="radio" name="metasync_options[breadcrumbs][separator]" value=">" <?php checked($options['separator'], '>'); ?>> |
| 2453 |
<span style="color: var(--dashboard-text);">></span> |
| 2454 |
</label> |
| 2455 |
<label style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> |
| 2456 |
<input type="radio" name="metasync_options[breadcrumbs][separator]" value="·" <?php checked($options['separator'], '·'); ?>> |
| 2457 |
<span style="color: var(--dashboard-text);">·</span> |
| 2458 |
</label> |
| 2459 |
</div> |
| 2460 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2461 |
Choose how to separate breadcrumb items |
| 2462 |
</p> |
| 2463 |
</div> |
| 2464 |
|
| 2465 |
<!-- Home Label --> |
| 2466 |
<div style="margin-bottom: 24px;"> |
| 2467 |
<label for="breadcrumb_home_label" style="display: block; margin-bottom: 8px; font-weight: 500; color: var(--dashboard-text);"> |
| 2468 |
Home Label |
| 2469 |
</label> |
| 2470 |
<input type="text" |
| 2471 |
id="breadcrumb_home_label" |
| 2472 |
name="metasync_options[breadcrumbs][home_label]" |
| 2473 |
value="<?php echo esc_attr($options['home_label']); ?>" |
| 2474 |
placeholder="Home" |
| 2475 |
style="width: 100%; padding: 10px 12px; background: var(--dashboard-input-bg); border: 1px solid var(--dashboard-border); border-radius: 6px; color: var(--dashboard-text); font-size: 14px; box-sizing: border-box;"> |
| 2476 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2477 |
Label for the home/root breadcrumb item |
| 2478 |
</p> |
| 2479 |
</div> |
| 2480 |
|
| 2481 |
<!-- Home URL --> |
| 2482 |
<div style="margin-bottom: 24px;"> |
| 2483 |
<label for="breadcrumb_home_url" style="display: block; margin-bottom: 8px; font-weight: 500; color: var(--dashboard-text);"> |
| 2484 |
Home URL |
| 2485 |
</label> |
| 2486 |
<input type="url" |
| 2487 |
id="breadcrumb_home_url" |
| 2488 |
name="metasync_options[breadcrumbs][home_url]" |
| 2489 |
value="<?php echo esc_attr($options['home_url']); ?>" |
| 2490 |
placeholder="<?php echo esc_attr(home_url('/')); ?>" |
| 2491 |
style="width: 100%; padding: 10px 12px; background: var(--dashboard-input-bg); border: 1px solid var(--dashboard-border); border-radius: 6px; color: var(--dashboard-text); font-size: 14px; box-sizing: border-box;"> |
| 2492 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2493 |
Leave empty to use your site home URL |
| 2494 |
</p> |
| 2495 |
</div> |
| 2496 |
|
| 2497 |
<!-- Show Current Page --> |
| 2498 |
<div style="margin-bottom: 24px;"> |
| 2499 |
<label style="display: flex; align-items: center; gap: 12px; cursor: pointer;"> |
| 2500 |
<input type="checkbox" |
| 2501 |
name="metasync_options[breadcrumbs][show_current_page]" |
| 2502 |
value="1" |
| 2503 |
<?php checked($options['show_current_page'], 1); ?> |
| 2504 |
style="width: 18px; height: 18px; cursor: pointer;"> |
| 2505 |
<span style="font-weight: 500; color: var(--dashboard-text);">Show current page</span> |
| 2506 |
</label> |
| 2507 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2508 |
Include the current page as the last (unlinked) breadcrumb item |
| 2509 |
</p> |
| 2510 |
</div> |
| 2511 |
|
| 2512 |
<!-- Prefix Text --> |
| 2513 |
<div style="margin-bottom: 24px;"> |
| 2514 |
<label for="breadcrumb_prefix" style="display: block; margin-bottom: 8px; font-weight: 500; color: var(--dashboard-text);"> |
| 2515 |
Prefix Text |
| 2516 |
</label> |
| 2517 |
<input type="text" |
| 2518 |
id="breadcrumb_prefix" |
| 2519 |
name="metasync_options[breadcrumbs][prefix_text]" |
| 2520 |
value="<?php echo esc_attr($options['prefix_text']); ?>" |
| 2521 |
placeholder='e.g., "You are here:"' |
| 2522 |
style="width: 100%; padding: 10px 12px; background: var(--dashboard-input-bg); border: 1px solid var(--dashboard-border); border-radius: 6px; color: var(--dashboard-text); font-size: 14px; box-sizing: border-box;"> |
| 2523 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2524 |
Optional text to display before the breadcrumbs (leave empty for none) |
| 2525 |
</p> |
| 2526 |
</div> |
| 2527 |
|
| 2528 |
<!-- Archive Label Format --> |
| 2529 |
<div style="margin-bottom: 24px;"> |
| 2530 |
<label for="breadcrumb_archive_format" style="display: block; margin-bottom: 8px; font-weight: 500; color: var(--dashboard-text);"> |
| 2531 |
Archive Label Format |
| 2532 |
</label> |
| 2533 |
<input type="text" |
| 2534 |
id="breadcrumb_archive_format" |
| 2535 |
name="metasync_options[breadcrumbs][archive_label_format]" |
| 2536 |
value="<?php echo esc_attr($options['archive_label_format']); ?>" |
| 2537 |
placeholder="{name}" |
| 2538 |
style="width: 100%; padding: 10px 12px; background: var(--dashboard-input-bg); border: 1px solid var(--dashboard-border); border-radius: 6px; color: var(--dashboard-text); font-size: 14px; box-sizing: border-box;"> |
| 2539 |
<p style="margin: 8px 0 0 0; font-size: 12px; color: var(--dashboard-text-secondary);"> |
| 2540 |
Use <code style="background: rgba(0,0,0,0.1); padding: 2px 4px; border-radius: 3px;">{name}</code> as a placeholder for the archive name. Example: <code style="background: rgba(0,0,0,0.1); padding: 2px 4px; border-radius: 3px;">Category: {name}</code> |
| 2541 |
</p> |
| 2542 |
</div> |
| 2543 |
|
| 2544 |
</div> |
| 2545 |
<?php |
| 2546 |
} |
| 2547 |
} |
| 2548 |
|