<?php
/*
Plugin Name: MYAIO - Your AI-Powered Co-Founder
Plugin URI: https://app.myaio.com
Description: AI-powered WordPress SEO plugin with real-time audits, smart recommendations, and controlled metadata deployment.

Version: 1.0.8
Author: MYAIO
License: GPLv2 or later
Text Domain: myaio-your-ai-powered-co-founder
*/


if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// Define constants
define( 'MYAIO_SAC_VERSION', '1.0' );
define( 'MYAIO_SAC_PATH', plugin_dir_path( __FILE__ ) );
define( 'MYAIO_SAC_URL', plugin_dir_url( __FILE__ ) );

// Storage directory (MUST be writable).
// IMPORTANT: Do NOT store backups inside the plugin folder, because many hosts
// make /wp-content/plugins read-only and backups would be deleted on reinstall.
if ( ! defined( 'MYAIO_STORAGE_PATH' ) ) {
	$myaio_uploads = wp_upload_dir();
	$myaio_base    = isset( $myaio_uploads['basedir'] ) ? $myaio_uploads['basedir'] : WP_CONTENT_DIR . '/uploads';
	define( 'MYAIO_STORAGE_PATH', trailingslashit( $myaio_base ) . 'myaio/' );
	define( 'MYAIO_BACKUP_DB_PATH', MYAIO_STORAGE_PATH . 'backups/db/' );
	define( 'MYAIO_BACKUP_FILES_PATH', MYAIO_STORAGE_PATH . 'backups/files/' );
	define( 'MYAIO_BACKUP_SITEMAPS_PATH', MYAIO_STORAGE_PATH . 'backups/sitemaps/' );
	define( 'MYAIO_SNAPSHOTS_PATH', MYAIO_STORAGE_PATH . 'snapshots/' );
}

// Config
if ( ! defined( 'MYAIO_RETRY_ATTEMPTS' ) ) {
	define( 'MYAIO_RETRY_ATTEMPTS', 25 );
}
// Timeout for backups + remote requests (seconds). 15 minutes.
if ( ! defined( 'MYAIO_REQUEST_TIMEOUT' ) ) {
	define( 'MYAIO_REQUEST_TIMEOUT', 900 );
}
// Extra free disk buffer to keep (bytes).
if ( ! defined( 'MYAIO_DISK_SPACE_BUFFER' ) ) {
	define( 'MYAIO_DISK_SPACE_BUFFER', 50 * 1024 * 1024 );
}

// API Key (placeholder)
if ( ! defined( 'MYAIO_SAC_API_KEY' ) ) {
	define( 'MYAIO_SAC_API_KEY', 'your_secret_api_key' );
}

function myaio_ensure_storage_dirs() {

	// Ensure wp_mkdir_p exists during activation (some hosts don't load it yet)
	if ( ! function_exists( 'wp_mkdir_p' ) ) {
		require_once ABSPATH . 'wp-admin/includes/file.php';
	}

	$dirs = [
		MYAIO_STORAGE_PATH,
		MYAIO_BACKUP_DB_PATH,
		MYAIO_BACKUP_FILES_PATH,
		MYAIO_BACKUP_SITEMAPS_PATH,
		MYAIO_SNAPSHOTS_PATH,
	];

	foreach ( $dirs as $dir ) {
		if ( ! file_exists( $dir ) ) {
			wp_mkdir_p( $dir );
		}
	}

	// Best-effort protection
	$htaccess = MYAIO_STORAGE_PATH . '.htaccess';
	if ( ! file_exists( $htaccess ) ) {
		@file_put_contents( $htaccess, "Deny from all\n" );
	}

	$index = MYAIO_STORAGE_PATH . 'index.php';
	if ( ! file_exists( $index ) ) {
		@file_put_contents( $index, "<?php // Silence is golden.\n" );
	}
}

/**
 * Purge previous backups/snapshots/logs on (re)install/activation.
 * Keeps .htaccess and index.php if present.
 */

/**
 * Initialize WP_Filesystem and return the global instance (or null on failure).
 *
 * @return WP_Filesystem_Base|null
 */
function myaio_get_wp_filesystem() {
	global $wp_filesystem;
	if ( $wp_filesystem instanceof WP_Filesystem_Base ) {
		return $wp_filesystem;
	}
	if ( ! function_exists( 'WP_Filesystem' ) ) {
		require_once ABSPATH . 'wp-admin/includes/file.php';
	}
	WP_Filesystem();
	return ( $wp_filesystem instanceof WP_Filesystem_Base ) ? $wp_filesystem : null;
}

/**
 * Sanitize a DB identifier (table/column) for safe interpolation.
 * Only allows [A-Za-z0-9_]. Returns empty string if invalid.
 */
function myaio_sanitize_db_identifier( $identifier ) {
	$identifier = (string) $identifier;
	if ( preg_match( '/^[A-Za-z0-9_]+$/', $identifier ) ) {
		return $identifier;
	}
	return '';
}
function myaio_purge_previous_artifacts() {
	$targets = [
		defined( 'MYAIO_BACKUP_DB_PATH' ) ? MYAIO_BACKUP_DB_PATH : '',
		defined( 'MYAIO_BACKUP_FILES_PATH' ) ? MYAIO_BACKUP_FILES_PATH : '',
		defined( 'MYAIO_SNAPSHOTS_PATH' ) ? MYAIO_SNAPSHOTS_PATH : '',
	];

	$fs = myaio_get_wp_filesystem();

	foreach ( $targets as $dir ) {
		if ( ! $dir || ! is_dir( $dir ) ) {
			continue;
		}

		// Prefer WP_Filesystem for deletions (Plugin Check compliant).
		if ( $fs ) {
			$items = (array) glob( trailingslashit( $dir ) . '*' );
			foreach ( $items as $path ) {
				$base = wp_basename( $path );
				if ( $base === '.htaccess' || $base === 'index.php' ) {
					continue;
				}
				if ( is_dir( $path ) ) {
					$fs->rmdir( $path, true );
				} else {
					wp_delete_file( $path );
				}
			}
		} else {
			// Fallback: best-effort using WP helpers (keeps logic intact).
			$items = @scandir( $dir );
			if ( ! is_array( $items ) ) {
				continue;
			}
			foreach ( $items as $item ) {
				if ( $item === '.' || $item === '..' ) {
					continue;
				}
				if ( $item === '.htaccess' || $item === 'index.php' ) {
					continue;
				}
				$path = $dir . $item;
				if ( is_dir( $path ) ) {
					if ( $fs ) {
						$fs->rmdir( $path, true );
					}
				} else {
					wp_delete_file( $path );
				}
			}
		}
	}

	// Remove file log.
	if ( defined( 'MYAIO_STORAGE_PATH' ) ) {
		wp_delete_file( trailingslashit( MYAIO_STORAGE_PATH ) . 'install.log' );
	}

	// Remove stored installer logs/state.
	delete_option( 'myaio_install_log' );
	delete_option( 'myaio_setup_state' );
	delete_option( 'myaio_setup_complete' );
}

/**
 * ✅ Fix redirects table schema (prevents Unknown column errors)
 */
function myaio_fix_redirects_table_schema() {
	global $wpdb;

	$table = $wpdb->prefix . 'myaio_redirects';

	$cache_key = 'tbl_exists_' . md5( $table );
	$exists    = wp_cache_get( $cache_key, 'myaio' );
	if ( false === $exists ) {
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cached below.
		$exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
		wp_cache_set( $cache_key, $exists, 'myaio', 300 );
	}

	if ( $exists !== $table ) {
		return;
	}

	$table_name = myaio_sanitize_db_identifier( $table );
	if ( '' === $table_name ) {
		return;
	}
	$table_sql = '`' . $table_name . '`';

	$cols_cache_key = 'tbl_cols_' . md5( $table_name );
	$cols           = wp_cache_get( $cols_cache_key, 'myaio' );
	if ( false === $cols ) {
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Identifier is sanitized above; cached below.
		$cols = $wpdb->get_col( "SHOW COLUMNS FROM {$table_sql}", 0 );
		wp_cache_set( $cols_cache_key, $cols, 'myaio', 300 );
	}

	if ( ! is_array( $cols ) ) {
		$cols = [];
	}

	if ( ! in_array( 'is_active', $cols, true ) ) {
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Identifier is sanitized above.
		$wpdb->query( "ALTER TABLE {$table_sql} ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1" );
		wp_cache_delete( $cols_cache_key, 'myaio' );
	}
	if ( ! in_array( 'match_query', $cols, true ) ) {
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Identifier is sanitized above.
		$wpdb->query( "ALTER TABLE {$table_sql} ADD COLUMN match_query TINYINT(1) NOT NULL DEFAULT 0" );
		wp_cache_delete( $cols_cache_key, 'myaio' );
	}
	if ( ! in_array( 'regex_flags', $cols, true ) ) {
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Identifier is sanitized above.
		$wpdb->query( "ALTER TABLE {$table_sql} ADD COLUMN regex_flags VARCHAR(50) NULL" );
		wp_cache_delete( $cols_cache_key, 'myaio' );
	}
}

// Autoload files
require_once MYAIO_SAC_PATH . 'includes/sac-loader.php';

// Register plugin activation/deactivation hooks
register_activation_hook( __FILE__, 'myaio_plugin_activate' );
function myaio_plugin_activate() {
	myaio_ensure_storage_dirs();
	myaio_purge_previous_artifacts();

	// ✅ Ensure redirects schema FIRST (so MU-loader won't crash on old tables)
	myaio_fix_redirects_table_schema();

	// Install MU-loader so SEO output persists even if main plugin is deactivated.
	myaio_install_mu_loader();

	// Keep activation fast on shared hosting: defer heavy migrations/sync to WP-Cron.
	update_option( 'myaio_deferred_activation_status', 'pending', false );
	update_option( 'myaio_baseline_sync_paged', 1, false );
	update_option( 'myaio_seo_migration_last_id', 0, false );
	delete_option( 'myaio_seo_migration_meta_done' );
	delete_option( 'myaio_seo_migration_final_done' );

	if ( ! wp_next_scheduled( 'myaio_run_deferred_activation' ) ) {
		wp_schedule_single_event( time() + 15, 'myaio_run_deferred_activation' );
	}

	// Keep any lightweight loader/table setup here.
	if ( class_exists( 'MYAIO_SAC_Loader' ) && method_exists( 'MYAIO_SAC_Loader', 'activate' ) ) {
		MYAIO_SAC_Loader::activate();
	}
}

add_action( 'myaio_run_deferred_activation', 'myaio_run_deferred_activation_tasks' );

/**
 * Run activation heavy work in small batches to avoid 500/timeouts on shared hosting.
 * This runs via WP-Cron and reschedules itself until complete.
 */
function myaio_run_deferred_activation_tasks() {

	if ( 'done' === (string) get_option( 'myaio_deferred_activation_status', '' ) ) {
		return;
	}

	// Best-effort: allow longer cron execution (hosts may ignore).
$started = microtime( true );
	$budget  = 18; // seconds (keep small to avoid host timeouts)

	// 1) Baseline sync in pages (only posts MYAIO has previously touched).
	$paged = (int) get_option( 'myaio_baseline_sync_paged', 1 );
	if ( $paged > 0 ) {
		$next = myaio_sync_seo_baseline_batch( $paged, 200, 2 ); // up to 400 posts per run
		update_option( 'myaio_baseline_sync_paged', (int) $next, false );
	}

	// 2) Meta migration in batches (RankMath/Yoast/AIOSEO -> MYAIO).
	$elapsed = microtime( true ) - $started;
	if ( $elapsed < $budget ) {
		$migrator_path = plugin_dir_path( __FILE__ ) . 'includes/seo/class-myaio-seo-migrator.php';
		if ( file_exists( $migrator_path ) ) {
			require_once $migrator_path;
			if ( class_exists( 'MYAIO_SEO_Migrator' ) && method_exists( 'MYAIO_SEO_Migrator', 'migrate_meta_batch' ) ) {
				MYAIO_SEO_Migrator::migrate_meta_batch( 200, max( 3, (int) ( $budget - $elapsed ) ) );
			}
		}
	}

	// 3) Finalize (redirects + sitemap settings) once meta is done.
	$meta_done  = (int) get_option( 'myaio_seo_migration_meta_done', 0 ) === 1;
	$final_done = (int) get_option( 'myaio_seo_migration_final_done', 0 ) === 1;

	if ( $meta_done && ! $final_done ) {
		// Ensure redirects table exists before finalizing.
		$continuity_path = plugin_dir_path( __FILE__ ) . 'includes/seo/class-myaio-seo-continuity.php';
		if ( file_exists( $continuity_path ) ) {
			require_once $continuity_path;
			if ( class_exists( 'MYAIO_SEO_Continuity' ) && method_exists( 'MYAIO_SEO_Continuity', 'ensure_tables' ) ) {
				MYAIO_SEO_Continuity::ensure_tables();
			}
		}

		myaio_fix_redirects_table_schema();

		$migrator_path = plugin_dir_path( __FILE__ ) . 'includes/seo/class-myaio-seo-migrator.php';
		if ( file_exists( $migrator_path ) ) {
			require_once $migrator_path;
			if ( class_exists( 'MYAIO_SEO_Migrator' ) && method_exists( 'MYAIO_SEO_Migrator', 'finalize_migration' ) ) {
				MYAIO_SEO_Migrator::finalize_migration();
			}
		}

		update_option( 'myaio_seo_migration_final_done', 1, false );
	}

	// Done when baseline paging finished AND meta+final done.
	$baseline_done = ( (int) get_option( 'myaio_baseline_sync_paged', 1 ) === 0 );

	if ( $baseline_done && $meta_done && ( (int) get_option( 'myaio_seo_migration_final_done', 0 ) === 1 ) ) {
		update_option( 'myaio_deferred_activation_status', 'done', false );
		return;
	}

	// Reschedule until done.
	if ( ! wp_next_scheduled( 'myaio_run_deferred_activation' ) ) {
		wp_schedule_single_event( time() + 30, 'myaio_run_deferred_activation' );
	}
}

register_deactivation_hook( __FILE__, [ 'MYAIO_SAC_Loader', 'deactivate' ] );

// Initialize plugin
add_action( 'plugins_loaded', [ 'MYAIO_SAC_Loader', 'init' ] );

/**
 * Install/refresh an MU-plugin loader so MYAIO SEO output persists even if the main plugin is deactivated.
 */
function myaio_install_mu_loader() {
	$mu_dir = WP_CONTENT_DIR . '/mu-plugins';
	if ( ! is_dir( $mu_dir ) ) {
		if ( function_exists( 'wp_mkdir_p' ) ) {
			@wp_mkdir_p( $mu_dir );
		} else {
			wp_mkdir_p( $mu_dir );
		}
	}

	if ( ! is_dir( $mu_dir ) || ! wp_is_writable( $mu_dir ) ) {
		update_option( 'myaio_mu_loader_failed', 1, false );
		return;
	}

	$loader_file = $mu_dir . '/myaio-seo-continuity-loader.php';

	$code = <<<'PHP'
<?php
/**
 * MYAIO SEO Continuity Loader (MU-plugin)
 * Loads automatically on every request, even if the main MYAIO plugin is deactivated.
 */
if (!defined('ABSPATH')) exit;

if (!function_exists('myaio__clean_text')) {
    function myaio__clean_text($value) {
        $value = trim(wp_strip_all_tags((string)$value));
        if ($value === '') return '';
        $value = sanitize_text_field($value);
        $value = preg_replace('/[[:cntrl:]]/u', '', $value);
        return trim($value);
    }
}
if (!function_exists('myaio__normalize_robots_meta')) {
    function myaio__normalize_robots_meta($value) {
        $allowed = [
            'index', 'noindex', 'follow', 'nofollow', 'noarchive', 'nosnippet', 'noimageindex',
        ];

        $push_tokens = static function (&$tokens, $raw) use ( $allowed ) {
            if (!is_scalar($raw)) {
                return;
            }

            $raw = strtolower(trim(wp_strip_all_tags((string) $raw)));
            if ($raw === '') {
                return;
            }

            foreach (preg_split('/\s*,\s*|\s+/', $raw) as $part) {
                $part = trim((string) $part);
                if ($part === '') {
                    continue;
                }

                if (in_array($part, $allowed, true) || preg_match('/^(?:max-snippet:-?\d+|max-image-preview:(?:none|standard|large)|max-video-preview:-?\d+|unavailable_after:.+)$/', $part)) {
                    $tokens[] = $part;
                }
            }
        };

        $is_truthy = static function ($raw) {
            if (is_bool($raw)) {
                return $raw;
            }
            if (is_int($raw) || is_float($raw)) {
                return (int) $raw === 1;
            }
            if (is_string($raw)) {
                $raw = strtolower(trim($raw));
                return in_array($raw, [ '1', 'true', 'yes', 'on', 'default', 'inherit', 'index', 'follow', 'enabled' ], true);
            }
            return false;
        };

        $walk = null;
        $walk = static function ($item, &$tokens) use (&$walk, $push_tokens, $is_truthy, $allowed) {
            $item = maybe_unserialize($item);
            if (is_string($item)) {
                $json = json_decode($item, true);
                if (json_last_error() === JSON_ERROR_NONE && is_array($json)) {
                    $item = $json;
                }
            }

            if (is_array($item)) {
                foreach ($item as $k => $v) {
                    $key = strtolower(trim((string) $k));

                    if (!is_int($k) && in_array($key, $allowed, true)) {
                        if (is_array($v)) {
                            $before = count($tokens);
                            $walk($v, $tokens);
                            if (count($tokens) === $before && isset($v['value']) && $is_truthy($v['value'])) {
                                $tokens[] = $key;
                            }
                        } elseif ($is_truthy($v) || strtolower(trim((string) $v)) === $key) {
                            $tokens[] = $key;
                        }
                        continue;
                    }

                    $walk($v, $tokens);
                }
                return;
            }

            $push_tokens($tokens, $item);
        };

        $tokens = [];
        $walk($value, $tokens);
        $tokens = array_values(array_unique(array_filter(array_map('trim', $tokens))));

        if (in_array('noindex', $tokens, true)) {
            $tokens = array_values(array_diff($tokens, [ 'index' ]));
        } elseif (in_array('index', $tokens, true) && !in_array('follow', $tokens, true) && !in_array('nofollow', $tokens, true)) {
            $tokens[] = 'follow';
        }

        if (in_array('nofollow', $tokens, true)) {
            $tokens = array_values(array_diff($tokens, [ 'follow' ]));
        } elseif (in_array('follow', $tokens, true) === false && (in_array('index', $tokens, true) || in_array('noindex', $tokens, true))) {
            $tokens[] = 'follow';
        }

        if (!in_array('index', $tokens, true) && !in_array('noindex', $tokens, true) && (in_array('follow', $tokens, true) || in_array('nofollow', $tokens, true))) {
            array_unshift($tokens, 'index');
        }

        $preferred_order = [ 'noindex', 'index', 'nofollow', 'follow', 'noarchive', 'nosnippet', 'noimageindex' ];
        usort($tokens, static function ($a, $b) use ( $preferred_order ) {
            $pa = array_search($a, $preferred_order, true);
            $pb = array_search($b, $preferred_order, true);
            $pa = ($pa === false) ? 999 : $pa;
            $pb = ($pb === false) ? 999 : $pb;
            if ($pa === $pb) {
                return strcmp($a, $b);
            }
            return $pa <=> $pb;
        });

        return implode(',', $tokens);
    }
}
if (!function_exists('myaio__first_nonempty')) {
    function myaio__first_nonempty(...$values) {
        foreach ($values as $v) {
            $v = myaio__clean_text($v);
            if ($v !== '') return $v;
        }
        return '';
    }
}

if (!function_exists('myaio__is_main_plugin_active')) {
    function myaio__is_main_plugin_active(): bool {
        $needle = 'myaio-your-ai-powered-co-founder.php';
        $plugins = (array) get_option('active_plugins', []);
        foreach ($plugins as $p) {
            if (is_string($p) && substr($p, -strlen($needle)) === $needle) return true;
        }
        if (function_exists('get_site_option')) {
            $sitewide = (array) get_site_option('active_sitewide_plugins', []);
            foreach (array_keys($sitewide) as $p) {
                if (is_string($p) && substr($p, -strlen($needle)) === $needle) return true;
            }
        }
        return false;
    }
}

// If a dedicated SEO plugin is active, do not output head tags here to avoid duplicates.
$_myaio_main_active = myaio__is_main_plugin_active();

// If a dedicated SEO plugin is active, do not output head tags here to avoid duplicates.
if (defined('RANK_MATH_VERSION') || defined('WPSEO_VERSION') || defined('AIOSEO_VERSION')) {
    // Also skip redirects here to avoid double-redirect conflicts.
    return;
}

/**
 * Redirect continuity (works even if main MYAIO plugin is deactivated)
 * Reads redirects from the myaio_redirects table (populated during migration / deploy).
 */
if (!function_exists('myaio__normalize_path')) {
    function myaio__normalize_path($url_or_path) {
        $s = trim((string) $url_or_path);

        if ($s === '') {
            return '';
        }
        // If full URL, keep only path + query.
        if (preg_match('~^https?://~i', $s)) {
            $parts = wp_parse_url($s);
            $path  = isset($parts['path']) ? $parts['path'] : '/';
            $q     = isset($parts['query']) ? $parts['query'] : '';

            if ($path === '' || $path === null) {
                $path = '/';
            }

            if ($path[0] !== '/') {
                $path = '/' . $path;
            }

            $out = $path;
            if ($q !== '') {
                $out .= '?' . $q;
            }

            return $out;
        }

        // Plain path -> always force leading slash.
        if ($s[0] !== '/') {
            $s = '/' . $s;
        }

        return $s;
    }
}

if (!function_exists('myaio__request_path')) {
    function myaio__request_path() {
        $uri = isset($_SERVER['REQUEST_URI']) ? (string)$_SERVER['REQUEST_URI'] : '/';
        if ($uri === '') $uri = '/';
        // ensure leading slash
        if ($uri[0] !== '/') $uri = '/' . $uri;
        return $uri;
    }
}

if (!function_exists('myaio__apply_redirects')) {
    function myaio__apply_redirects() {
        if (is_admin() || (defined('DOING_AJAX') && DOING_AJAX) || (defined('REST_REQUEST') && REST_REQUEST) || (defined('DOING_CRON') && DOING_CRON)) {
            return;
        }
        global $wpdb;
        $table = $wpdb->prefix . 'myaio_redirects';
        $exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table));
        if ($exists !== $table) return;

        $req = myaio__request_path();
        $req_path = wp_parse_url($req, PHP_URL_PATH);
        $req_qs   = wp_parse_url($req, PHP_URL_QUERY);

        // ✅ Build SELECT + WHERE based on existing columns (prevents Unknown column errors)
        $cols = $wpdb->get_col("SHOW COLUMNS FROM {$table}", 0);
        if (!is_array($cols)) $cols = [];

        if (!in_array('from_url', $cols, true) || !in_array('to_url', $cols, true)) return;

        $select = ['from_url','to_url'];
        if (in_array('http_code', $cols, true))   $select[] = 'http_code';
        if (in_array('is_regex', $cols, true))    $select[] = 'is_regex';
        if (in_array('match_query', $cols, true)) $select[] = 'match_query';
        if (in_array('regex_flags', $cols, true)) $select[] = 'regex_flags';

        // ✅ Only use is_active if the column exists
        $where = '';
        if (in_array('is_active', $cols, true)) {
            $where = ' WHERE is_active = 1 ';
        }

        $sql  = 'SELECT ' . implode(',', $select) . " FROM {$table} {$where} ORDER BY id ASC LIMIT 5000";
        $rows = $wpdb->get_results($sql, ARRAY_A);
        if (empty($rows)) return;

       foreach ($rows as $r) {
			$from = isset($r['from_url']) ? myaio__normalize_path($r['from_url']) : '';
			$to   = isset($r['to_url']) ? trim((string)$r['to_url']) : '';
			if ($from === '') continue;

			$code = isset($r['http_code']) ? (int)$r['http_code'] : 301;
			if (!in_array($code, [301, 302, 307, 308, 410, 451], true)) $code = 301;

            $is_regex = isset($r['is_regex']) ? (int)$r['is_regex'] : 0;

            $match_query = isset($r['match_query']) ? (int)$r['match_query'] : 0;
            $flags = isset($r['regex_flags']) ? (string)$r['regex_flags'] : '';

            $matched = false;

            if ($is_regex) {
                $delim = '~';
                $pattern = $delim . $from . $delim . $flags;
                $matched = @preg_match($pattern, $req) === 1 || @preg_match($pattern, $req_path) === 1;
            } else {
                if (strpos($from, '*') !== false) {
                    $rx = '~^' . str_replace('\*', '.*', preg_quote($from, '~')) . '$~';
                    $matched = (bool) preg_match($rx, $req) || (bool) preg_match($rx, $req_path);
                } else {
                    $from_path = wp_parse_url($from, PHP_URL_PATH);
                    $from_qs   = wp_parse_url($from, PHP_URL_QUERY);

                    $a = rtrim((string)$req_path, '/');
                    $b = rtrim((string)$from_path, '/');
                    if ($a === '') $a = '/';
                    if ($b === '') $b = '/';

                    $matched = ($a === $b);

                    if ($matched && $match_query) {
                        $matched = ((string)$req_qs === (string)$from_qs);
                    }
                }
            }

            if (!$matched) continue;

			if ($code === 410 || $code === 451) {
				nocache_headers();
				status_header($code);
				exit;
			}

			if (preg_match('~^https?://~i', $to)) {
				$target = $to;
			} else {
				if ($to === '') continue;
				if ($to[0] !== '/') $to = '/' . $to;
				$target = home_url($to);
			}

			$current = home_url($req);
			if (rtrim($current, '/') === rtrim($target, '/')) {
				continue;
			}

			wp_redirect($target, $code);
			exit;
        }
    }
}
add_action('template_redirect', 'myaio__apply_redirects', 0);


// ---------------- META REWRITE ----------------
if (!function_exists('myaio__rewrite_head_meta')) {
    function myaio__rewrite_head_meta($html) {
        if (!is_string($html) || $html === '') return $html;

        if (empty($GLOBALS['myaio__head_meta']) || !is_array($GLOBALS['myaio__head_meta'])) return $html;
        $m = $GLOBALS['myaio__head_meta'];

        $has_any = false;
        foreach (['description','keywords','robots','canonical','og_title','og_description','twitter_title','twitter_description','twitter_card','twitter_site'] as $k) {
            if (!empty($m[$k])) { $has_any = true; break; }
        }
        if (!$has_any) return $html;

        $desc = $m['description'];
        $keywords = $m['keywords'] ?? '';
        $robots = $m['robots'] ?? '';
        $canonical = $m['canonical'] ?? '';

        if (!empty($m['description'])) {
            $html = preg_replace('~<meta\b[^>]*\bname\s*=\s*(["\'])description\1[^>]*>\s*~i', '', $html);
        }
        if (!empty($m['keywords'])) {
            $html = preg_replace('~<meta\b[^>]*\bname\s*=\s*(["\'])keywords\1[^>]*>\s*~i', '', $html);
        }
        if (!empty($m['robots'])) {
            $html = preg_replace('~<meta\b[^>]*\bname\s*=\s*(["\'])robots\1[^>]*>\s*~i', '', $html);
        }
        if (!empty($m['canonical'])) {
            $html = preg_replace('~<link\b[^>]*\brel\s*=\s*(["\'])canonical\1[^>]*>\s*~i', '', $html);
        }

        if (!empty($m['og_title']) || !empty($m['og_description'])) {
            $html = preg_replace('~<meta\b[^>]*\bproperty\s*=\s*(["\'])og:(title|description)\1[^>]*>\s*~i', '', $html);
        }
        if (!empty($m['twitter_title']) || !empty($m['twitter_description']) || !empty($m['twitter_card']) || !empty($m['twitter_site'])) {
			$html = preg_replace('~<meta\b[^>]*\bname\s*=\s*(["\'])twitter:(title|description|card|site)\1[^>]*>\s*~i', '', $html);
		}

        $inserts = "";
        $inserts .= "\n<meta name=\"description\" content=\"" . esc_attr($desc) . "\" />\n";
        if ($keywords !== '') $inserts .= "<meta name=\"keywords\" content=\"" . esc_attr($keywords) . "\" />\n";
        if ($robots !== '') $inserts .= "<meta name=\"robots\" content=\"" . esc_attr($robots) . "\" />\n";
        if ($canonical !== '') $inserts .= "<link rel=\"canonical\" href=\"" . esc_url($canonical) . "\" />\n";

        $og_title = $m['og_title'] ?? '';
        $og_desc = $m['og_description'] ?? '';
        $tw_title = $m['twitter_title'] ?? '';
        $tw_desc = $m['twitter_description'] ?? '';
        $tw_card = $m['twitter_card'] ?? '';
		$tw_site = $m['twitter_site'] ?? '';

        if ($og_title !== '') $inserts .= "<meta property=\"og:title\" content=\"" . esc_attr($og_title) . "\" />\n";
        if ($og_desc !== '') $inserts .= "<meta property=\"og:description\" content=\"" . esc_attr($og_desc) . "\" />\n";
        if ($tw_card !== '') $inserts .= "<meta name=\"twitter:card\" content=\"" . esc_attr($tw_card) . "\" />\n";
        if ($tw_title !== '') $inserts .= "<meta name=\"twitter:title\" content=\"" . esc_attr($tw_title) . "\" />\n";
        if ($tw_desc !== '') $inserts .= "<meta name=\"twitter:description\" content=\"" . esc_attr($tw_desc) . "\" />\n";
		if ($tw_site !== '') $inserts .= "<meta name=\"twitter:site\" content=\"" . esc_attr($tw_site) . "\" />\n";

        if (stripos($html, '</head>') !== false) {
            $html = preg_replace('~</head>~i', $inserts . "</head>", $html, 1);
        } else {
            $html .= $inserts;
        }

        return $html;
    }
}

add_action('template_redirect', function () {
    global $_myaio_main_active;
    if (!empty($_myaio_main_active)) return;
    if (!is_singular()) return;
    $post_id = get_queried_object_id();
    if (!$post_id) return;

    $desc = myaio__first_nonempty(
        get_post_field('post_excerpt', $post_id),
        get_post_meta($post_id, '_myaio_seo_description', true),
        get_post_meta($post_id, '_myaio_meta_description', true)
    );

    if ($desc === '') return;

    $permalink = get_permalink($post_id);
    $canonical = myaio__first_nonempty(get_post_meta($post_id, '_myaio_canonical_url', true));
    if ($canonical === '') {
        if (function_exists('wp_get_canonical_url')) $canonical = myaio__clean_text(wp_get_canonical_url($post_id));
        if ($canonical === '') $canonical = $permalink;
    }

    $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_seo_robots', true ) );
    if ($robots === '') $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_meta_robots', true ) );
    if ($robots === '') $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_robots', true ) );
    if ($robots === '') $robots = 'index,follow';

    $keywords = myaio__first_nonempty(get_post_meta($post_id, '_myaio_seo_keywords', true), get_post_meta($post_id, '_myaio_meta_keywords', true));

    $GLOBALS['myaio__head_meta'] = [
        'description' => $desc,
        'keywords' => $keywords,
        'robots' => $robots,
        'canonical' => $canonical,
        'og_title' => myaio__clean_text(get_post_meta($post_id, '_myaio_og_title', true)),
        'og_description' => myaio__clean_text(get_post_meta($post_id, '_myaio_og_description', true)),
        'twitter_title' => myaio__clean_text(get_post_meta($post_id, '_myaio_twitter_title', true)),
        'twitter_description' => myaio__clean_text(get_post_meta($post_id, '_myaio_twitter_description', true)),
        'twitter_card' => myaio__clean_text(get_post_meta($post_id, '_myaio_twitter_card', true)),
    ];

    ob_start('myaio__rewrite_head_meta');
}, 0);

add_filter('pre_get_document_title', function ($title) {
    global $_myaio_main_active;
    if (!empty($_myaio_main_active)) return $title;
    if (!is_singular()) return $title;

    $post_id = get_queried_object_id();
    if (!$post_id) return $title;

    $seo_title = myaio__clean_text(get_post_meta($post_id, '_myaio_seo_title', true));
    return ($seo_title !== '') ? $seo_title : $title;
}, 9999);

add_action('wp_head', function () {
    global $_myaio_main_active;
    if (!empty($_myaio_main_active)) return;
    if (!is_singular()) return;

    $post_id = get_queried_object_id();
    if (!$post_id) return;

    $permalink = get_permalink($post_id);

    $desc = myaio__first_nonempty(
        get_post_field('post_excerpt', $post_id),
        get_post_meta($post_id, '_myaio_seo_description', true),
        get_post_meta($post_id, '_myaio_meta_description', true)
    );

    $keywords = myaio__first_nonempty(
        get_post_meta($post_id, '_myaio_seo_keywords', true),
        get_post_meta($post_id, '_myaio_meta_keywords', true)
    );

    $canonical = myaio__first_nonempty(get_post_meta($post_id, '_myaio_canonical_url', true));
    if ($canonical === '') {
        if (function_exists('wp_get_canonical_url')) {
            $canonical = myaio__clean_text(wp_get_canonical_url($post_id));
        }
        if ($canonical === '') $canonical = $permalink;
    }

    $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_seo_robots', true ) );
    if ( $robots === '' ) $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_meta_robots', true ) );
    if ( $robots === '' ) $robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_myaio_robots', true ) );
    if ( $robots === '' ) $robots = 'index,follow';

    if ($desc !== '') echo "\n<meta name=\"description\" content=\"" . esc_attr($desc) . "\" />\n";
    if ($keywords !== '') echo "\n<meta name=\"keywords\" content=\"" . esc_attr($keywords) . "\" />\n";
    if ($robots !== '') echo "\n<meta name=\"robots\" content=\"" . esc_attr($robots) . "\" />\n";
    if ($canonical !== '') echo "\n<link rel=\"canonical\" href=\"" . esc_url($canonical) . "\" />\n";
}, 99);
PHP;

	@file_put_contents( $loader_file, $code );
	delete_option( 'myaio_mu_loader_failed' );
}

/**
 * On activation, sync MYAIO stored SEO fields to whatever is currently live.
 * NOTE: We only sync posts/pages that MYAIO has previously touched (has MYAIO meta),
 * to avoid heavy site-wide operations during activation.
 */
function myaio_sync_seo_baseline_on_activation() {
	if ( ! class_exists( 'WP_Query' ) ) {
		return;
	}

	$public_types = get_post_types( [ 'public' => true ], 'names' );
	if ( isset( $public_types['attachment'] ) ) {
		unset( $public_types['attachment'] );
	}
	// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
	$meta_query = [
		'relation' => 'OR',
		[ 'key' => '_myaio_seo_title', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_seo_description', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_seo_keywords', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_meta_description', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_meta_keywords', 'compare' => 'EXISTS' ],
	];

	$paged     = 1;
	$per_page  = 200;
	$max_pages = 200; // safety cap: up to 40,000 posts

	while ( $paged <= $max_pages ) {
		// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
		$q = new WP_Query(
			[
				'post_type'      => array_values( $public_types ),
				'post_status'    => 'any',
				'posts_per_page' => $per_page,
				'paged'          => $paged,
				'fields'         => 'ids',
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
				'meta_query'     => $meta_query,
				'no_found_rows'  => false,
			]
		);

		if ( empty( $q->posts ) ) {
			break;
		}

		foreach ( $q->posts as $post_id ) {
			$current = myaio_get_current_seo_for_post( $post_id );

			if ( ! empty( $current['title'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_title', $current['title'] );
			}

			if ( ! empty( $current['description'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_description', $current['description'] );
				update_post_meta( $post_id, '_myaio_meta_description', $current['description'] );
			}

			if ( ! empty( $current['keywords'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_keywords', $current['keywords'] );
				update_post_meta( $post_id, '_myaio_meta_keywords', $current['keywords'] );
			}

			if ( ! empty( $current['canonical'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_canonical', $current['canonical'] );
			}
			if ( ! empty( $current['robots'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_robots', $current['robots'] );
			}

			if ( ! empty( $current['og_title'] ) ) {
				update_post_meta( $post_id, '_myaio_og_title', $current['og_title'] );
			}
			if ( ! empty( $current['og_description'] ) ) {
				update_post_meta( $post_id, '_myaio_og_description', $current['og_description'] );
			}
			if ( ! empty( $current['twitter_title'] ) ) {
				update_post_meta( $post_id, '_myaio_twitter_title', $current['twitter_title'] );
			}
			if ( ! empty( $current['twitter_description'] ) ) {
				update_post_meta( $post_id, '_myaio_twitter_description', $current['twitter_description'] );
			}
			if ( ! empty( $current['twitter_card'] ) ) {
				update_post_meta( $post_id, '_myaio_twitter_card', $current['twitter_card'] );
			}
			if ( ! empty( $current['twitter_site'] ) ) {
				update_post_meta( $post_id, '_myaio_twitter_site', $current['twitter_site'] );
			}
		}

		$paged++;
		wp_reset_postdata();

		if ( $paged > (int) $q->max_num_pages ) {
			break;
		}
	}

	update_option( 'myaio_last_activation_seo_sync', time(), false );
}


/**
 * Baseline sync batch runner used by deferred activation (WP-Cron).
 *
 * @param int $paged           Current page (1-based).
 * @param int $per_page        Posts per page.
 * @param int $max_pages_run   Max pages to process in this call.
 * @return int Next page number, or 0 when complete.
 */
function myaio_sync_seo_baseline_batch( $paged, $per_page = 200, $max_pages_run = 1 ) {

	$paged = max( 1, (int) $paged );
	$per_page = max( 10, (int) $per_page );
	$max_pages_run = max( 1, (int) $max_pages_run );

	if ( ! class_exists( 'WP_Query' ) ) {
		return 0;
	}

	$public_types = get_post_types( [ 'public' => true ], 'names' );
	if ( isset( $public_types['attachment'] ) ) {
		unset( $public_types['attachment'] );
	}
	// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
	$meta_query = [
		'relation' => 'OR',
		[ 'key' => '_myaio_seo_title', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_seo_description', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_seo_keywords', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_meta_description', 'compare' => 'EXISTS' ],
		[ 'key' => '_myaio_meta_keywords', 'compare' => 'EXISTS' ],
	];
		// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query

	$pages_run = 0;

	while ( $pages_run < $max_pages_run ) {

		$q = new WP_Query(
			[
				'post_type'      => array_values( $public_types ),
				'post_status'    => 'any',
				'posts_per_page' => $per_page,
				'paged'          => $paged,
				'fields'         => 'ids',
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
				'meta_query'     => $meta_query,
				'no_found_rows'  => false,
			]
		);

		if ( empty( $q->posts ) ) {
			wp_reset_postdata();
			update_option( 'myaio_last_activation_seo_sync', time(), false );
			return 0;
		}

		foreach ( $q->posts as $post_id ) {
			$current = myaio_get_current_seo_for_post( $post_id );

			if ( ! empty( $current['title'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_title', $current['title'] );
			}

			if ( ! empty( $current['description'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_description', $current['description'] );
				update_post_meta( $post_id, '_myaio_meta_description', $current['description'] );
			}

			if ( ! empty( $current['keywords'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_keywords', $current['keywords'] );
				update_post_meta( $post_id, '_myaio_meta_keywords', $current['keywords'] );
			}

			if ( ! empty( $current['canonical'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_canonical', $current['canonical'] );
			}
			if ( ! empty( $current['robots'] ) ) {
				update_post_meta( $post_id, '_myaio_seo_robots', $current['robots'] );
			}

			if ( ! empty( $current['og_title'] ) ) {
				update_post_meta( $post_id, '_myaio_og_title', $current['og_title'] );
			}
			if ( ! empty( $current['og_description'] ) ) {
				update_post_meta( $post_id, '_myaio_og_description', $current['og_description'] );
			}
			if ( ! empty( $current['twitter_title'] ) ) {
				update_post_meta( $post_id, '_myaio_twitter_title', $current['twitter_title'] );
			}
			if ( ! empty( $current['twitter_description'] ) ) {
				update_post_meta( $post_id, '_myaio_twitter_description', $current['twitter_description'] );
			}
			if ( ! empty( $current['twitter_card'] ) ) {
				update_post_meta( $post_id, '_myaio_twitter_card', $current['twitter_card'] );
			}
		}

		$max_pages = (int) $q->max_num_pages;
		wp_reset_postdata();

		$paged++;
		$pages_run++;

		if ( $paged > $max_pages ) {
			update_option( 'myaio_last_activation_seo_sync', time(), false );
			return 0;
		}
	}

	return $paged;
}


/**
 * Get "currently live" SEO values for a post, preferring common SEO plugin meta,
 * otherwise falling back to WordPress core fields.
 */
function myaio_get_current_seo_for_post( $post_id ) {
	$out = [
		'title'               => '',
		'description'         => '',
		'keywords'            => '',
		'canonical'           => '',
		'robots'              => '',
		'og_title'            => '',
		'og_description'      => '',
		'twitter_title'       => '',
		'twitter_description' => '',
		'twitter_card'        => '',
		'twitter_site'        => '',
	];

	// ----- Title -----
	$title = '';

	$rm_title = get_post_meta( $post_id, 'rank_math_title', true );
	if ( is_string( $rm_title ) && trim( $rm_title ) !== '' && strpos( $rm_title, '%' ) === false ) {
		$title = $rm_title;
	}

	if ( $title === '' ) {
		$yo_title = get_post_meta( $post_id, '_yoast_wpseo_title', true );
		if ( is_string( $yo_title ) && trim( $yo_title ) !== '' && strpos( $yo_title, '%%' ) === false ) {
			$title = $yo_title;
		}
	}

	if ( $title === '' ) {
		$aio_title = get_post_meta( $post_id, '_aioseo_title', true );
		if ( is_string( $aio_title ) && trim( $aio_title ) !== '' && strpos( $aio_title, '#' ) === false ) {
			$title = $aio_title;
		}
	}

	if ( $title === '' ) {
		$title = get_the_title( $post_id );
	}

	$title        = trim( wp_strip_all_tags( (string) $title ) );
	$title        = sanitize_text_field( $title );
	$title        = preg_replace( '/[[:cntrl:]]/u', '', $title );
	$out['title'] = $title;

	// ----- Description -----
	$desc    = '';
	$rm_desc = get_post_meta( $post_id, 'rank_math_description', true );
	if ( is_string( $rm_desc ) && trim( $rm_desc ) !== '' && strpos( $rm_desc, '%' ) === false ) {
		$desc = $rm_desc;
	}

	if ( $desc === '' ) {
		$yo_desc = get_post_meta( $post_id, '_yoast_wpseo_metadesc', true );
		if ( is_string( $yo_desc ) && trim( $yo_desc ) !== '' ) {
			$desc = $yo_desc;
		}
	}

	if ( $desc === '' ) {
		$aio_desc = get_post_meta( $post_id, '_aioseo_description', true );
		if ( is_string( $aio_desc ) && trim( $aio_desc ) !== '' && strpos( $aio_desc, '#' ) === false ) {
			$desc = $aio_desc;
		}
	}

	if ( $desc === '' ) {
		$desc = get_post_field( 'post_excerpt', $post_id );
	}

	$desc               = trim( wp_strip_all_tags( (string) $desc ) );
	$desc               = sanitize_text_field( $desc );
	$desc               = preg_replace( '/[[:cntrl:]]/u', '', $desc );
	$out['description'] = $desc;

	// ----- Keywords -----
	$kw    = '';
	$rm_kw = get_post_meta( $post_id, 'rank_math_focus_keyword', true );
	if ( is_string( $rm_kw ) && trim( $rm_kw ) !== '' ) {
		$kw = $rm_kw;
	}

	if ( $kw === '' ) {
		$yo_kw = get_post_meta( $post_id, '_yoast_wpseo_focuskw', true );
		if ( is_string( $yo_kw ) && trim( $yo_kw ) !== '' ) {
			$kw = $yo_kw;
		}
	}

	if ( $kw === '' ) {
		$aio_kw = get_post_meta( $post_id, '_aioseo_keywords', true );
		if ( is_string( $aio_kw ) && trim( $aio_kw ) !== '' && strpos( $aio_kw, '#' ) === false ) {
			$kw = $aio_kw;
		}
	}

	$kw              = trim( wp_strip_all_tags( (string) $kw ) );
	$kw              = sanitize_text_field( $kw );
	$kw              = preg_replace( '/[[:cntrl:]]/u', '', $kw );
	$out['keywords'] = $kw;

	// ----- Canonical / Robots -----
	$canonical = '';
	$rm_can    = get_post_meta( $post_id, 'rank_math_canonical_url', true );
	if ( is_string( $rm_can ) && trim( $rm_can ) !== '' ) {
		$canonical = $rm_can;
	}

	if ( $canonical === '' ) {
		$yo_can = get_post_meta( $post_id, '_yoast_wpseo_canonical', true );
		if ( is_string( $yo_can ) && trim( $yo_can ) !== '' ) {
			$canonical = $yo_can;
		}
	}

	if ( $canonical === '' ) {
		$aio_can = get_post_meta( $post_id, '_aioseo_canonical_url', true );
		if ( is_string( $aio_can ) && trim( $aio_can ) !== '' ) {
			$canonical = $aio_can;
		}
	}

	if ( $canonical === '' ) {
		$canonical = get_permalink( $post_id );
	}

	$out['canonical'] = trim( (string) $canonical );

	$robots = myaio__normalize_robots_meta( get_post_meta( $post_id, 'rank_math_robots', true ) );
	if ( $robots === '' ) {
		$robots = myaio__normalize_robots_meta( get_post_meta( $post_id, '_aioseo_robots', true ) );
	}
	if ( $robots === '' ) {
		$noindex  = get_post_meta( $post_id, '_yoast_wpseo_meta-robots-noindex', true );
		$nofollow = get_post_meta( $post_id, '_yoast_wpseo_meta-robots-nofollow', true );
		if ( $noindex === '1' || $nofollow === '1' ) {
			$parts   = [];
			$parts[] = ( $noindex === '1' ) ? 'noindex' : 'index';
			$parts[] = ( $nofollow === '1' ) ? 'nofollow' : 'follow';
			$robots  = implode( ',', $parts );
		}
	}
	if ( $robots === '' ) {
		$robots = 'index,follow';
	}
	$out['robots'] = trim( (string) $robots );

	// ----- Open Graph / Twitter -----
	$og_title = '';
	$og_desc  = '';
	$tw_title = '';
	$tw_desc  = '';
	$tw_card  = '';
	$tw_site  = '';

	// Rank Math
	foreach ( [ 'rank_math_facebook_title', 'rank_math_facebook_title' ] as $k ) {
		$v = get_post_meta( $post_id, $k, true );
		if ( is_string( $v ) && trim( $v ) !== '' && strpos( $v, '%' ) === false ) {
			$og_title = $v;
			break;
		}
	}
	$v = get_post_meta( $post_id, 'rank_math_facebook_description', true );
	if ( is_string( $v ) && trim( $v ) !== '' && strpos( $v, '%' ) === false ) {
		$og_desc = $v;
	}

	$v = get_post_meta( $post_id, 'rank_math_twitter_title', true );
	if ( is_string( $v ) && trim( $v ) !== '' && strpos( $v, '%' ) === false ) {
		$tw_title = $v;
	}
	$v = get_post_meta( $post_id, 'rank_math_twitter_description', true );
	if ( is_string( $v ) && trim( $v ) !== '' && strpos( $v, '%' ) === false ) {
		$tw_desc = $v;
	}
	$v = get_post_meta( $post_id, 'rank_math_twitter_card_type', true );
	if ( is_string( $v ) && trim( $v ) !== '' ) {
		$tw_card = $v;
	}
	$v = get_post_meta( $post_id, '_myaio_twitter_site', true );
	if ( is_string( $v ) && trim( $v ) !== '' ) {
		$tw_site = $v;
	}

	// Yoast social
	if ( $og_title === '' ) {
		$v = get_post_meta( $post_id, '_yoast_wpseo_opengraph-title', true );
		if ( is_string( $v ) && trim( $v ) !== '' ) {
			$og_title = $v;
		}
	}
	if ( $og_desc === '' ) {
		$v = get_post_meta( $post_id, '_yoast_wpseo_opengraph-description', true );
		if ( is_string( $v ) && trim( $v ) !== '' ) {
			$og_desc = $v;
		}
	}
	if ( $tw_title === '' ) {
		$v = get_post_meta( $post_id, '_yoast_wpseo_twitter-title', true );
		if ( is_string( $v ) && trim( $v ) !== '' ) {
			$tw_title = $v;
		}
	}
	if ( $tw_desc === '' ) {
		$v = get_post_meta( $post_id, '_yoast_wpseo_twitter-description', true );
		if ( is_string( $v ) && trim( $v ) !== '' ) {
			$tw_desc = $v;
		}
	}
	if ( $tw_card === '' ) {
		$v = get_post_meta( $post_id, '_yoast_wpseo_twitter-card', true );
		if ( is_string( $v ) && trim( $v ) !== '' ) {
			$tw_card = $v;
		}
	}

	$out['og_title']            = sanitize_text_field( trim( wp_strip_all_tags( (string) $og_title ) ) );
	$out['og_description']      = sanitize_text_field( trim( wp_strip_all_tags( (string) $og_desc ) ) );
	$out['twitter_title']       = sanitize_text_field( trim( wp_strip_all_tags( (string) $tw_title ) ) );
	$out['twitter_description'] = sanitize_text_field( trim( wp_strip_all_tags( (string) $tw_desc ) ) );
	$out['twitter_card']        = sanitize_text_field( trim( wp_strip_all_tags( (string) $tw_card ) ) );
	$out['twitter_site']        = sanitize_text_field( trim( wp_strip_all_tags( (string) $tw_site ) ) );

	return $out;
}

add_action(
	'admin_notices',
	function () {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		if ( ! get_option( 'myaio_mu_loader_failed' ) ) {
			return;
		}

		echo '<div class="notice notice-warning"><p><strong>MYAIO:</strong> Unable to create the MU-loader file in <code>wp-content/mu-plugins</code>. SEO title/meta tags will not persist if MYAIO is deactivated. Please ensure the folder exists and is writable.</p></div>';
	}
);