PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
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
extendify / bootstrap.php

bootstrap.php in Extendify 3.2.1, at bootstrap.php

303 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Bootstrap the application
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;
13 use Extendify\Config;
14 use Extendify\Draft\Admin as DraftAdmin;
15 use Extendify\HelpCenter\Admin as HelpCenterAdmin;
16 use Extendify\Insights;
17 use Extendify\Launch\Admin as LaunchAdmin;
18 use Extendify\AutoLaunch\Admin as AutoLaunchAdmin;
19 use Extendify\Library\Admin as LibraryAdmin;
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;
41
42 if (!defined('EXTENDIFY_REQUIRED_CAPABILITY')) {
43 define('EXTENDIFY_REQUIRED_CAPABILITY', 'manage_options');
44 }
45
46 if (!defined('EXTENDIFY_PATH')) {
47 define('EXTENDIFY_PATH', \plugin_dir_path(__FILE__));
48 }
49
50 if (!defined('EXTENDIFY_URL')) {
51 define('EXTENDIFY_URL', \plugin_dir_url(__FILE__));
52 }
53
54 if (is_readable(EXTENDIFY_PATH . 'vendor/autoload.php')) {
55 require EXTENDIFY_PATH . 'vendor/autoload.php';
56 }
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
95 if (!defined('EXTENDIFY_IS_THEME_EXTENDABLE')) {
96 define('EXTENDIFY_IS_THEME_EXTENDABLE', get_option('stylesheet') === 'extendable');
97 }
98
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();
106
107 // Run various database updates depending on the plugin version.
108 new VersionMigrator();
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
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');
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 }
297
298 // To cover legacy conflicts.
299 // phpcs:ignore
300 class ExtendifySdk
301 {
302 }
303