plugin_name = 'affiliateboxes'; $this->version = defined( 'AFFILIATEBOXES_VERSION' ) ? AFFILIATEBOXES_VERSION : '1.0.0'; $this->load_dependencies(); $this->define_admin_hooks(); $this->define_public_hooks(); $this->register_post_types(); $this->init_action_scheduler(); } /** * Initialize Action Scheduler. */ private function init_action_scheduler() { if ( class_exists( 'AffiliateBoxes_Action_Scheduler' ) ) { $action_scheduler = new AffiliateBoxes_Action_Scheduler(); $action_scheduler->init(); } } /** * Load the required dependencies for the plugin. */ private function load_dependencies() { // The class responsible for admin-specific functionality. require_once AFFILIATEBOXES_PLUGIN_DIR . 'admin/class-affiliateboxes-admin.php'; // The class responsible for public-facing functionality. require_once AFFILIATEBOXES_PLUGIN_DIR . 'public/class-affiliateboxes-public.php'; // Initialize admin and public classes. $this->admin = new AffiliateBoxes_Admin( $this->get_plugin_name(), $this->get_version() ); $this->public = new AffiliateBoxes_Public( $this->get_version() ); } /** * Register all of the hooks related to the admin area functionality. */ private function define_admin_hooks() { // Post-activation onboarding notice on the plugins screen. add_action( 'admin_notices', array( $this->admin, 'render_activation_notice' ) ); add_action( 'admin_enqueue_scripts', array( $this->admin, 'enqueue_activation_notice_script' ) ); add_action( 'wp_ajax_affiliateboxes_dismiss_activation_notice', array( $this->admin, 'dismiss_activation_notice' ) ); // "Settings" link under the plugin name on the plugins screen. if ( defined( 'AFFILIATEBOXES_PLUGIN_BASENAME' ) ) { add_filter( 'plugin_action_links_' . AFFILIATEBOXES_PLUGIN_BASENAME, array( $this->admin, 'add_plugin_action_links' ) ); } // Add admin menu. add_action( 'admin_menu', array( $this->admin, 'add_plugin_admin_menu' ) ); // Enqueue admin scripts and styles. add_action( 'admin_enqueue_scripts', array( $this->admin, 'enqueue_styles' ) ); add_action( 'admin_enqueue_scripts', array( $this->admin, 'enqueue_scripts' ) ); add_action( 'admin_footer', array( $this->admin, 'render_icon_sprite' ) ); // AJAX handlers. add_action( 'wp_ajax_affiliateboxes_sync_products', array( $this->admin, 'sync_products' ) ); add_action( 'wp_ajax_affiliateboxes_get_sync_status', array( $this->admin, 'get_sync_status' ) ); add_action( 'wp_ajax_affiliateboxes_get_queue_status', array( $this->admin, 'get_queue_status' ) ); add_action( 'wp_ajax_affiliateboxes_disconnect_site', array( $this->admin, 'disconnect_site' ) ); add_action( 'wp_ajax_affiliateboxes_get_available_products', array( $this->admin, 'get_available_products' ) ); add_action( 'wp_ajax_affiliateboxes_start_connection', array( $this->admin, 'start_connection' ) ); } /** * Register all of the hooks related to the public-facing functionality. */ private function define_public_hooks() { // Enqueue block editor assets. add_action( 'enqueue_block_editor_assets', array( $this->admin, 'enqueue_block_editor_assets' ) ); // Styles for the iframed block canvas, which enqueue_block_editor_assets does not reach. add_action( 'enqueue_block_assets', array( $this->public, 'enqueue_block_canvas_assets' ) ); // Register shortcodes. add_shortcode( 'affiliateboxes_product', array( $this->public, 'render_affiliate_product' ) ); add_shortcode( 'affiliateboxes_table', array( $this->public, 'render_affiliate_product' ) ); add_shortcode( 'affiliateboxes', array( $this->public, 'render_affiliate_product' ) ); // Legacy alias. // Register Gutenberg block. add_action( 'init', array( $this->public, 'register_blocks' ) ); // Register the bundled front-end behaviour script and stylesheet handle for // structured payloads. add_action( 'wp_enqueue_scripts', array( 'AffiliateBoxes_Renderer', 'register_assets' ) ); add_action( 'enqueue_block_editor_assets', array( 'AffiliateBoxes_Renderer', 'register_assets' ) ); // Catch product stylesheets queued after wp_head's normal print pass (shortcodes and // blocks render during the_content, which runs later on most themes). add_action( 'wp_footer', array( 'AffiliateBoxes_Renderer', 'print_deferred_style' ), 20 ); // Register public webhook REST routes (connect + receive). add_action( 'rest_api_init', array( $this->public, 'register_webhook_routes' ) ); } /** * Register custom post types and taxonomies. */ private function register_post_types() { add_action( 'init', array( $this, 'register_affiliate_product_post_type' ) ); add_action( 'init', array( $this, 'register_affiliate_product_meta' ) ); } /** * Register meta fields for REST API access. */ public static function register_affiliate_product_meta() { register_post_meta( 'affiliate_product', '_affprod_slug', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); // _affprod_sri_hash is written by AffiliateBoxes_Utils::upsert_product_by_slug() // alongside the other payload fields, so it is registered with them: the // integrity hash should carry the same read-only schema and capability // check as the content it protects. foreach ( array( '_affprod_html', '_affprod_css', '_affprod_version', '_affprod_sri_hash' ) as $affiliateboxes_meta_key ) { register_post_meta( 'affiliate_product', $affiliateboxes_meta_key, array( 'show_in_rest' => array( 'schema' => array( 'type' => 'string', 'readonly' => true, ), ), 'single' => true, 'type' => 'string', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); } register_post_meta( 'affiliate_product', '_affprod_last_synced', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); register_post_meta( 'affiliate_product', '_affprod_identifier', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); register_post_meta( 'affiliate_product', '_affprod_type', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); } /** * Run the plugin logic. */ public function run() { // No loader needed, hooks are already registered in the constructor. } /** * Get the plugin name. * * @return string The plugin name. */ public function get_plugin_name() { return $this->plugin_name; } /** * Get the version of the plugin. * * @return string The version. */ public function get_version() { return $this->version; } /** * Activation hook. */ public static function activate() { // Register post type and flush rewrite rules. self::register_affiliate_product_post_type(); // Run migration from old post type/meta keys if needed. self::migrate_from_boxes(); // Drop payloads stored by versions that rendered a remote script. self::purge_retired_script_payloads(); // Set default options if they don't exist. if ( false === get_option( 'affiliateboxes_settings' ) ) { update_option( 'affiliateboxes_settings', array( 'api_key' => '', ) ); } /* * Flag the onboarding notice rather than redirecting. A redirect hijacks bulk * activation, has nowhere to go under WP-CLI, and races every other plugin that * tries the same trick. The window is a day so the notice is still waiting when a * site activated from the command line is next opened in a browser. */ set_transient( 'affiliateboxes_activation_notice', true, DAY_IN_SECONDS ); } /** * Remove the payloads written by versions before 1.1.0. * * Those versions stored the remote response wrapped in a