<?php

/**
 * Plugin Name:       PlugUpp Search & Social Appearance Audit
 * Plugin URI:        https://wordpress.org/plugins/search-social-appearance-audit/
 * Description:       See exactly how your WordPress content appears in search engines and on social media - audits the final rendered output, regardless of theme, SEO plugin or page builder.
 * Version:           1.4.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            PlugUpp
 * Author URI:        https://plugupp.com/
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       search-social-appearance-audit
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
// ----------------------------------------------------------------------------
// Free <-> Premium co-existence guard.
//
// During an upgrade from free to premium (or downgrade premium -> free),
// WordPress can briefly load BOTH plugin folders in the same request. The
// Freemius SDK's documented solution (SDK Integration step 19):
//
//   1. The FIRST file to load wins - it falls through to the `else` branch
//      and runs the full bootstrap, including defining ssaa_fs().
//   2. The SECOND file to load sees ssaa_fs() already exists, calls
//      ssaa_fs()->set_basename( true, __FILE__ ), and exits. set_basename
//      tells the SDK "the active install lives at THIS __FILE__", which
//      triggers the SDK to deactivate the other build automatically.
//
// NOTE: until the Freemius SDK is vendored (vendor/freemius/) and the
// placeholder IDs below are replaced, ssaa_fs() is never defined and this
// guard is inert. That is fine during development - the guard becomes live
// the moment the SDK lands. Do not ship to Freemius/WP.org without it live.
// ----------------------------------------------------------------------------
if ( function_exists( 'ssaa_fs' ) ) {
    ssaa_fs()->set_basename( false, __FILE__ );
} else {
    // ------------------------------------------------------------------------
    // Freemius SDK bootstrap. Product 31815. Stays inert until the SDK is
    // vendored at vendor/freemius/ (the file_exists guard below), so this is
    // safe to commit before the SDK lands.
    //
    // The public key and wp_org_gatekeeper are safe to commit (the gatekeeper
    // is stripped from the free build). Never put the secret key (sk_...) in
    // plugin files. For local testing, add to wp-config.php:
    //
    //   define( 'WP_FS__DEV_MODE', true );
    //   define( 'WP_FS__SKIP_EMAIL_ACTIVATION', true );
    // ------------------------------------------------------------------------
    if ( !function_exists( 'ssaa_fs' ) && file_exists( dirname( __FILE__ ) . '/vendor/freemius/start.php' ) ) {
        function ssaa_fs() {
            global $ssaa_fs;
            if ( !isset( $ssaa_fs ) ) {
                require_once dirname( __FILE__ ) . '/vendor/freemius/start.php';
                $ssaa_fs = fs_dynamic_init( array(
                    'id'               => '31815',
                    'slug'             => 'search-social-appearance-audit',
                    'type'             => 'plugin',
                    'public_key'       => 'pk_fc17433aa693e7055ad1b19353190',
                    'is_premium'       => false,
                    'has_addons'       => false,
                    'has_paid_plans'   => true,
                    'is_org_compliant' => true,
                    'menu'             => array(
                        'slug'    => 'search-social-appearance-audit',
                        'contact' => false,
                        'support' => false,
                    ),
                    'is_live'          => true,
                ) );
            }
            return $ssaa_fs;
        }

        // Initialise Freemius.
        ssaa_fs();
        // Tell Freemius where the plugin icon lives. The plugin_icon filter is
        // the documented escape hatch around the SDK's path-derivation logic,
        // which otherwise globs in vendor/freemius/assets/img/ rather than the
        // plugin's own assets/img/. See _standards/docs/CONVENTIONS.md
        // "Freemius plugin icon".
        ssaa_fs()->add_filter( 'plugin_icon', function () {
            return __DIR__ . '/assets/img/search-social-appearance-audit.png';
        } );
        // Signal that the SDK was initialised - other code can hook here.
        do_action( 'ssaa_fs_loaded' );
    }
    // Plugin constants.
    define( 'SSAA_VERSION', '1.4.0' );
    define( 'SSAA_ENGINE_VERSION', '0.4.0' );
    // Bundled render-engine source version (vendored from _shared/shared-render-engine via sync.sh).
    define( 'SSAA_PLUGIN_FILE', __FILE__ );
    define( 'SSAA_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    define( 'SSAA_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
    define( 'SSAA_PLUGIN_SLUG', 'search-social-appearance-audit' );
    define( 'SSAA_OPTION_KEY', 'ssaa_settings' );
    // Requires - dependency order matters; SSAA_Plugin::init() boots each class.
    // Shared-logging component first (vendored from _shared/shared-logging via
    // its OWN sync.sh - never edit in place): the engine and the plugin both
    // log through SSAA_Logger, and engine boot maps SSAA's config into
    // SSAA_Log::boot(). Log file: uploads/search-social-appearance-audit/
    // search-social-appearance-audit.log (the cross-plugin slug standard since
    // 1.0.35; older installs' ssaa.log in the same dir is removed at uninstall).
    require_once SSAA_PLUGIN_DIR . 'includes/class-log.php';
    require_once SSAA_PLUGIN_DIR . 'includes/class-logger.php';
    require_once SSAA_PLUGIN_DIR . 'includes/class-log-ui.php';
    // Vendored render engine next (interface before its implementors). Synced from
    // _shared/shared-render-engine via sync.sh - do NOT edit includes/engine/* in
    // place; re-sync instead. The engine is booted with SSAA's handler + config in
    // SSAA_Scan::boot_engine(), called from SSAA_Plugin::init(). Since engine
    // 0.2.0 the shared-logging component above is a HARD engine dependency.
    require_once SSAA_PLUGIN_DIR . 'includes/engine/interface-engine-handler.php';
    require_once SSAA_PLUGIN_DIR . 'includes/engine/class-engine.php';
    require_once SSAA_PLUGIN_DIR . 'includes/engine/class-engine-renderer.php';
    require_once SSAA_PLUGIN_DIR . 'includes/engine/class-engine-discovery.php';
    require_once SSAA_PLUGIN_DIR . 'includes/engine/class-engine-exclusions.php';
    require_once SSAA_PLUGIN_DIR . 'includes/engine/class-engine-queue.php';
    require_once SSAA_PLUGIN_DIR . 'includes/class-license.php';
    require_once SSAA_PLUGIN_DIR . 'includes/class-settings.php';
    require_once SSAA_PLUGIN_DIR . 'includes/class-ignores.php';
    // before results (results consults it)
    require_once SSAA_PLUGIN_DIR . 'includes/class-results.php';
    // after ignores
    require_once SSAA_PLUGIN_DIR . 'includes/class-analyzer.php';
    require_once SSAA_PLUGIN_DIR . 'includes/class-site-notices.php';
    // VENDORED shared sitewide-findings banner (re-sync via _shared/shared-site-notices)
    require_once SSAA_PLUGIN_DIR . 'includes/class-ai-access.php';
    // AI-crawler token table + robots.txt matrix (free; feeds the Site row)
    require_once SSAA_PLUGIN_DIR . 'includes/class-site-checks.php';
    // favicon audit (free; SSAA owns favicon_missing cross-plugin since 2026-07-24)
    require_once SSAA_PLUGIN_DIR . 'includes/class-discovery.php';
    // posts + synthesized archives + the Site row (before scan - discover() consults it)
    require_once SSAA_PLUGIN_DIR . 'includes/class-scan.php';
    // engine handler - implements SSAA_Engine_Handler (rendering/queue/discovery/exclusions/logging now in includes/engine/)
    require_once SSAA_PLUGIN_DIR . 'includes/class-plugin.php';
    // Files with the __premium_only suffix are stripped from the WP.org free
    // build by the Freemius deployment tool. file_exists() guards ensure
    // clean degradation when the files are absent. Each file self-registers
    // on plugins_loaded (11).
    // class-schedule / class-report / class-schedule-report-ui are VENDORED from
    // _shared/shared-schedule-reports (sync.sh - do not edit in place; re-sync).
    // class-report-content is SSAA's adapter (gate, scan trigger, report content).
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-schedule__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-schedule__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-report__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-report__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-schedule-report-ui__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-schedule-report-ui__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-report-content__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-report-content__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-changes__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-changes__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-updater-url__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-updater-url__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-author-flag__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-author-flag__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-content-types__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-content-types__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-drafts__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-drafts__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-filters-export__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-filters-export__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-enhanced__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-enhanced__premium_only.php';
    }
    // Shared rule-based exclusion component (vendored from _shared/shared-exclusion-rules
    // via sync.sh). It is plugin-agnostic and reads its two plugin-specific behaviours
    // through these filters (see that package's docs/SPEC.md): the premium gate and the
    // descriptor source for URL-rule match counts. Wired here (file present = premium build).
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-ai-readiness__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-ai-readiness__premium_only.php';
    }
    if ( file_exists( SSAA_PLUGIN_DIR . 'includes/class-exclusion-rules__premium_only.php' ) ) {
        require_once SSAA_PLUGIN_DIR . 'includes/class-exclusion-rules__premium_only.php';
        add_filter( 'ssaa_exclusion_rules_active', array('SSAA_License', 'is_premium') );
        add_filter( 'ssaa_exclusion_descriptors', array('SSAA_Engine_Discovery', 'post_descriptors') );
    }
    if ( is_admin() ) {
        require_once SSAA_PLUGIN_DIR . 'admin/class-admin.php';
        require_once SSAA_PLUGIN_DIR . 'admin/class-results-table.php';
        if ( file_exists( SSAA_PLUGIN_DIR . 'admin/class-admin__premium_only.php' ) ) {
            require_once SSAA_PLUGIN_DIR . 'admin/class-admin__premium_only.php';
        }
    }
    // Activation / deactivation hooks.
    register_activation_hook( __FILE__, array('SSAA_Plugin', 'activate') );
    register_deactivation_hook( __FILE__, array('SSAA_Plugin', 'deactivate') );
    // Boot.
    add_action( 'plugins_loaded', array('SSAA_Plugin', 'init') );
    // Plugins-list action links (left, high-prominence): Settings then Docs.
    // array_unshift in reverse so Settings ends up first, then Docs, ahead of
    // Freemius's own links. Cross-plugin standard - mirrors DOIG.
    add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), function ( $links ) {
        $docs = '<a href="' . esc_url( SSAA_Plugin::docs_url( '', 'plugin_action_link' ) ) . '" target="_blank" rel="noopener">' . esc_html__( 'Docs', 'search-social-appearance-audit' ) . '</a>';
        $settings = '<a href="' . esc_url( admin_url( 'admin.php?page=ssaa-settings' ) ) . '">' . esc_html__( 'Settings', 'search-social-appearance-audit' ) . '</a>';
        array_unshift( $links, $docs );
        array_unshift( $links, $settings );
        return $links;
    } );
    // Plugins-list meta row (right, lower-prominence): Documentation, the
    // WP-native location for reference material. Cross-plugin standard.
    add_filter(
        'plugin_row_meta',
        function ( $links, $file ) {
            if ( plugin_basename( __FILE__ ) !== $file ) {
                return $links;
            }
            $links[] = '<a href="' . esc_url( SSAA_Plugin::docs_url( '', 'plugin_row_meta' ) ) . '" target="_blank" rel="noopener">' . esc_html__( 'Documentation', 'search-social-appearance-audit' ) . '</a>';
            return $links;
        },
        10,
        2
    );
    // Freemius uninstall hook - replaces uninstall.php (Freemius rejects zips
    // containing a standalone uninstall.php). Inert until the SDK is vendored.
    if ( function_exists( 'ssaa_fs' ) && !function_exists( 'ssaa_fs_uninstall_cleanup' ) ) {
        ssaa_fs()->add_action( 'after_uninstall', 'ssaa_fs_uninstall_cleanup' );
        function ssaa_fs_uninstall_cleanup() {
            global $wpdb;
            delete_option( 'ssaa_settings' );
            delete_option( 'ssaa_db_version' );
            delete_option( 'ssaa_summary' );
            delete_option( 'ssaa_scan_queue' );
            delete_option( 'ssaa_excluded_ids' );
            delete_option( 'ssaa_ignored_issues' );
            delete_option( 'ssaa_last_report_summary' );
            delete_option( 'ssaa_changes' );
            delete_option( 'ssaa_changes_baseline' );
            delete_transient( 'ssaa_queue_lock' );
            // Clear scheduled cron events (uninstall cleanup may reference
            // names from stripped files - the standards' allowed exception).
            wp_clear_scheduled_hook( 'ssaa_process_queue' );
            wp_clear_scheduled_hook( 'ssaa_scheduled_scan' );
            wp_clear_scheduled_hook( 'ssaa_recovery_scan' );
            // Drop the results table.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- uninstall-time drop of the plugin's own table; prefix is not user input.
            $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}ssaa_results" );
            // Remove the log directory (recursive WP_Filesystem delete - see
            // _standards/docs/CONVENTIONS.md "Filesystem operations").
            $upload_dir = wp_upload_dir();
            $log_dir = trailingslashit( $upload_dir['basedir'] ) . 'search-social-appearance-audit/';
            if ( is_dir( $log_dir ) ) {
                if ( !function_exists( 'WP_Filesystem' ) ) {
                    require_once ABSPATH . 'wp-admin/includes/file.php';
                }
                WP_Filesystem();
                global $wp_filesystem;
                if ( $wp_filesystem ) {
                    $wp_filesystem->delete( $log_dir, true, 'd' );
                }
            }
        }

    }
}
// end of else (first-load branch - full bootstrap)