| @@ -8,8 +8,9 @@ | ||
| 8 | 8 | |
| 9 | 9 | use Extendify\AdminPageRouter; |
| 10 | 10 | use Extendify\Assist\Admin as AssistAdmin; |
| 11 | 11 | use Extendify\Agent\Admin as AgentAdmin; |
| 12 | +use Extendify\ComingSoon\Frontend as ComingSoonFrontend; | |
| 12 | 13 | use Extendify\Config; |
| 13 | 14 | use Extendify\Draft\Admin as DraftAdmin; |
| 14 | 15 | use Extendify\HelpCenter\Admin as HelpCenterAdmin; |
| 15 | 16 | use Extendify\Insights; |
| @@ -17,17 +18,27 @@ | ||
| 17 | 18 | use Extendify\AutoLaunch\Admin as AutoLaunchAdmin; |
| 18 | 19 | use Extendify\Library\Admin as LibraryAdmin; |
| 19 | 20 | use Extendify\Library\Frontend as LibraryFrontend; |
| 20 | 21 | use Extendify\Agent\Frontend as AgentFrontend; |
| 22 | +use Extendify\QuickEdit\Frontend as QuickEditFrontend; | |
| 21 | 23 | use Extendify\PageCreator\Admin as PageCreatorAdmin; |
| 22 | 24 | use Extendify\PartnerData; |
| 25 | +use Extendify\Notifications\Admin as NotificationsAdmin; | |
| 26 | +use Extendify\Notifications\Frontend as NotificationsFrontend; | |
| 27 | +use Extendify\Toolbar\Admin as ToolbarAdmin; | |
| 28 | +use Extendify\Toolbar\Frontend as ToolbarFrontend; | |
| 23 | 29 | use Extendify\Recommendations\Admin as RecommendationsAdmin; |
| 24 | 30 | use Extendify\PluginNotifications\Admin as PluginNotificationsAdmin; |
| 25 | 31 | use Extendify\Shared\Admin as SharedAdmin; |
| 32 | +use Extendify\Shared\DataProvider\NotificationData; | |
| 26 | 33 | use Extendify\Shared\DataProvider\ResourceData; |
| 34 | +use Extendify\Shared\Services\BlockStyleVariations; | |
| 35 | +use Extendify\Shared\Services\ForcePluginReinstall; | |
| 27 | 36 | use Extendify\Shared\Services\Import\ImagesImporter; |
| 28 | 37 | use Extendify\Shared\Services\PluginRedirectDisabler; |
| 38 | +use Extendify\Shared\Services\PluginsActivation\SimplyBook; | |
| 29 | 39 | use Extendify\Shared\Services\VersionMigrator; |
| 40 | +use Extendify\SiteVisibility; | |
| 30 | 41 | |
| 31 | 42 | if (!defined('EXTENDIFY_REQUIRED_CAPABILITY')) { |
| 32 | 43 | define('EXTENDIFY_REQUIRED_CAPABILITY', 'manage_options'); |
| 33 | 44 | } |
| @@ -39,16 +50,49 @@ | ||
| 39 | 50 | if (!defined('EXTENDIFY_URL')) { |
| 40 | 51 | define('EXTENDIFY_URL', \plugin_dir_url(__FILE__)); |
| 41 | 52 | } |
| 42 | 53 | |
| 43 | -if (!defined('EXTENDIFY_PLUGIN_BASENAME')) { | |
| 44 | - define('EXTENDIFY_PLUGIN_BASENAME', \plugin_basename(__DIR__ . '/extendify.php')); | |
| 45 | -} | |
| 46 | - | |
| 47 | 54 | if (is_readable(EXTENDIFY_PATH . 'vendor/autoload.php')) { |
| 48 | 55 | require EXTENDIFY_PATH . 'vendor/autoload.php'; |
| 49 | 56 | } |
| 50 | 57 | |
| 58 | +// Registered after the autoloader — these callbacks reference classes it loads. | |
| 59 | +add_filter('http_request_args', function ($args, $url) { | |
| 60 | + $extendifyHosts = array_filter(array_map(function ($host) { | |
| 61 | + return wp_parse_url($host, PHP_URL_HOST); | |
| 62 | + }, \Extendify\Constants::serviceUrls())); | |
| 63 | + | |
| 64 | + $host = wp_parse_url($url, PHP_URL_HOST); | |
| 65 | + if ($host && (str_contains($host, 'extendify') || in_array($host, $extendifyHosts, true))) { | |
| 66 | + $args['timeout'] = 45; | |
| 67 | + } | |
| 68 | + | |
| 69 | + return $args; | |
| 70 | +}, 100, 2); | |
| 71 | + | |
| 72 | +add_action('update_option', function ($option) { | |
| 73 | + if (in_array($option, ['WPLANG', 'blogname'], true)) { | |
| 74 | + \delete_transient('extendify_recommendations'); | |
| 75 | + \delete_transient('extendify_domains'); | |
| 76 | + \delete_transient('extendify_supportArticles'); | |
| 77 | + } | |
| 78 | + | |
| 79 | + // Delete the partner transient so we can fetch new data when the locale is switched. | |
| 80 | + if (($option === 'WPLANG') && get_transient('extendify_partner_data_cache_check')) { | |
| 81 | + delete_transient('extendify_partner_data_cache_check'); | |
| 82 | + PartnerData::getPartnerData(); | |
| 83 | + } | |
| 84 | +}); | |
| 85 | + | |
| 86 | +// Delete the partner transient so we can fetch new data when the locale is switched via WP-CLI. | |
| 87 | +add_action('cli_init', function () { | |
| 88 | + $command = sanitize_text_field(wp_unslash(($_SERVER['argv'][1] ?? ''))); | |
| 89 | + if ($command === 'language' && get_transient('extendify_partner_data_cache_check')) { | |
| 90 | + delete_transient('extendify_partner_data_cache_check'); | |
| 91 | + PartnerData::getPartnerData(); | |
| 92 | + } | |
| 93 | +}); | |
| 94 | + | |
| 51 | 95 | if (!defined('EXTENDIFY_IS_THEME_EXTENDABLE')) { |
| 52 | 96 | define('EXTENDIFY_IS_THEME_EXTENDABLE', get_option('stylesheet') === 'extendable'); |
| 53 | 97 | } |
| 54 | 98 | |
| @@ -62,18 +106,35 @@ | ||
| 62 | 106 | |
| 63 | 107 | // Run various database updates depending on the plugin version. |
| 64 | 108 | new VersionMigrator(); |
| 65 | 109 | |
| 110 | + // Force-reinstall support for /wp/v2/plugins (opt-in via request header). | |
| 111 | + ForcePluginReinstall::register(); | |
| 112 | + | |
| 113 | + // Keeps our design variation names registered so global styles can hold them. | |
| 114 | + BlockStyleVariations::register(); | |
| 115 | + | |
| 116 | + // Their registration callback comes in unauthenticated, so this cannot sit behind the capability gate. | |
| 117 | + SimplyBook::register(); | |
| 118 | + | |
| 66 | 119 | // This class will fetch and cache partner data to be used |
| 67 | 120 | // throughout every class below. If opt in. |
| 68 | 121 | new PartnerData(); |
| 69 | 122 | |
| 123 | + // Assign A/B test variants now that partner data is loaded. | |
| 124 | + Insights::setup((array) PartnerData::setting('activeTests')); | |
| 125 | + | |
| 70 | 126 | // Set up scheduled cache (if opt-in and active). |
| 71 | 127 | if (!PartnerData::setting('deactivated')) { |
| 72 | 128 | ResourceData::scheduleCache(); |
| 129 | + NotificationData::scheduleCache(); | |
| 73 | 130 | } |
| 74 | 131 | |
| 75 | 132 | if (!current_user_can(EXTENDIFY_REQUIRED_CAPABILITY)) { |
| 133 | + if (!SiteVisibility::isPublished()) { | |
| 134 | + new ComingSoonFrontend(); | |
| 135 | + } | |
| 136 | + | |
| 76 | 137 | return; |
| 77 | 138 | } |
| 78 | 139 | |
| 79 | 140 | // The config class will collect information about the |
| @@ -131,8 +192,14 @@ | ||
| 131 | 192 | $extendifyShowAgent = constant('EXTENDIFY_IS_THEME_EXTENDABLE') |
| 132 | 193 | && Config::$launchCompleted |
| 133 | 194 | && (PartnerData::setting('showAIAgents') || Config::preview('ai-agent')); |
| 134 | 195 | |
| 196 | + // True when the AI Agent is actually loaded this request — the gate | |
| 197 | + // above, or dev mode (so it can be exercised locally). Quick Edit and | |
| 198 | + // the simple toolbar both build on the Agent, so they share this | |
| 199 | + // decision rather than gating themselves independently. | |
| 200 | + $extendifyLoadAgent = $extendifyShowAgent || constant('EXTENDIFY_DEVMODE'); | |
| 201 | + | |
| 135 | 202 | if (!$extendifyShowAgent) { |
| 136 | 203 | new HelpCenterAdmin(); |
| 137 | 204 | } |
| 138 | 205 | |
| @@ -139,15 +206,35 @@ | ||
| 139 | 206 | if (PartnerData::setting('showProductRecommendations') || constant('EXTENDIFY_DEVMODE')) { |
| 140 | 207 | new RecommendationsAdmin(); |
| 141 | 208 | } |
| 142 | 209 | |
| 210 | + new NotificationsAdmin(); | |
| 211 | + new NotificationsFrontend(); | |
| 212 | + | |
| 143 | 213 | if (PartnerData::setting('showDraft') || constant('EXTENDIFY_DEVMODE')) { |
| 144 | 214 | new DraftAdmin(); |
| 145 | 215 | } |
| 146 | 216 | |
| 147 | - if ($extendifyShowAgent || constant('EXTENDIFY_DEVMODE')) { | |
| 217 | + if ($extendifyLoadAgent) { | |
| 148 | 218 | new AgentAdmin(); |
| 149 | 219 | new AgentFrontend(); |
| 220 | + } | |
| 221 | + | |
| 222 | + if ($extendifyLoadAgent) { | |
| 223 | + new QuickEditFrontend(); | |
| 224 | + } | |
| 225 | + | |
| 226 | + // Simple Extendify toolbar — replaces the WordPress core admin | |
| 227 | + // bar on the front end with a minimal AI Agent / Quick Edit / | |
| 228 | + // Edit / WP Admin bar. The user-profile "Toolbar Style" setting | |
| 229 | + // controls per-user override; the default is Launch-aware | |
| 230 | + // ('simple' post-Launch, 'full' pre-Launch). Gated on the Agent | |
| 231 | + // too: the toolbar's "AI Agent" button drives the Agent's mounted | |
| 232 | + // admin-bar button, so without the Agent it would present a dead | |
| 233 | + // button — never ship the toolbar unless the Agent is there. | |
| 234 | + if ($extendifyLoadAgent && (PartnerData::setting('showSimpleToolbar') || Config::preview('simple-toolbar'))) { | |
| 235 | + new ToolbarAdmin(); | |
| 236 | + new ToolbarFrontend(); | |
| 150 | 237 | } |
| 151 | 238 | })(); |
| 152 | 239 | |
| 153 | 240 | (static function () { |