$pro ? 'pro' : 'free', 'features' => [ 'taxonomy' => true, 'search' => $pro, 'publishDate' => $pro, 'postSort' => $pro, 'loadMore' => $pro, 'freshResults' => $pro, 'layouts' => true, 'customFields' => $pro, 'number' => $pro, 'eventDates' => $pro, 'advancedQuery' => $pro, 'legacyV3' => $pro, ]]; } } // Register independently of the claimed runtime: activating the other edition // loads its bootstrap while this request still runs the previously active one. if (!function_exists('fqbp_register_edition_guard')) { function fqbp_edition_plugins() { return fqbp_known_plugins(); } function fqbp_free_activation_conflict($plugin, $network_wide) { if (!in_array($plugin, fqbp_known_plugins('free'), true)) return ''; $find = static function () use ($plugin) { foreach (fqbp_known_plugins() as $other) { if ($other !== $plugin && is_plugin_active($other)) { return in_array($other, fqbp_known_plugins('pro'), true) ? 'free-conflict' : 'free-duplicate'; } } return ''; }; $conflict = $find(); if (!$conflict && $network_wide && is_multisite()) { foreach (get_sites(['fields' => 'ids', 'number' => 0]) as $site_id) { switch_to_blog((int) $site_id); try { $conflict = $find(); } finally { restore_current_blog(); } if ($conflict) break; } } return $conflict; } function fqbp_guard_edition_activation($plugin, $network_wide) { // Free may refuse its own activation; commercial Pro owns its handoff. $conflict = fqbp_free_activation_conflict($plugin, $network_wide); if ($conflict) fqbp_block_edition_activation($conflict); } function fqbp_edition_notice_message($code) { switch ($code) { case 'free-conflict': return __('The Free edition was not activated because Filter Query Block Pro is already active. To use Free, deactivate Pro first. Your filters and settings have been preserved.', 'accomplice-query-loop-filters'); case 'free-duplicate': return __('The Free edition was not activated because another Free installation is active. Deactivate that installation first. Your filters and settings have been preserved.', 'accomplice-query-loop-filters'); case 'pro-network-conflict': return __('Filter Query Block Pro was not activated because Free is active for the network. Activate Pro from Network Admin to replace it for all sites.', 'accomplice-query-loop-filters'); case 'pro-upgrade': return __('Filter Query Block Pro is active and the Free edition has been deactivated. Your filters and settings have been preserved.', 'accomplice-query-loop-filters'); case 'duplicate': return __('A duplicate Filter Query Block edition disabled itself because another edition is already running. Your filters and settings have been preserved.', 'accomplice-query-loop-filters'); } return ''; } function fqbp_set_edition_notice($code) { if (!get_current_user_id() || !fqbp_edition_notice_message($code)) return; set_transient('fqbp_edition_notice_' . get_current_user_id(), $code, 5 * MINUTE_IN_SECONDS); } function fqbp_block_edition_activation($code) { if (defined('WP_CLI') && WP_CLI) { \WP_CLI::error(fqbp_edition_notice_message($code)); } fqbp_set_edition_notice($code); // Return to the ordinary Plugins screen before core persists activation. // This also replaces core's provisional activation-error redirect. wp_safe_redirect(self_admin_url('plugins.php')); exit; } function fqbp_render_edition_notice() { global $pagenow; if ($pagenow !== 'plugins.php' || (!current_user_can('activate_plugins') && !current_user_can('manage_network_plugins'))) return; $key = 'fqbp_edition_notice_' . get_current_user_id(); $code = get_transient($key); $message = fqbp_edition_notice_message($code); if ($message === '') return; delete_transient($key); wp_admin_notice(esc_html($message), ['type' => $code === 'pro-upgrade' ? 'success' : 'warning', 'dismissible' => true]); } function fqbp_register_edition_guard($plugin_file) { static $registered = []; $plugin = plugin_basename($plugin_file); if (!in_array($plugin, fqbp_edition_plugins(), true)) return; if (isset($registered[$plugin])) return; $registered[$plugin] = true; add_action('admin_init', static function () use ($plugin) { if (!defined('FQBPRO_PLUGIN_BASENAME') || FQBPRO_PLUGIN_BASENAME === $plugin || !is_plugin_active($plugin)) return; $network_wide = is_plugin_active_for_network($plugin); if (!current_user_can($network_wide ? 'manage_network_plugins' : 'activate_plugins')) return; // WordPress.org permits self-deactivation to prevent errors, never // deactivating another plugin. This closure owns its bootstrap only. // Skip cleanup callbacks because the surviving edition uses our data. deactivate_plugins($plugin, true, $network_wide); fqbp_set_edition_notice('duplicate'); }); } add_action('activate_plugin', 'fqbp_guard_edition_activation', 10, 2); add_action('admin_notices', 'fqbp_render_edition_notice'); add_action('network_admin_notices', 'fqbp_render_edition_notice'); }