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 +84 -4 3.1.5 → 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,
@@ -97,8 +98,9 @@
97 98 'useAutoUpdate' => false,
98 99 'showLaunchUpdate' => false,
99 100 'activeTests' => [],
100 101 'showExtendifyCode' => false,
102 + 'useComingSoon' => false,
101 103 'extendifyCodeData' => [
102 104 'link' => '',
103 105 'title' => '',
104 106 'message' => '',
@@ -103,8 +105,10 @@
103 105 'title' => '',
104 106 'message' => '',
105 107 'cta-primary' => '',
106 108 ],
109 + 'customDesign' => null,
110 + 'strings' => [],
107 111 ];
108 112
109 113 // phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
110 114 /**
@@ -129,8 +133,9 @@
129 133 self::$config['domainTLDs'] = ($data['domainTLDs'] ?? self::$config['domainTLDs']);
130 134 self::$config['priorityDomainTLDs'] = ($data['priorityDomainTLDs']
131 135 ?? self::$config['priorityDomainTLDs']);
132 136 self::$config['stagingSites'] = array_map('trim', ($data['stagingSites'] ?? self::$config['stagingSites']));
137 + self::$config['trialDomains'] = array_map('trim', ($data['trialDomains'] ?? self::$config['trialDomains']));
133 138 self::$config['domainSearchURL'] = ($data['domainSearchURL'] ?? self::$config['domainSearchURL']);
134 139 self::$logo = isset($data['logo'][0]['thumbnails']['large']['url'])
135 140 ? $data['logo'][0]['thumbnails']['large']['url']
136 141 : self::$logo;
@@ -185,9 +190,12 @@
185 190 self::$config['useAutoUpdate'] = ($data['useAutoUpdate'] ?? self::$config['useAutoUpdate']);
186 191 self::$config['showLaunchUpdate'] = ($data['showLaunchUpdate'] ?? self::$config['showLaunchUpdate']);
187 192 self::$config['activeTests'] = ($data['activeTests'] ?? self::$config['activeTests']);
188 193 self::$config['showExtendifyCode'] = ($data['showExtendifyCode'] ?? self::$config['showExtendifyCode']);
194 + self::$config['useComingSoon'] = ($data['useComingSoon'] ?? self::$config['useComingSoon']);
189 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']);
190 198
191 199 // Add the job hook to fetch the partner data.
192 200 \add_action('extendify_fetch_partner_data', [self::class, 'fetchPartnerData']);
193 201 }
@@ -271,12 +279,16 @@
271 279 }
272 280
273 281 $sanitizedData = array_merge(
274 282 Sanitizer::sanitizeUnknown($result['data']),
275 - ['consentTermsCustom' => \sanitize_text_field(htmlentities(
276 - ($result['data']['consentTermsCustom'] ?? ''),
277 - ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401
278 - ))]
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 + ]
279 291 );
280 292
281 293 // Merge before persisting as this data is accessed directly elsewhere.
282 294 $mergedData = array_merge(self::$config, $sanitizedData);
@@ -282,8 +294,76 @@
282 294 $mergedData = array_merge(self::$config, $sanitizedData);
283 295 \update_option('extendify_partner_data_v2', $mergedData);
284 296
285 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;
286 366 }
287 367
288 368 /**
289 369 * Return colors mapped as css variables