<?php

/**
 * Plugin Name: PublisherKits SocialPromoter
 * Plugin URI:  https://publisherkits.com/socialpromoter
 * Description: Post and schedule social media promotions from WordPress Posts to X, LinkedIn, Facebook and Bluesky.
 * Version:     1.54.0
 * Author:      Black and White Digital
 * Author URI:  https://publisherkits.com
 * Copyright:   Copyright (c) 2026 Symposium Group Ltd
 * License:     GPL v2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: publisherkits-socialpromoter
 * Domain Path: /languages
 * Requires at least: 6.0
 * Requires PHP: 7.4
 *
 * Freemius strips the following premium-only files from the free WordPress.org
 * build (the promotion engine: campaigns, automation, AI copy, reporting,
 * author tagging). Their require statements are additionally wrapped in a
 * premium-only block that the build process removes, and every free-reachable reference to
 * these classes is class_exists()-guarded or lives inside such a block.
 *
 *
 * @package PublisherKits_SocialPromoter
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
if ( !defined( 'PKITS_SP_VERSION' ) ) {
    define( 'PKITS_SP_VERSION', '1.54.0' );
}
if ( !defined( 'PKITS_SP_FILE' ) ) {
    define( 'PKITS_SP_FILE', __FILE__ );
}
if ( !defined( 'PKITS_SP_DIR' ) ) {
    define( 'PKITS_SP_DIR', plugin_dir_path( __FILE__ ) );
}
if ( !defined( 'PKITS_SP_URL' ) ) {
    define( 'PKITS_SP_URL', plugin_dir_url( __FILE__ ) );
}
if ( !defined( 'PKITS_SP_BASENAME' ) ) {
    define( 'PKITS_SP_BASENAME', plugin_basename( __FILE__ ) );
}
/**
 * Freemius SDK bootstrap — licence activation and automatic updates.
 * Store 12984 (PublisherKits). Premium features ship only in the separate
 * Pro build; the free build contains no premium feature code.
 */
if ( function_exists( 'pkits_sp_fs' ) ) {
    pkits_sp_fs()->set_basename( false, __FILE__ );
} else {
    if ( !function_exists( 'pkits_sp_fs' ) ) {
        function pkits_sp_fs() {
            global $pkits_sp_fs;
            if ( !isset( $pkits_sp_fs ) ) {
                require_once PKITS_SP_DIR . 'vendor/freemius/start.php';
                $pkits_sp_fs = fs_dynamic_init( array(
                    'id'               => '33585',
                    'slug'             => 'publisherkits-socialpromoter',
                    'type'             => 'plugin',
                    'public_key'       => 'pk_1cea514450f6b22424773f4a39cf3',
                    'is_premium'       => false,
                    'premium_suffix'   => 'Pro',
                    'has_addons'       => false,
                    'has_paid_plans'   => true,
                    'is_org_compliant' => true,
                    'menu'             => array(
                        'slug'           => 'publisherkits-socialpromoter-settings',
                        'override_exact' => true,
                        'contact'        => false,
                        'support'        => false,
                        'parent'         => array(
                            'slug' => 'publisherkits-socialpromoter-accounts',
                        ),
                    ),
                    'is_live'          => true,
                ) );
            }
            return $pkits_sp_fs;
        }

        pkits_sp_fs();
        do_action( 'pkits_sp_fs_loaded' );
    }
    // Keep the Freemius opt-in / account screens inside the SocialPromoter menu.
    if ( !function_exists( 'pkits_sp_fs_settings_url' ) ) {
        function pkits_sp_fs_settings_url() {
            return admin_url( 'admin.php?page=publisherkits-socialpromoter-settings' );
        }

    }
    pkits_sp_fs()->add_filter( 'connect_url', 'pkits_sp_fs_settings_url' );
    pkits_sp_fs()->add_filter( 'after_skip_url', 'pkits_sp_fs_settings_url' );
    pkits_sp_fs()->add_filter( 'after_connect_url', 'pkits_sp_fs_settings_url' );
    pkits_sp_fs()->add_filter( 'after_pending_connect_url', 'pkits_sp_fs_settings_url' );
}
// Bundle the PublisherKits Core Library (site profile + topic framework +
// deterministic classifier). The pkcore\ folder is a verbatim vendored copy
// synced from the canonical publisherkits-core repo - never edit it here.
// The newest bundled core across all active PublisherKits plugins wins at
// runtime; this plugin activates both modules and the library ships in the
// free build (the deterministic engine is free-tier by design).
$pkcore_modules = array('profile', 'classify');
require_once PKITS_SP_DIR . 'pkcore/pkcore.php';
// Canonical shared (free) classes — must load before any class that uses the AI key.
require_once PKITS_SP_DIR . 'includes/class-sp-installer.php';
require_once PKITS_SP_DIR . 'includes/class-sp-crypto.php';
require_once PKITS_SP_DIR . 'includes/class-sp-accounts.php';
require_once PKITS_SP_DIR . 'includes/class-sp-connector-interface.php';
require_once PKITS_SP_DIR . 'includes/class-sp-platform-registry.php';
require_once PKITS_SP_DIR . 'includes/class-sp-connector-x.php';
require_once PKITS_SP_DIR . 'includes/class-sp-connector-facebook.php';
require_once PKITS_SP_DIR . 'includes/class-sp-connector-linkedin.php';
require_once PKITS_SP_DIR . 'includes/class-sp-connector-bluesky.php';
require_once PKITS_SP_DIR . 'includes/class-sp-site-profile.php';
require_once PKITS_SP_DIR . 'includes/class-sp-topics.php';
require_once PKITS_SP_DIR . 'includes/class-sp-queue.php';
require_once PKITS_SP_DIR . 'includes/class-sp-poster.php';
require_once PKITS_SP_DIR . 'includes/class-sp-metabox.php';
require_once PKITS_SP_DIR . 'includes/class-sp-admin.php';
require_once PKITS_SP_DIR . 'includes/class-sp-image-handler.php';
require_once PKITS_SP_DIR . 'includes/class-sp-nudge.php';
/*
 * Support Copilot (the Help button and its Support screen). Ships in BOTH builds
 * and is deliberately required HERE, at file scope, above the paid-edition block:
 * this file is not listed in the main file's paid-edition-only path directive, and
 * requiring it from inside that block would mean the free build required a file
 * that had been removed, fataling every free install. register() only requires the
 * module bundle and schedules the config; the config itself is queued on init.
 */
require_once PKITS_SP_DIR . 'includes/class-sp-support-copilot-boot.php';
PKITS_SP_Support_Copilot_Boot::register();
require_once PKITS_SP_DIR . 'includes/class-sp-core.php';
// Boot the bundled PK Core explicitly on activation: activation can fire
// without a fresh plugins_loaded for the activating plugin, so the
// plugins_loaded boot in pkcore.php may not have run yet. boot() is
// idempotent. Registered before the installer so the core is up first.
register_activation_hook( __FILE__, array('PKCORE_Loader', 'boot') );
register_activation_hook( __FILE__, array('PKITS_SP_Installer', 'run') );
register_deactivation_hook( __FILE__, array('PKITS_SP_Core', 'deactivate') );
add_action( 'plugins_loaded', array('PKITS_SP_Core', 'init') );
/**
 * One-time cleanup after the WordPress AI Client migration.
 *
 * Removes the now-unused bespoke AI key, provider and model from this plugin's
 * own settings so no stale encrypted secret lingers. Touches only this plugin's
 * option; the shared publisherkits_api_config (which other PublisherKits plugins
 * may own) is never modified here.
 *
 * @return void
 */
function pkits_sp_cleanup_bespoke_ai() {
    if ( get_option( 'pkits_sp_ai_connector_retired' ) ) {
        return;
    }
    $settings = get_option( 'pkits_sp_settings', array() );
    if ( is_array( $settings ) ) {
        unset($settings['ai_api_key'], $settings['ai_provider'], $settings['ai_model']);
        update_option( 'pkits_sp_settings', $settings, false );
    }
    update_option( 'pkits_sp_ai_connector_retired', 1, false );
}

add_action( 'init', 'pkits_sp_cleanup_bespoke_ai', 1 );
/**
 * Uninstall cleanup, run via the Freemius after_uninstall action.
 *
 * Freemius owns the uninstall flow (WP.org compliance requires no bespoke
 * uninstall.php alongside the SDK), so this replaces the former uninstall.php and
 * fires whether the plugin is deleted through wp-admin or the Freemius screens.
 *
 * Data retention: by default NOTHING is removed, so connected accounts, API keys,
 * the queue, campaigns and settings survive a delete/reinstall. Everything is only
 * dropped when the site owner ticked "Delete all SocialPromoter data when the
 * plugin is deleted" (Settings > Advanced). Ephemeral transients and the plugin's
 * cron events are always cleared since they regenerate on demand / would otherwise
 * fire into no handler once the code is gone.
 *
 * Uses literal option/table/hook names, not plugin class constants: during
 * uninstall the plugin classes may not be loaded, and (in the premium build) some
 * live in premium-only files.
 *
 * @return void
 */
function pkits_sp_uninstall_cleanup() {
    // Always clear ephemeral, regenerable transients.
    delete_transient( 'pkits_sp_admin_notice' );
    delete_transient( 'pksp_ai_models' );
    // Always unschedule the plugin's cron events (hook names hard-coded).
    wp_unschedule_hook( 'pkits_sp_fire_post' );
    wp_unschedule_hook( 'pkits_sp_automation_tick' );
    wp_unschedule_hook( 'pkits_sp_run_boost' );
    wp_unschedule_hook( 'pkits_sp_refresh_stats' );
    $pkits_sp_settings = get_option( 'pkits_sp_settings', array() );
    $pkits_sp_settings = ( is_array( $pkits_sp_settings ) ? $pkits_sp_settings : array() );
    // Respect the user's retention choice. Default OFF: preserve everything.
    if ( empty( $pkits_sp_settings['delete_data_on_uninstall'] ) ) {
        return;
    }
    global $wpdb;
    // Drop all plugin tables.
    $pkits_sp_tables = array(
        $wpdb->prefix . 'pkits_sp_queue',
        $wpdb->prefix . 'pkits_sp_campaigns',
        $wpdb->prefix . 'pkits_sp_post_stats',
        $wpdb->prefix . 'pkits_sp_campaign_posts'
    );
    foreach ( $pkits_sp_tables as $pkits_sp_table ) {
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name is a trusted prefix + literal; DROP cannot use a placeholder.
        $wpdb->query( "DROP TABLE IF EXISTS `{$pkits_sp_table}`" );
    }
    // Remove plugin options.
    $pkits_sp_options = array(
        'pkits_sp_settings',
        'pkits_sp_accounts',
        'pkits_sp_app_credentials',
        'pkits_sp_db_version',
        'pkits_sp_queue_nullable_fixed',
        'pkits_sp_reporting_config',
        'pkits_sp_automation',
        'pkits_sp_content_classes',
        'pksp_ai_pref',
        'pksp_ai_pref_custom',
        'pksp_ai_strict',
        'pkits_sp_ai_key_migration_v2',
        'pkits_sp_ai_key_migration_v3',
        'pkits_sp_assisted_destinations',
        'pkits_sp_assisted_dismissed'
    );
    foreach ( $pkits_sp_options as $pkits_sp_option ) {
        delete_option( $pkits_sp_option );
    }
    /*
     * The SHARED reporting config belongs to the whole PublisherKits suite and is
     * deliberately NOT deleted — PageSkin, EngagementSignals, Insight Engine and
     * Publisher Tools read it. Only this plugin's own slot is removed: since
     * 1.52.1 the service-account JSON stored there is encrypted with this
     * plugin's key, so leaving it behind would strand an unreadable credential in
     * the shared option once this plugin's crypto class is gone.
     */
    $pkits_sp_shared = get_option( 'publisherkits_reporting_config', array() );
    if ( is_array( $pkits_sp_shared ) && isset( $pkits_sp_shared['ga4_service_account_json'] ) ) {
        unset($pkits_sp_shared['ga4_service_account_json']);
        update_option( 'publisherkits_reporting_config', $pkits_sp_shared, false );
    }
    // Remove the plugin's post meta.
    $pkits_sp_post_meta = array(
        '_pkits_sp_boost',
        '_pkits_sp_boost_done',
        '_pkits_sp_no_auto',
        '_pkits_sp_auto_done',
        '_pkits_sp_promotion_status',
        '_pkits_sp_headline',
        '_pkits_sp_headline_ai',
        '_pkits_sp_content_class'
    );
    foreach ( $pkits_sp_post_meta as $pkits_sp_meta_key ) {
        delete_metadata(
            'post',
            0,
            $pkits_sp_meta_key,
            '',
            true
        );
    }
    // Remove the plugin's own user meta (author-tagging exclude flag only). Social
    // handles and hashtags are BioBuilder-compatible shared fields and are left
    // intact so other PublisherKits plugins keep working.
    delete_metadata(
        'user',
        0,
        '_pkits_sp_exclude_tagging',
        '',
        true
    );
    // Note: the shared publisherkits_api_config / publisherkits_site_context /
    // publisherkits_seo_keywords options are deliberately NOT removed - they are
    // shared across the PublisherKits suite and owned by no single plugin.
}

if ( function_exists( 'pkits_sp_fs' ) ) {
    pkits_sp_fs()->add_action( 'after_uninstall', 'pkits_sp_uninstall_cleanup' );
}