PluginProbe
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce / 3.3.0
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce v3.3.0
3.3.0 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.1 trunk 1.0.4 1.1.0 1.1.0.1 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 All 162 releases
← All changes | wizard/ajax/wizard.php +24 -12 3.1.4 → 3.3.0 View file →
@@ -354,9 +354,11 @@
354 354 $response_data = array( 'message' => $this->get_error_msg( 'nonce' ) );
355 355 wp_send_json_error( $response_data );
356 356 }
357 357
358 - $page_builder = isset( $_POST['page_builder'] ) ? sanitize_text_field( wp_unslash( $_POST['page_builder'] ) ) : '';
358 + // sanitize_key() here as well as sanitize_text_field(): import_templates() writes the
359 + // cache under the sanitized slug, so reading with the raw one missed it permanently.
360 + $page_builder = isset( $_POST['page_builder'] ) ? sanitize_key( wp_unslash( $_POST['page_builder'] ) ) : '';
359 361
360 362 $page = 1;
361 363 $flows_list = array();
362 364
@@ -407,9 +409,11 @@
407 409 $api_args = array(
408 410 'timeout' => 30, //phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout
409 411 );
410 412
411 - $sites_and_pages = array();
413 + // Always shaped like a successful response so the error paths below cannot return
414 + // null for 'flows' — the client reads .flows.length off it.
415 + $sites_and_pages = array( 'flows' => array() );
412 416 $site_url = wcf()->get_site_url();
413 417
414 418 $query_args = array(
415 419 'per_page' => 100,
@@ -422,27 +426,35 @@
422 426 $api_url = add_query_arg( $query_args, $site_url . 'wp-json/cartflows-server/v1/flows-and-steps/' );
423 427
424 428 $response = wp_remote_get( $api_url, $api_args );
425 429
426 - if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) {
430 + if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
427 431
428 - $sites_and_pages = json_decode( wp_remote_retrieve_body( $response ), true );
432 + // Decode into its own variable — assigning over $sites_and_pages let the error
433 + // branches below return a response with no 'flows' key at all.
434 + $decoded = json_decode( wp_remote_retrieve_body( $response ), true );
429 435
430 - if ( isset( $sites_and_pages['code'] ) ) {
431 - $message = isset( $sites_and_pages['message'] ) ? $sites_and_pages['message'] : '';
436 + if ( is_array( $decoded ) && isset( $decoded['code'] ) ) {
437 + $message = isset( $decoded['message'] ) ? $decoded['message'] : '';
432 438 if ( ! empty( $message ) ) {
433 439 wcf()->logger->sync_log( 'HTTP Request Error: ' . $message );
434 440 } else {
435 441 wcf()->logger->sync_log( 'HTTP Request Error!' );
436 442 }
437 - } elseif ( is_array( $sites_and_pages ) && isset( $sites_and_pages['flows'] ) && ! empty( $sites_and_pages['flows'] ) ) {
438 - $option_name = 'cartflows-store-checkout-' . sanitize_key( $page_builder ) . '-flows-and-steps-' . $page;
439 - update_site_option( $option_name, $sites_and_pages['flows'] );
440 - } else {
441 - $sites_and_pages['flows'] = array();
443 + } elseif ( is_array( $decoded ) && ! empty( $decoded['flows'] ) ) {
444 + $sites_and_pages['flows'] = $decoded['flows'];
445 +
446 + $option_name = 'cartflows-store-checkout-' . $page_builder . '-flows-and-steps-' . $page;
447 + update_site_option( $option_name, $decoded['flows'] );
442 448 }
443 449 } else {
444 - wcf()->logger->sync_log( 'API Error: ' . $response->get_error_message() );
450 + // A non-200 response is not necessarily a WP_Error, and get_error_message()
451 + // only exists on one — the previous `||` sent those into the branch above.
452 + $error_message = is_wp_error( $response )
453 + ? $response->get_error_message()
454 + : sprintf( 'HTTP %s', wp_remote_retrieve_response_code( $response ) );
455 +
456 + wcf()->logger->sync_log( 'API Error: ' . $error_message );
445 457 }
446 458
447 459 return $sites_and_pages['flows'];
448 460 }