PluginProbe
Extendify / 3.1.3
Extendify v3.1.3
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.3, at bootstrap.php

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