PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/models/FrmFormApi.php +50 -11 6.28 → trunk View file →
@@ -35,8 +35,18 @@
35 35 */
36 36 protected $force = false;
37 37
38 38 /**
39 + * The most recent decode of each cache key's payload.
40 + *
41 + * Each entry is array( 'raw' => string, 'decoded' => mixed ). The raw JSON is kept so a reuse
42 + * can be checked against what is stored right now, rather than assumed to still be current.
43 + *
44 + * @var array<string,array>
45 + */
46 + private static $decoded_cache = array();
47 +
48 + /**
39 49 * @since 3.06
40 50 *
41 51 * @param string|null $license The license key.
42 52 *
@@ -79,9 +89,9 @@
79 89 *
80 90 * @return void
81 91 */
82 92 protected function set_cache_key() {
83 - $this->cache_key = 'frm_addons_l' . ( empty( $this->license ) ? '' : md5( $this->license ) );
93 + $this->cache_key = 'frm_addons_l' . ( $this->license ? md5( $this->license ) : '' );
84 94 }
85 95
86 96 /**
87 97 * @since 3.06
@@ -111,9 +121,9 @@
111 121 */
112 122 public function get_api_info() {
113 123 $url = $this->api_url();
114 124
115 - if ( ! empty( $this->license ) ) {
125 + if ( $this->license ) {
116 126 $url .= '?l=' . urlencode( base64_encode( $this->license ) );
117 127 }
118 128
119 129 if ( $this->force ) {
@@ -234,9 +244,9 @@
234 244 *
235 245 * @return bool
236 246 */
237 247 protected function run_as_multisite() {
238 - return is_multisite() && empty( $this->license );
248 + return is_multisite() && ! $this->license;
239 249 }
240 250
241 251 /**
242 252 * @since 6.8.3
@@ -243,9 +253,9 @@
243 253 *
244 254 * @return string
245 255 */
246 256 protected function transient_key() {
247 - return strtolower( self::class ) . '_request_lock';
257 + return strtolower( static::class ) . '_request_lock';
248 258 }
249 259
250 260 /**
251 261 * @since 3.06
@@ -252,9 +262,9 @@
252 262 *
253 263 * @return string
254 264 */
255 265 protected function api_url() {
256 - if ( empty( $this->license ) ) {
266 + if ( ! $this->license ) {
257 267 // Direct traffic to Cloudflare worker when there is no license.
258 268 return 'https://plapi.formidableforms.com/list/';
259 269 }
260 270 return 'https://formidableforms.com/wp-json/s11edd/v1/updates/';
@@ -338,12 +348,44 @@
338 348 if ( $is_expired && ! $this->is_running() ) {
339 349 return false;
340 350 }
341 351
342 - return json_decode( $cache['value'], true );
352 + return $this->decode_cached( $cache['value'] );
343 353 }
344 354
345 355 /**
356 + * Decode a cached API payload, reusing the previous decode of an unchanged payload.
357 + *
358 + * The payload runs to tens of kilobytes of JSON, and decoding it costs far more than reading
359 + * the option it came from. That matters because a single form builder page decodes it once per
360 + * upsell it renders. The reuse is keyed on the raw JSON rather than on the cache key, so
361 + * anything that changes what is stored -- a new license, a cleared cache, a fresh API response,
362 + * a test replacing the option -- is picked up on the very next read instead of being masked.
363 + *
364 + * @since 6.35
365 + *
366 + * @param string $value The cached JSON.
367 + *
368 + * @return mixed
369 + */
370 + private function decode_cached( $value ) {
371 + $previous = self::$decoded_cache[ $this->cache_key ] ?? false;
372 +
373 + if ( $previous && $previous['raw'] === $value ) {
374 + return $previous['decoded'];
375 + }
376 +
377 + $decoded = json_decode( $value, true );
378 +
379 + self::$decoded_cache[ $this->cache_key ] = array(
380 + 'raw' => $value,
381 + 'decoded' => $decoded,
382 + );
383 +
384 + return $decoded;
385 + }
386 +
387 + /**
346 388 * Get the cache for the network if multisite.
347 389 *
348 390 * @since 6.8.3
349 391 *
@@ -437,9 +479,9 @@
437 479 return false;
438 480 }
439 481
440 482 if ( isset( $addon['categories'] ) ) {
441 - if ( 'views' === $addon['slug'] ) {
483 + if ( isset( $addon['slug'] ) && 'views' === $addon['slug'] ) {
442 484 // Legacy views has no categories set, but we should still
443 485 // Include it in cache since it is a valid add-on.
444 486 return true;
445 487 }
@@ -489,12 +531,9 @@
489 531 *
490 532 * @return array
491 533 */
492 534 public function error_for_license() {
493 - if ( ! empty( $this->license ) ) {
494 - return $this->get_error_from_response();
495 - }
496 - return array();
535 + return $this->license ? $this->get_error_from_response() : array();
497 536 }
498 537
499 538 /**
500 539 * @since 3.06