PluginProbe
Extendify / 3.1.5
Extendify v3.1.5
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 0.7.0 All 126 releases
extendify / bootstrap.php

bootstrap.php in Extendify 3.1.5, at bootstrap.php

293 lines 9.8 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\Config;
13 use Extendify\Draft\Admin as DraftAdmin;
14 use Extendify\HelpCenter\Admin as HelpCenterAdmin;
15 use Extendify\Insights;
16 use Extendify\Launch\Admin as LaunchAdmin;
17 use Extendify\AutoLaunch\Admin as AutoLaunchAdmin;
18 use Extendify\Library\Admin as LibraryAdmin;
19 use Extendify\Library\Frontend as LibraryFrontend;
20 use Extendify\Agent\Frontend as AgentFrontend;
21 use Extendify\QuickEdit\Frontend as QuickEditFrontend;
22 use Extendify\PageCreator\Admin as PageCreatorAdmin;
23 use Extendify\PartnerData;
24 use Extendify\Notifications\Admin as NotificationsAdmin;
25 use Extendify\Notifications\Frontend as NotificationsFrontend;
26 use Extendify\Toolbar\Admin as ToolbarAdmin;
27 use Extendify\Toolbar\Frontend as ToolbarFrontend;
28 use Extendify\Recommendations\Admin as RecommendationsAdmin;
29 use Extendify\PluginNotifications\Admin as PluginNotificationsAdmin;
30 use Extendify\Shared\Admin as SharedAdmin;
31 use Extendify\Shared\DataProvider\NotificationData;
32 use Extendify\Shared\DataProvider\ResourceData;
33 use Extendify\Shared\Services\ForcePluginReinstall;
34 use Extendify\Shared\Services\Import\ImagesImporter;
35 use Extendify\Shared\Services\PluginRedirectDisabler;
36 use Extendify\Shared\Services\PluginsActivation\SimplyBook;
37 use Extendify\Shared\Services\VersionMigrator;
38
39 if (!defined('EXTENDIFY_REQUIRED_CAPABILITY')) {
40 define('EXTENDIFY_REQUIRED_CAPABILITY', 'manage_options');
41 }
42
43 if (!defined('EXTENDIFY_PATH')) {
44 define('EXTENDIFY_PATH', \plugin_dir_path(__FILE__));
45 }
46
47 if (!defined('EXTENDIFY_URL')) {
48 define('EXTENDIFY_URL', \plugin_dir_url(__FILE__));
49 }
50
51 if (is_readable(EXTENDIFY_PATH . 'vendor/autoload.php')) {
52 require EXTENDIFY_PATH . 'vendor/autoload.php';
53 }
54
55 // Registered after the autoloader — these callbacks reference classes it loads.
56 add_filter('http_request_args', function ($args, $url) {
57 $extendifyHosts = array_filter(array_map(function ($host) {
58 return wp_parse_url($host, PHP_URL_HOST);
59 }, \Extendify\Constants::serviceUrls()));
60
61 $host = wp_parse_url($url, PHP_URL_HOST);
62 if ($host && (str_contains($host, 'extendify') || in_array($host, $extendifyHosts, true))) {
63 $args['timeout'] = 45;
64 }
65
66 return $args;
67 }, 100, 2);
68
69 add_action('update_option', function ($option) {
70 if (in_array($option, ['WPLANG', 'blogname'], true)) {
71 \delete_transient('extendify_recommendations');
72 \delete_transient('extendify_domains');
73 \delete_transient('extendify_supportArticles');
74 }
75
76 // Delete the partner transient so we can fetch new data when the locale is switched.
77 if (($option === 'WPLANG') && get_transient('extendify_partner_data_cache_check')) {
78 delete_transient('extendify_partner_data_cache_check');
79 PartnerData::getPartnerData();
80 }
81 });
82
83 // Delete the partner transient so we can fetch new data when the locale is switched via WP-CLI.
84 add_action('cli_init', function () {
85 $command = sanitize_text_field(wp_unslash(($_SERVER['argv'][1] ?? '')));
86 if ($command === 'language' && get_transient('extendify_partner_data_cache_check')) {
87 delete_transient('extendify_partner_data_cache_check');
88 PartnerData::getPartnerData();
89 }
90 });
91
92 if (!defined('EXTENDIFY_IS_THEME_EXTENDABLE')) {
93 define('EXTENDIFY_IS_THEME_EXTENDABLE', get_option('stylesheet') === 'extendable');
94 }
95
96 (static function () {
97 // This file should have no dependencies and always load.
98 new LibraryFrontend();
99 // This file hooks into an external task and should always load.
100 new Insights();
101 // This class set up the image import check scheduler.
102 new ImagesImporter();
103
104 // Run various database updates depending on the plugin version.
105 new VersionMigrator();
106
107 // Force-reinstall support for /wp/v2/plugins (opt-in via request header).
108 ForcePluginReinstall::register();
109
110 // Their registration callback comes in unauthenticated, so this cannot sit behind the capability gate.
111 SimplyBook::register();
112
113 // This class will fetch and cache partner data to be used
114 // throughout every class below. If opt in.
115 new PartnerData();
116
117 // Assign A/B test variants now that partner data is loaded.
118 Insights::setup((array) PartnerData::setting('activeTests'));
119
120 // Set up scheduled cache (if opt-in and active).
121 if (!PartnerData::setting('deactivated')) {
122 ResourceData::scheduleCache();
123 NotificationData::scheduleCache();
124 }
125
126 if (!current_user_can(EXTENDIFY_REQUIRED_CAPABILITY)) {
127 return;
128 }
129
130 // The config class will collect information about the
131 // partner and plugin, so it's easier to access.
132 new Config();
133 if (!defined('EXTENDIFY_DEVMODE')) {
134 define('EXTENDIFY_DEVMODE', Config::$environment === 'DEVELOPMENT');
135 }
136
137 // This is a global "loader" class that loads in any assets that are shared everywhere.
138 new SharedAdmin();
139 // This class will handle loading library assets.
140 new LibraryAdmin();
141 if (PartnerData::setting('hidePluginNotifications')) {
142 new PluginNotificationsAdmin();
143 }
144
145 // Only load these if the partner ID is set. These are all opt-in features.
146 if (!Config::$partnerId && !constant('EXTENDIFY_DEVMODE')) {
147 return;
148 }
149
150 if (PartnerData::setting('deactivated')) {
151 return;
152 }
153
154 // This class handles the admin pages required for the plugin.
155 new AdminPageRouter();
156 new PluginRedirectDisabler();
157
158 // This class will handle loading page creator assets.
159 if (PartnerData::setting('showAIPageCreation') || constant('EXTENDIFY_DEVMODE')) {
160 new PageCreatorAdmin();
161 }
162
163 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
164 $page = sanitize_text_field(wp_unslash($_GET['page'] ?? ''));
165
166 if ($page === 'extendify-launch') {
167 new LaunchAdmin();
168 return;
169 }
170
171 if ($page === 'extendify-auto-launch') {
172 new AutoLaunchAdmin();
173 return;
174 }
175
176 // The remaining classes handle loading assets for each individual products.
177 // They are essentially asset loading classes.
178 if ($page === 'extendify-assist') {
179 new AssistAdmin();
180 }
181
182 $extendifyShowAgent = constant('EXTENDIFY_IS_THEME_EXTENDABLE')
183 && Config::$launchCompleted
184 && (PartnerData::setting('showAIAgents') || Config::preview('ai-agent'));
185
186 // True when the AI Agent is actually loaded this request — the gate
187 // above, or dev mode (so it can be exercised locally). Quick Edit and
188 // the simple toolbar both build on the Agent, so they share this
189 // decision rather than gating themselves independently.
190 $extendifyLoadAgent = $extendifyShowAgent || constant('EXTENDIFY_DEVMODE');
191
192 if (!$extendifyShowAgent) {
193 new HelpCenterAdmin();
194 }
195
196 if (PartnerData::setting('showProductRecommendations') || constant('EXTENDIFY_DEVMODE')) {
197 new RecommendationsAdmin();
198 }
199
200 new NotificationsAdmin();
201 new NotificationsFrontend();
202
203 if (PartnerData::setting('showDraft') || constant('EXTENDIFY_DEVMODE')) {
204 new DraftAdmin();
205 }
206
207 if ($extendifyLoadAgent) {
208 new AgentAdmin();
209 new AgentFrontend();
210 }
211
212 if ($extendifyLoadAgent) {
213 new QuickEditFrontend();
214 }
215
216 // Simple Extendify toolbar — replaces the WordPress core admin
217 // bar on the front end with a minimal AI Agent / Quick Edit /
218 // Edit / WP Admin bar. The user-profile "Toolbar Style" setting
219 // controls per-user override; the default is Launch-aware
220 // ('simple' post-Launch, 'full' pre-Launch). Gated on the Agent
221 // too: the toolbar's "AI Agent" button drives the Agent's mounted
222 // admin-bar button, so without the Agent it would present a dead
223 // button — never ship the toolbar unless the Agent is there.
224 if ($extendifyLoadAgent && (PartnerData::setting('showSimpleToolbar') || Config::preview('simple-toolbar'))) {
225 new ToolbarAdmin();
226 new ToolbarFrontend();
227 }
228 })();
229
230 (static function () {
231 if (!current_user_can(EXTENDIFY_REQUIRED_CAPABILITY)) {
232 return;
233 }
234
235 // This loads in all the REST API routes used by the plugin.
236 require EXTENDIFY_PATH . 'routes/api.php';
237 })();
238
239 // This file is used to update the plugin and removed before w.org release.
240 if (is_readable(EXTENDIFY_PATH . '/updater.php')) {
241 require EXTENDIFY_PATH . 'updater.php';
242 }
243
244 add_action('init', function () {
245 load_plugin_textdomain('extendify-local', false, dirname(plugin_basename(__FILE__)) . '/languages/php');
246 });
247
248 // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
249 add_filter('load_script_translation_file', function ($file, $handle, $domain) {
250 if ($domain !== 'extendify-local') {
251 return $file;
252 }
253
254 return extendifyResolveFallbackLocaleFile($file);
255 }, 10, 3);
256
257 add_filter('load_textdomain_mofile', function ($mofile, $domain) {
258 if ($domain !== 'extendify-local') {
259 return $mofile;
260 }
261
262 return extendifyResolveFallbackLocaleFile($mofile);
263 }, 10, 2);
264
265 /**
266 * Resolves a fallback translation file path if the requested locale is unsupported.
267 *
268 * This function checks if the current file path includes an unsupported locale
269 * and replaces it with a supported fallback (e.g. es_AR → es_ES),
270 * as long as the fallback file exists on disk.
271 *
272 * @param string $filepath The original .mo or .json translation file path.
273 * @return string The fallback file path if it exists, or the original one.
274 */
275
276 function extendifyResolveFallbackLocaleFile($filepath)
277 {
278 if (str_contains($filepath, '-es_') && !file_exists($filepath)) {
279 $fallbackFile = preg_replace('/-es_[A-Z]{2}/', '-es_ES', $filepath);
280 if ($fallbackFile && file_exists($fallbackFile)) {
281 return $fallbackFile;
282 }
283 }
284
285 return $filepath;
286 }
287
288 // To cover legacy conflicts.
289 // phpcs:ignore
290 class ExtendifySdk
291 {
292 }
293