PluginProbe
Extendify / trunk
Extendify vtrunk
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
← All changes | bootstrap.php +270 -25 0.10.1 → trunk View file →
@@ -1,21 +1,47 @@
1 1 <?php
2 +
2 3 /**
3 4 * Bootstrap the application
4 5 */
5 6
7 +defined('ABSPATH') || die('No direct access.');
8 +
9 +use Extendify\AdminPageRouter;
10 +use Extendify\Assist\Admin as AssistAdmin;
11 +use Extendify\Agent\Admin as AgentAdmin;
12 +use Extendify\ComingSoon\Frontend as ComingSoonFrontend;
6 13 use Extendify\Config;
14 +use Extendify\Draft\Admin as DraftAdmin;
15 +use Extendify\HelpCenter\Admin as HelpCenterAdmin;
7 16 use Extendify\Insights;
8 -use Extendify\Onboarding\Admin as OnboardingAdmin;
17 +use Extendify\Launch\Admin as LaunchAdmin;
18 +use Extendify\AutoLaunch\Admin as AutoLaunchAdmin;
9 19 use Extendify\Library\Admin as LibraryAdmin;
10 -use Extendify\Library\Shared;
11 -use Extendify\Library\Welcome;
12 -use Extendify\Library\Frontend;
13 -use Extendify\Assist\AdminPage as AssistAdminPage;
14 -use Extendify\Assist\Admin as AssistAdmin;
20 +use Extendify\Library\Frontend as LibraryFrontend;
21 +use Extendify\Agent\Frontend as AgentFrontend;
22 +use Extendify\QuickEdit\Frontend as QuickEditFrontend;
23 +use Extendify\PageCreator\Admin as PageCreatorAdmin;
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;
29 +use Extendify\Recommendations\Admin as RecommendationsAdmin;
30 +use Extendify\PluginNotifications\Admin as PluginNotificationsAdmin;
31 +use Extendify\Shared\Admin as SharedAdmin;
32 +use Extendify\Shared\DataProvider\NotificationData;
33 +use Extendify\Shared\DataProvider\ResourceData;
34 +use Extendify\Shared\Services\BlockStyleVariations;
35 +use Extendify\Shared\Services\ForcePluginReinstall;
36 +use Extendify\Shared\Services\Import\ImagesImporter;
37 +use Extendify\Shared\Services\PluginRedirectDisabler;
38 +use Extendify\Shared\Services\PluginsActivation\SimplyBook;
39 +use Extendify\Shared\Services\VersionMigrator;
40 +use Extendify\SiteVisibility;
15 41
16 -if (!defined('ABSPATH')) {
17 - die('No direct access.');
42 +if (!defined('EXTENDIFY_REQUIRED_CAPABILITY')) {
43 + define('EXTENDIFY_REQUIRED_CAPABILITY', 'manage_options');
18 44 }
19 45
20 46 if (!defined('EXTENDIFY_PATH')) {
21 47 define('EXTENDIFY_PATH', \plugin_dir_path(__FILE__));
@@ -24,32 +50,251 @@
24 50 if (!defined('EXTENDIFY_URL')) {
25 51 define('EXTENDIFY_URL', \plugin_dir_url(__FILE__));
26 52 }
27 53
28 -if (!defined('EXTENDIFY_PLUGIN_BASENAME')) {
29 - define('EXTENDIFY_PLUGIN_BASENAME', \plugin_basename(__DIR__ . '/extendify.php'));
54 +if (is_readable(EXTENDIFY_PATH . 'vendor/autoload.php')) {
55 + require EXTENDIFY_PATH . 'vendor/autoload.php';
30 56 }
31 57
32 -if (is_readable(EXTENDIFY_PATH . 'vendor/autoload.php')) {
33 - require EXTENDIFY_PATH . 'vendor/autoload.php';
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 +
95 +if (!defined('EXTENDIFY_IS_THEME_EXTENDABLE')) {
96 + define('EXTENDIFY_IS_THEME_EXTENDABLE', get_option('stylesheet') === 'extendable');
34 97 }
35 98
36 -new Config();
37 -new Insights();
38 -new OnboardingAdmin();
39 -new LibraryAdmin();
40 -new Frontend();
41 -new Shared();
42 -new Welcome();
43 -new AssistAdminPage();
44 -new AssistAdmin();
99 +(static function () {
100 + // This file should have no dependencies and always load.
101 + new LibraryFrontend();
102 + // This file hooks into an external task and should always load.
103 + new Insights();
104 + // This class set up the image import check scheduler.
105 + new ImagesImporter();
45 106
46 -require EXTENDIFY_PATH . 'routes/api.php';
47 -require EXTENDIFY_PATH . 'editorplus/EditorPlus.php';
107 + // Run various database updates depending on the plugin version.
108 + new VersionMigrator();
48 109
49 -\add_action('plugins_loaded', function () {
50 - \load_plugin_textdomain('extendify');
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 +
119 + // This class will fetch and cache partner data to be used
120 + // throughout every class below. If opt in.
121 + new PartnerData();
122 +
123 + // Assign A/B test variants now that partner data is loaded.
124 + Insights::setup((array) PartnerData::setting('activeTests'));
125 +
126 + // Set up scheduled cache (if opt-in and active).
127 + if (!PartnerData::setting('deactivated')) {
128 + ResourceData::scheduleCache();
129 + NotificationData::scheduleCache();
130 + }
131 +
132 + if (!current_user_can(EXTENDIFY_REQUIRED_CAPABILITY)) {
133 + if (!SiteVisibility::isPublished()) {
134 + new ComingSoonFrontend();
135 + }
136 +
137 + return;
138 + }
139 +
140 + // The config class will collect information about the
141 + // partner and plugin, so it's easier to access.
142 + new Config();
143 + if (!defined('EXTENDIFY_DEVMODE')) {
144 + define('EXTENDIFY_DEVMODE', Config::$environment === 'DEVELOPMENT');
145 + }
146 +
147 + // This is a global "loader" class that loads in any assets that are shared everywhere.
148 + new SharedAdmin();
149 + // This class will handle loading library assets.
150 + new LibraryAdmin();
151 + if (PartnerData::setting('hidePluginNotifications')) {
152 + new PluginNotificationsAdmin();
153 + }
154 +
155 + // Only load these if the partner ID is set. These are all opt-in features.
156 + if (!Config::$partnerId && !constant('EXTENDIFY_DEVMODE')) {
157 + return;
158 + }
159 +
160 + if (PartnerData::setting('deactivated')) {
161 + return;
162 + }
163 +
164 + // This class handles the admin pages required for the plugin.
165 + new AdminPageRouter();
166 + new PluginRedirectDisabler();
167 +
168 + // This class will handle loading page creator assets.
169 + if (PartnerData::setting('showAIPageCreation') || constant('EXTENDIFY_DEVMODE')) {
170 + new PageCreatorAdmin();
171 + }
172 +
173 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
174 + $page = sanitize_text_field(wp_unslash($_GET['page'] ?? ''));
175 +
176 + if ($page === 'extendify-launch') {
177 + new LaunchAdmin();
178 + return;
179 + }
180 +
181 + if ($page === 'extendify-auto-launch') {
182 + new AutoLaunchAdmin();
183 + return;
184 + }
185 +
186 + // The remaining classes handle loading assets for each individual products.
187 + // They are essentially asset loading classes.
188 + if ($page === 'extendify-assist') {
189 + new AssistAdmin();
190 + }
191 +
192 + $extendifyShowAgent = constant('EXTENDIFY_IS_THEME_EXTENDABLE')
193 + && Config::$launchCompleted
194 + && (PartnerData::setting('showAIAgents') || Config::preview('ai-agent'));
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 +
202 + if (!$extendifyShowAgent) {
203 + new HelpCenterAdmin();
204 + }
205 +
206 + if (PartnerData::setting('showProductRecommendations') || constant('EXTENDIFY_DEVMODE')) {
207 + new RecommendationsAdmin();
208 + }
209 +
210 + new NotificationsAdmin();
211 + new NotificationsFrontend();
212 +
213 + if (PartnerData::setting('showDraft') || constant('EXTENDIFY_DEVMODE')) {
214 + new DraftAdmin();
215 + }
216 +
217 + if ($extendifyLoadAgent) {
218 + new AgentAdmin();
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();
237 + }
238 +})();
239 +
240 +(static function () {
241 + if (!current_user_can(EXTENDIFY_REQUIRED_CAPABILITY)) {
242 + return;
243 + }
244 +
245 + // This loads in all the REST API routes used by the plugin.
246 + require EXTENDIFY_PATH . 'routes/api.php';
247 +})();
248 +
249 +// This file is used to update the plugin and removed before w.org release.
250 +if (is_readable(EXTENDIFY_PATH . '/updater.php')) {
251 + require EXTENDIFY_PATH . 'updater.php';
252 +}
253 +
254 +add_action('init', function () {
255 + load_plugin_textdomain('extendify-local', false, dirname(plugin_basename(__FILE__)) . '/languages/php');
51 256 });
257 +
258 +// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
259 +add_filter('load_script_translation_file', function ($file, $handle, $domain) {
260 + if ($domain !== 'extendify-local') {
261 + return $file;
262 + }
263 +
264 + return extendifyResolveFallbackLocaleFile($file);
265 +}, 10, 3);
266 +
267 +add_filter('load_textdomain_mofile', function ($mofile, $domain) {
268 + if ($domain !== 'extendify-local') {
269 + return $mofile;
270 + }
271 +
272 + return extendifyResolveFallbackLocaleFile($mofile);
273 +}, 10, 2);
274 +
275 +/**
276 + * Resolves a fallback translation file path if the requested locale is unsupported.
277 + *
278 + * This function checks if the current file path includes an unsupported locale
279 + * and replaces it with a supported fallback (e.g. es_AR → es_ES),
280 + * as long as the fallback file exists on disk.
281 + *
282 + * @param string $filepath The original .mo or .json translation file path.
283 + * @return string The fallback file path if it exists, or the original one.
284 + */
285 +
286 +function extendifyResolveFallbackLocaleFile($filepath)
287 +{
288 + if (str_contains($filepath, '-es_') && !file_exists($filepath)) {
289 + $fallbackFile = preg_replace('/-es_[A-Z]{2}/', '-es_ES', $filepath);
290 + if ($fallbackFile && file_exists($fallbackFile)) {
291 + return $fallbackFile;
292 + }
293 + }
294 +
295 + return $filepath;
296 +}
52 297
53 298 // To cover legacy conflicts.
54 299 // phpcs:ignore
55 300 class ExtendifySdk