admin = $admin; } /** * @param Metasync_Admin $admin * @return self */ public static function get_instance(Metasync_Admin $admin): self { if (null === self::$instance || self::$instance->admin !== $admin) { self::$instance = new self($admin); } return self::$instance; } // ------------------------------------------------------------------ // Dashboard iframe (~200 lines) // ------------------------------------------------------------------ public function create_admin_dashboard_iframe() { $general_options = Metasync::get_option('general'); $otto_pixel_uuid = isset($general_options['otto_pixel_uuid']) ? $general_options['otto_pixel_uuid'] : ''; $api_key = isset($general_options['searchatlas_api_key']) ? $general_options['searchatlas_api_key'] : ''; $hide_dashboard = $general_options['hide_dashboard_framework'] ?? false; if ($hide_dashboard) { $this->admin->render_layout_open('Dashboard', 'dashboard', 'Overview of your SEO performance and plugin status.'); ?>

Dashboard Disabled

The dashboard is currently disabled.

admin->render_layout_close(false); return; } if (!$this->admin->is_heartbeat_connected()) { $this->admin->render_layout_open('Dashboard', 'dashboard', 'Overview of your SEO performance and plugin status.'); ?>

Setup Wizard

Run the setup wizard to configure your plugin, import from other SEO plugins, and optimize your settings in just a few minutes.

Start Setup Wizard

Authentication Required

You need to authenticate with to access the dashboard.

Go to Settings & Connect
admin->render_layout_close(false); return; } $jwt_token = $this->admin->get_fresh_jwt_token(); if ($jwt_token) { $jwt_parts = explode('.', $jwt_token); $jwt_header_info = count($jwt_parts) >= 2 ? 'Valid format (' . count($jwt_parts) . ' parts)' : 'Invalid format'; } else { } $public_hash = false; if ($jwt_token && $otto_pixel_uuid) { $public_hash = $this->admin->fetch_public_hash($otto_pixel_uuid, $jwt_token); if ($public_hash) { } else { } } else { $missing_params = []; if (empty($jwt_token)) $missing_params[] = 'JWT_TOKEN'; if (empty($otto_pixel_uuid)) $missing_params[] = 'OTTO_UUID'; } $dashboard_domain = Metasync_Admin::get_effective_dashboard_domain(); if ($public_hash) { $iframe_url = $dashboard_domain . '/seo-automation-v3/public?uuid=' . urlencode($otto_pixel_uuid) . '&category=onpage_optimizations&subGroup=page_title&public_hash=' . urlencode($public_hash); } else { $iframe_url = $dashboard_domain . '/seo-automation-v3/tasks?uuid=' . urlencode($otto_pixel_uuid) . '&category=All&Embed=True'; if ($jwt_token) { $iframe_url .= '&jwtToken=' . urlencode($jwt_token) . '&impersonate=1'; } else { } } $iframe_url .= '&source=wordpress-plugin-iframe'; $whitelabel_company_name = Metasync::get_whitelabel_company_name(); if ($whitelabel_company_name) { $iframe_url .= '&whitelabel=' . urlencode($whitelabel_company_name); } $whitelabel_settings = Metasync::get_whitelabel_settings(); $is_whitelabel_domain = !empty($whitelabel_settings['domain']); $this->admin->render_layout_open('Dashboard', 'dashboard', 'Overview of your SEO performance and plugin status.'); ?> admin->render_layout_close(false); } // ------------------------------------------------------------------ // Settings page (~1000 lines) // ------------------------------------------------------------------ public function create_admin_settings_page() { $active_tab = isset($_GET['tab']) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'general'; $whitelabel_settings = Metasync::get_whitelabel_settings(); $user_password = $whitelabel_settings['settings_password'] ?? ''; $hide_settings_enabled = !empty($whitelabel_settings['hide_settings']); $protected_tabs = []; if (!empty($user_password)) { $protected_tabs[] = 'whitelabel'; } if ($hide_settings_enabled && !empty($user_password)) { $protected_tabs = ['general', 'whitelabel', 'advanced']; } $password_protection_enabled = false; $password_validated = false; $password_error = ''; if (in_array($active_tab, $protected_tabs)) { $password_protection_enabled = !empty($user_password); $auth = new Metasync_Auth_Manager('whitelabel', 1800); $password_validated = $auth->has_access(); if (isset($_POST['whitelabel_password_submit']) && !$password_validated) { $password_error = 'Incorrect password. Please try again.'; } } $is_authenticated = $password_validated; $whitelabel_otto_name = Metasync::get_whitelabel_otto_name(); $page_slug = Metasync_Admin::$page_slug; ?> admin->render_layout_open('Settings', $settings_current_page, 'Manage all plugin settings and configuration.'); ?> *

* Clear all caches at once
* This will slow down your site until caches are rebuilt * *

* */ ?>

Protected Section

❌ Access Denied:
Forgot Password?

Security Tip: You can set a custom password in the White Label Settings to protect this section.

General Configuration

Configure your API, plugin features, caching, and general settings.

render_lock_button('general'); ?>
✅ Access Granted: You have successfully authenticated and can now modify settings.
admin->render_accordion_sections(Metasync_Admin::$page_slug . '_general'); ?>

Content Genius Synchronization

Sync your categories and user/author data with .

Setup Wizard

Run the setup wizard to configure your plugin, import from other SEO plugins, and optimize your settings in just a few minutes.

Start Setup Wizard

White Label Branding

Customize the plugin appearance with your own branding and logo.

render_lock_button('whitelabel'); ?>
✅ Access Granted: You have successfully authenticated and can now modify white label settings.

Color Palette

Customize the plugin color scheme for both dark and light themes. Changes preview instantly.

array( 'label' => 'Background', 'hint' => 'Main page background behind all content', 'dark' => '#0f1419', 'light' => '#f8f9fa', ), 'dashboard-card-bg' => array( 'label' => 'Card Background', 'hint' => 'Background of cards, panels, and content boxes', 'dark' => '#1a1f26', 'light' => '#ffffff', ), 'dashboard-card-hover' => array( 'label' => 'Card Hover', 'hint' => 'Card background when you hover over it', 'dark' => '#222831', 'light' => '#f1f3f5', ), 'dashboard-text-primary' => array( 'label' => 'Primary Text', 'hint' => 'Headings, body text, and main content', 'dark' => '#ffffff', 'light' => '#1a1f26', ), 'dashboard-text-secondary' => array( 'label' => 'Secondary Text', 'hint' => 'Descriptions, hints, and less important text', 'dark' => '#9ca3af', 'light' => '#6b7280', ), 'dashboard-accent' => array( 'label' => 'Accent Color', 'hint' => 'Buttons, links, and highlighted elements', 'dark' => '#3b82f6', 'light' => '#3b82f6', ), 'dashboard-accent-hover' => array( 'label' => 'Accent Hover', 'hint' => 'Buttons and links when hovered', 'dark' => '#2563eb', 'light' => '#2563eb', ), 'dashboard-success' => array( 'label' => 'Success', 'hint' => 'Success messages, connected status, positive indicators', 'dark' => '#10b981', 'light' => '#10b981', ), 'dashboard-warning' => array( 'label' => 'Warning', 'hint' => 'Warning alerts and caution indicators', 'dark' => '#f59e0b', 'light' => '#f59e0b', ), 'dashboard-error' => array( 'label' => 'Error', 'hint' => 'Error messages and critical alerts', 'dark' => '#ef4444', 'light' => '#ef4444', ), 'dashboard-border' => array( 'label' => 'Border', 'hint' => 'Card borders, dividers, and separators', 'dark' => '#374151', 'light' => '#e5e7eb', ), 'dashboard-gradient-primary-from' => array( 'label' => 'Button Gradient Start', 'hint' => 'Left/top color of buttons, save bars, and active tabs', 'dark' => '#667eea', 'light' => '#667eea', ), 'dashboard-gradient-primary-to' => array( 'label' => 'Button Gradient End', 'hint' => 'Right/bottom color of buttons, save bars, and active tabs', 'dark' => '#764ba2', 'light' => '#764ba2', ), 'dashboard-gradient-accent-from' => array( 'label' => 'Accent Gradient Start', 'hint' => 'Left/top color of secondary badges and highlight bars', 'dark' => '#f093fb', 'light' => '#f093fb', ), 'dashboard-gradient-accent-to' => array( 'label' => 'Accent Gradient End', 'hint' => 'Right/bottom color of secondary badges and highlight bars', 'dark' => '#f5576c', 'light' => '#f5576c', ), ); ?>
$field): ?>

$field): ?>

Export Whitelabel Plugin

Export the entire plugin with all whitelabel settings pre-configured. This creates a complete plugin zip file ready for installation on another WordPress site.

This will create a zip file containing the complete plugin with all your whitelabel settings included. Upload and install this zip file on another WordPress site via Plugins → Add New → Upload Plugin. All whitelabel configurations will be automatically applied upon activation.

'; echo '

Access Denied

'; echo '

You do not have permission to access this page.

'; echo ''; } else { ?>

🧰 Advanced Settings

Technical utilities for troubleshooting and connectivity checks.

render_lock_button('advanced'); ?>
✅ Access Granted: You have successfully authenticated and can now modify settings.

✅ Success! Debug mode has been enabled.

ℹ️ Debug Mode Disabled: Debug mode has been successfully disabled.

✅ Extended! Debug mode has been extended for another 24 hours.

❌ Error: Unable to perform the debug mode operation. Please try again.

admin->render_advanced_accordion(); ?>

✅ Success! All plugin settings have been cleared successfully and a new Plugin Auth Token has been generated. Please reconfigure the plugin as needed.

❌ Error! Failed to clear settings due to a security check failure. Please try again.

✅ Success! Error logs have been cleared successfully.

❌ Error! Failed to clear error logs due to a security check failure. Please try again.

✅ Success! Plugin access roles have been saved successfully.

❌ Error! Failed to save plugin access roles.

admin->render_layout_close(); ?> admin->render_layout_open('Dashboard', 'dashboard', ''); ?>

admin->get_effective_menu_title()); ?> Dashboard

Access your dashboard to view analytics, manage SEO settings, and monitor your site performance.

Authentication required: Please authenticate with your ' . esc_html(Metasync::get_effective_plugin_name()) . ' account and save your auth token in general settings.

'; echo 'Go to Settings'; } else { echo 'Open Dashboard'; } ?>
admin->render_layout_close(); ?> admin->render_layout_open('Robots.txt', 'robots_txt', 'Control which pages search engines can crawl.'); ?> validate_content($content); if ($validation['valid']) { $result = $robots_txt->write_robots_file($content); if (is_wp_error($result)) { echo '

' . esc_html($result->get_error_message()) . '

'; } else { echo '

' . esc_html__('robots.txt file saved successfully!', 'metasync') . '

'; if (!empty($validation['warnings'])) { foreach ($validation['warnings'] as $warning) { echo '

' . esc_html($warning) . '

'; } } } } else { echo '

' . esc_html__('Validation failed. Please fix the errors below:', 'metasync') . '

'; foreach ($validation['errors'] as $error) { echo '

- ' . esc_html($error) . '

'; } echo '
'; } } } $current_content = $robots_txt->read_robots_file(); if (is_wp_error($current_content)) { echo '

' . esc_html($current_content->get_error_message()) . '

'; $current_content = ''; } $backups = $robots_txt->get_backup_history(10); $file_exists = $robots_txt->file_exists(); $is_writable = $robots_txt->is_writable(); $robots_txt->render($this->admin, $current_content, $backups, $file_exists, $is_writable); ?> admin->render_layout_close(); ?> disable_other_sitemap_generators(); $result = $sitemap_generator->generate_sitemap(); if (is_wp_error($result)) { error_log('[MetaSync] Sitemap generation failed: ' . $result->get_error_message()); echo '

' . esc_html__('Sitemap generation failed. Please try again or check the error logs.', 'metasync') . '

'; } else { $message = esc_html__('Sitemap generated successfully!', 'metasync'); if ($disabled_plugins) { $message .= ' ' . esc_html__('Conflicting sitemap generators have been automatically disabled.', 'metasync'); } $robots_result = get_transient('metasync_sitemap_robots_updated'); if ($robots_result && $robots_result['success']) { if ($robots_result['action'] === 'added') { $message .= ' ' . esc_html__('Sitemap URL has been added to robots.txt.', 'metasync'); } elseif ($robots_result['action'] === 'updated') { $message .= ' ' . esc_html__('Sitemap URL has been updated in robots.txt.', 'metasync'); } elseif ($robots_result['action'] === 'created') { $message .= ' ' . esc_html__('robots.txt file has been created with sitemap URL.', 'metasync'); } delete_transient('metasync_sitemap_robots_updated'); } echo '

' . esc_html($message) . '

'; } } elseif (isset($_POST['enable_auto_update'])) { update_option('metasync_sitemap_auto_update', true); $sitemap_generator->setup_auto_update_hooks(); echo '

' . esc_html__('Auto-update enabled!', 'metasync') . '

'; } elseif (isset($_POST['disable_auto_update'])) { update_option('metasync_sitemap_auto_update', false); echo '

' . esc_html__('Auto-update disabled!', 'metasync') . '

'; } elseif (isset($_POST['delete_sitemap'])) { $deleted = $sitemap_generator->delete_sitemap(); if ($deleted) { update_option('metasync_sitemap_auto_update', false); echo '

' . esc_html__('Sitemap deleted successfully!', 'metasync') . '

'; } else { echo '

' . esc_html__('Failed to delete sitemap. The file may not exist or is not writable.', 'metasync') . '

'; } } elseif (isset($_POST['enable_other_sitemaps'])) { $enabled_plugins = $sitemap_generator->enable_other_sitemap_generators(); if ($enabled_plugins) { echo '

' . esc_html__('Other sitemap plugins have been re-enabled successfully!', 'metasync') . '

'; } else { echo '

' . esc_html__('No sitemap plugins were found to re-enable.', 'metasync') . '

'; } } } $sitemap_exists = $sitemap_generator->sitemap_exists(); $sitemap_url = $sitemap_generator->get_sitemap_url(); $url_count = $sitemap_generator->count_urls(); $last_generated = $sitemap_generator->get_last_generated_time(); $auto_update_enabled = get_option('metasync_sitemap_auto_update', false); $active_sitemap_plugins = $sitemap_generator->check_active_sitemap_plugins(); require_once plugin_dir_path(dirname(__FILE__)) . 'views/metasync-xml-sitemap.php'; } public function create_admin_custom_pages_page() { ?> admin->render_layout_open('Custom Pages', 'custom_pages', 'Create blank canvas pages for Elementor, Divi, or Gutenberg.'); ?>
admin->render_layout_close(); ?> admin->render_layout_open('404 Monitor', 'monitor_404', 'Track and manage 404 errors detected on your site.'); $ErrorMonitor->create_admin_plugin_interface(); $this->admin->render_layout_close(); } public function create_admin_search_engine_verification_page() { $page_slug = Metasync_Admin::$page_slug . '_searchengines-verification'; ?> admin->render_layout_open('Site Verification', 'site_verification', 'Verify your site ownership with search engines and other platforms.'); ?>

Search Engine Verification

Verify your site ownership with major search engines to access their tools and analytics.

admin->render_layout_close(); ?> admin->render_layout_open('Breadcrumbs', 'breadcrumbs', 'Configure breadcrumb trail settings and placement.'); ?>

Breadcrumbs Settings

Configure how breadcrumb trails are displayed across your site.

📖 How to Display Breadcrumbs

Breadcrumbs are not inserted automatically. Use one of the methods below to place them on your site.

Option 1 — Shortcode

Paste the shortcode inside any page, post, or widget:

[metasync_breadcrumb]

Option 2 — PHP Template Function

Call the helper function directly inside your theme template files (e.g. single.php, page.php, header.php):

<?php metasync_breadcrumb(); ?>

Option 3 — PHP Return Value

Get the breadcrumb HTML as a string to manipulate before output:

$breadcrumbs = new Metasync_Breadcrumbs();
echo $breadcrumbs->render_breadcrumb_html();

Tip: You can also pass a post_id argument to generate breadcrumbs for a specific post outside of a template context:
echo $breadcrumbs->render_breadcrumb_html(['post_id' => 123]);

admin->render_layout_close(); ?> admin->render_layout_open('Schema Markup', 'schema_markup', 'Configure global schema markup settings for your site. Organization and WebSite schemas are injected site-wide.'); ?>
admin->render_layout_close(); } public function create_admin_local_business_page() { $page_slug = Metasync_Admin::$page_slug . '_local-seo'; ?> admin->render_layout_open('Local Business', 'local_business', 'Configure local business information for better local SEO.'); ?>

🏢 Local Business Configuration

Configure your local business information for better local search engine optimization.

admin->render_layout_close(); ?> admin->render_layout_open('Code Snippets', 'code_snippets', 'Add custom code to your site header and footer.'); ?>

Code Snippets Management

Add custom code snippets to enhance your site functionality and tracking capabilities.

admin->render_layout_close(); ?> admin->create_admin_google_instant_index_page(); } public function create_admin_google_console_page() { ?> admin->render_layout_open('Google Console', 'google_console', ''); ?> show_google_instant_indexing_console(); ?> admin->render_layout_close(); ?> admin->render_layout_open('Bing Console', 'bing_console', ''); ?> show_bing_instant_indexing_console(); ?> admin->render_layout_close(); ?> admin->render_layout_open('Optimal Settings', 'optimal_settings', 'Apply recommended SEO settings automatically.'); ?>

Site Compatibility Status

Check your site's compatibility with optimal settings.

site_compatible_status_view(); ?>

Optimization Settings

Configure optimization settings for best performance.

optimization_settings_options(); ?>
admin->render_layout_close(); ?> admin->render_layout_open('Global Settings', 'general', ''); ?>

Global Configuration

Configure global settings that apply across your entire site.

admin->render_layout_close(); ?> admin->render_layout_open('Common Meta Settings', 'general', ''); ?>

Meta Configuration

Configure common meta tags and SEO settings for your site.

admin->render_layout_close(); ?> admin->render_layout_open('Social Meta', 'general', ''); ?>

📲 Social Meta Tags

Configure how your content appears when shared on social media platforms.

admin->render_layout_close(); ?> admin->render_layout_open('Indexation Control', 'seo_controls', 'Control how search engines index your content.'); ?>
Import from SEO Plugins
admin->render_layout_close(); ?> '); settings_fields(Metasync_Admin::option_group); do_settings_sections($page_slug); do_settings_sections($site_info_slug); submit_button(); printf(''); } public function create_admin_error_logs_page() { ?> admin->render_layout_open('Error Logs', 'general', ''); ?>

Error Logs Management

View and manage system error logs to troubleshoot issues and monitor plugin performance.

can_show_error_logs()) { $log_content = $error_logs->get_error_logs(50); if (!empty(trim($log_content))) { $error_logs->show_copy_button(); $error_logs->show_logs(); $error_logs->show_info(); } else { echo '
'; echo '

✅ Log file is empty - no errors recorded.

'; echo '
'; } } else { $error_message = $error_logs->get_error_message(); if (!empty($error_message)) { echo '
'; echo '

'; echo esc_html($error_message); echo '

'; echo '
'; } else { echo '
'; echo '

Unable to access error log file. Please check permissions.

'; echo '
'; } } ?>
admin->render_layout_close(); ?> handle_sync_log_ajax(); return; } $page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1; $per_page = 10; $offset = ($page - 1) * $per_page; $filters = [ 'date_range' => isset($_GET['date_range']) ? sanitize_text_field($_GET['date_range']) : '', 'status' => isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '', ]; $date_range = $filters['date_range']; $wp_now_ts = current_time('timestamp'); $date_from = ''; $date_to = ''; if (!empty($date_range)) { $date_to = date('Y-m-d H:i:s', $wp_now_ts); if ($date_range === 'today') { $start_ts = strtotime('today', $wp_now_ts); $date_from = date('Y-m-d H:i:s', $start_ts); } elseif ($date_range === 'yesterday') { $start_ts = strtotime('yesterday', $wp_now_ts); $end_ts = strtotime('today', $wp_now_ts) - 1; $date_from = date('Y-m-d H:i:s', $start_ts); $date_to = date('Y-m-d H:i:s', $end_ts); } elseif ($date_range === 'this_week') { $start_of_week = (int) get_option('start_of_week', 1); $day_of_week = (int) date('w', $wp_now_ts); $delta_days = ($day_of_week - $start_of_week + 7) % 7; $start_ts = strtotime('-' . $delta_days . ' days', strtotime('today', $wp_now_ts)); $date_from = date('Y-m-d H:i:s', $start_ts); } elseif ($date_range === 'this_month') { $start_ts = strtotime(date('Y-m-01 00:00:00', $wp_now_ts)); $date_from = date('Y-m-d H:i:s', $start_ts); } elseif ($date_range === 'all') { // no bounds } } if (!empty($date_from)) { $filters['date_from'] = $date_from; } if (!empty($date_to)) { $filters['date_to'] = $date_to; } $filters = array_filter($filters); $sync_records = $sync_db->getAllRecords($per_page, $offset, $filters); $total_records = $sync_db->get_count($filters); $total_pages = ceil($total_records / $per_page); $stats = $sync_db->get_statistics(); ?> admin->render_layout_open('Changes Log', 'sync_log', 'Track all SEO changes made by the plugin.'); ?>

Changes Log

Recent content synchronizations from external tools.

No sync records found

Sync records will appear here when content/pages receive new updates.

title); ?> url)): ?>
time_elapsed_string($record->created_at) ); ?>
status === 'published' || $record->status === 'publish'): ?> Published i Draft
1): ?>
Total records: | Showing -
1): ?>
admin->render_layout_close(); ?> Error Logs '); // $error_log = new Metasync_Error_Logs_Table($this->data_error_log_list); // $error_log->create_admin_error_log_list_interface(); } public function create_admin_heartbeat_error_logs_page() { ?> admin->render_layout_open('Heartbeat Error Logs', 'general', ''); ?>

💓 HeartBeat Error Logs

Monitor WordPress heartbeat errors to identify connectivity issues and system problems.

admin->db_heartbeat_errors); $heartbeat_errors->create_admin_heartbeat_errors_interface(); ?>
admin->render_layout_close(); ?> diff($ago); $string = [ 'y' => 'year', 'm' => 'month', 'w' => 'week', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second', ]; foreach ($string as $k => &$v) { if (isset($diff->$k) && $diff->$k) { $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); } else { unset($string[$k]); } } if (!$full) $string = array_slice($string, 0, 1); return $string ? implode(', ', $string) . ' ago' : 'just now'; } private function build_filter_query_string($filters) { $query_parts = []; foreach ($filters as $key => $value) { if (!empty($value)) { $query_parts[] = $key . '=' . urlencode($value); } } return !empty($query_parts) ? '&' . implode('&', $query_parts) : ''; } private function handle_sync_log_ajax() { wp_die(); } }