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 | app/PartnerData.php +88 -1 3.1.2 → trunk View file →
@@ -59,8 +59,9 @@
59 59 'showSecondaryDomainRecommendationAgent' => false,
60 60 'domainTLDs' => ['com', 'net'],
61 61 'priorityDomainTLDs' => [],
62 62 'stagingSites' => ['wordpress'],
63 + 'trialDomains' => [],
63 64 'domainSearchURL' => '',
64 65 'showDraft' => false,
65 66 'showChat' => false,
66 67 'showAIPageCreation' => false,
@@ -67,8 +68,9 @@
67 68 'enableImageImports-1-14-6' => false,
68 69 'disableLibraryAutoOpen' => false,
69 70 'enableApexDomain' => false,
70 71 'showLaunch' => false,
72 + 'showLaunchTitle' => false,
71 73 'deactivated' => true,
72 74 'launchRedirectWebsite' => false,
73 75 'showAILogo' => false,
74 76 'showProductRecommendations' => false,
@@ -93,10 +95,12 @@
93 95 'useAgentOnboarding' => false,
94 96 'hidePluginNotifications' => false,
95 97 'hideLaunchExitLink' => false,
96 98 'useAutoUpdate' => false,
99 + 'showLaunchUpdate' => false,
97 100 'activeTests' => [],
98 101 'showExtendifyCode' => false,
102 + 'useComingSoon' => false,
99 103 'extendifyCodeData' => [
100 104 'link' => '',
101 105 'title' => '',
102 106 'message' => '',
@@ -101,8 +105,10 @@
101 105 'title' => '',
102 106 'message' => '',
103 107 'cta-primary' => '',
104 108 ],
109 + 'customDesign' => null,
110 + 'strings' => [],
105 111 ];
106 112
107 113 // phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
108 114 /**
@@ -127,8 +133,9 @@
127 133 self::$config['domainTLDs'] = ($data['domainTLDs'] ?? self::$config['domainTLDs']);
128 134 self::$config['priorityDomainTLDs'] = ($data['priorityDomainTLDs']
129 135 ?? self::$config['priorityDomainTLDs']);
130 136 self::$config['stagingSites'] = array_map('trim', ($data['stagingSites'] ?? self::$config['stagingSites']));
137 + self::$config['trialDomains'] = array_map('trim', ($data['trialDomains'] ?? self::$config['trialDomains']));
131 138 self::$config['domainSearchURL'] = ($data['domainSearchURL'] ?? self::$config['domainSearchURL']);
132 139 self::$logo = isset($data['logo'][0]['thumbnails']['large']['url'])
133 140 ? $data['logo'][0]['thumbnails']['large']['url']
134 141 : self::$logo;
@@ -147,8 +154,9 @@
147 154 'secondaryColorText' => '#ffffff',
148 155 ];
149 156 self::$config['showAIPageCreation'] = ($data['showAIPageCreation'] ?? self::$config['showAIPageCreation']);
150 157 self::$config['showLaunch'] = ($data['showLaunch'] ?? self::$config['showLaunch']);
158 + self::$config['showLaunchTitle'] = ($data['showLaunchTitle'] ?? self::$config['showLaunchTitle']);
151 159 self::$config['deactivated'] = ($data['deactivated'] ?? self::$config['deactivated']);
152 160 self::$config['launchRedirectWebsite'] = ($data['launchRedirectWebsite']
153 161 ?? self::$config['launchRedirectWebsite']);
154 162 self::$config['showAILogo'] = ($data['showAILogo'] ?? self::$config['showAILogo']);
@@ -179,11 +187,15 @@
179 187 self::$config['hidePluginNotifications'] = ($data['hidePluginNotifications']
180 188 ?? self::$config['hidePluginNotifications']);
181 189 self::$config['hideLaunchExitLink'] = ($data['hideLaunchExitLink'] ?? self::$config['hideLaunchExitLink']);
182 190 self::$config['useAutoUpdate'] = ($data['useAutoUpdate'] ?? self::$config['useAutoUpdate']);
191 + self::$config['showLaunchUpdate'] = ($data['showLaunchUpdate'] ?? self::$config['showLaunchUpdate']);
183 192 self::$config['activeTests'] = ($data['activeTests'] ?? self::$config['activeTests']);
184 193 self::$config['showExtendifyCode'] = ($data['showExtendifyCode'] ?? self::$config['showExtendifyCode']);
194 + self::$config['useComingSoon'] = ($data['useComingSoon'] ?? self::$config['useComingSoon']);
185 195 self::$config['extendifyCodeData'] = ($data['extendifyCodeData'] ?? self::$config['extendifyCodeData']);
196 + self::$config['customDesign'] = ($data['customDesign'] ?? self::$config['customDesign']);
197 + self::$config['strings'] = ($data['strings'] ?? self::$config['strings']);
186 198
187 199 // Add the job hook to fetch the partner data.
188 200 \add_action('extendify_fetch_partner_data', [self::class, 'fetchPartnerData']);
189 201 }
@@ -267,9 +279,16 @@
267 279 }
268 280
269 281 $sanitizedData = array_merge(
270 282 Sanitizer::sanitizeUnknown($result['data']),
271 - ['consentTermsCustom' => \sanitize_text_field(htmlentities(($result['data']['consentTermsCustom'] ?? '')))]
283 + [
284 + 'consentTermsCustom' => \sanitize_text_field(htmlentities(
285 + ($result['data']['consentTermsCustom'] ?? ''),
286 + ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401
287 + )),
288 + 'customDesign' => self::sanitizeDesign($result['data']['customDesign'] ?? null),
289 + 'strings' => self::sanitizeStrings($result['data']['strings'] ?? null),
290 + ]
272 291 );
273 292
274 293 // Merge before persisting as this data is accessed directly elsewhere.
275 294 $mergedData = array_merge(self::$config, $sanitizedData);
@@ -275,8 +294,76 @@
275 294 $mergedData = array_merge(self::$config, $sanitizedData);
276 295 \update_option('extendify_partner_data_v2', $mergedData);
277 296
278 297 return $mergedData;
298 + }
299 +
300 + /**
301 + * Partner copy overriding the shipped strings.
302 + *
303 + * Which keys exist is the flow's to know, so only shape and text are checked here.
304 + *
305 + * @param mixed $strings The map as the partner-data response carried it.
306 + * @return array
307 + */
308 + public static function sanitizeStrings($strings)
309 + {
310 + return array_map(
311 + 'sanitize_text_field',
312 + self::designEntries($strings, '/^[a-zA-Z][a-zA-Z0-9]*$/', 'is_string')
313 + );
314 + }
315 +
316 + /**
317 + * A design carries GLSL, which the text sanitizers break, so only its shape is checked.
318 + *
319 + * Empty members are left out rather than kept: json_encode writes an empty
320 + * PHP array as [], and the page reads the design as an object.
321 + *
322 + * @param mixed $design The design as the partner-data response carried it.
323 + * @return array|null
324 + */
325 + private static function sanitizeDesign($design)
326 + {
327 + if (!is_array($design)) {
328 + return null;
329 + }
330 +
331 + $shader = ($design['shader'] ?? null);
332 + $logo = ($design['logo'] ?? null);
333 + $kept = array_filter([
334 + 'vars' => self::designEntries(
335 + ($design['vars'] ?? null),
336 + '/^--ext-(ui|tpl)-[a-z0-9-]+$/',
337 + function ($value) {
338 + // A CSS value is a string, but 0.88 is a natural way to write one.
339 + return is_string($value) || is_int($value) || is_float($value);
340 + }
341 + ),
342 + 'templates' => self::designEntries(($design['templates'] ?? null), '/^[A-Za-z0-9_-]+$/', 'is_string'),
343 + 'shader' => is_string($shader) ? \wp_check_invalid_utf8($shader) : '',
344 + 'logo' => is_string($logo) ? \esc_url_raw($logo) : '',
345 + ]);
346 +
347 + return $kept ?: null;
348 + }
349 +
350 + private static function designEntries($entries, $keyPattern, callable $accepts)
351 + {
352 + if (!is_array($entries)) {
353 + return [];
354 + }
355 +
356 + $kept = [];
357 + foreach ($entries as $key => $value) {
358 + if (!is_string($key) || !preg_match($keyPattern, $key) || !$accepts($value)) {
359 + continue;
360 + }
361 +
362 + $kept[$key] = is_string($value) ? \wp_check_invalid_utf8($value) : $value;
363 + }
364 +
365 + return $kept;
279 366 }
280 367
281 368 /**
282 369 * Return colors mapped as css variables