10, 'headers' => array( 'Accept' => 'application/json' ), ) ); if ( is_wp_error( $response ) ) { return $response; } if ( 200 !== (int) wp_remote_retrieve_response_code( $response ) ) { return new \WP_Error( 'at_http', __( 'The demo library could not be reached.', 'advanced-testimonial' ) ); } $data = json_decode( wp_remote_retrieve_body( $response ), true ); $data = self::validate_manifest( $data ); if ( is_wp_error( $data ) ) { return $data; } set_transient( self::TRANSIENT, $data, self::CACHE_TTL ); return $data; } /** * Validate the raw manifest and normalise its demos. * * @param mixed $data Decoded JSON. * @return array|\WP_Error */ private static function validate_manifest( $data ) { if ( ! is_array( $data ) || empty( $data['demos'] ) || ! is_array( $data['demos'] ) ) { return new \WP_Error( 'at_manifest', __( 'The demo library response was not valid.', 'advanced-testimonial' ) ); } if ( isset( $data['plugin'] ) && 'advanced-testimonial' !== $data['plugin'] ) { return new \WP_Error( 'at_manifest', __( 'The demo library is for a different plugin.', 'advanced-testimonial' ) ); } $demos = array(); foreach ( $data['demos'] as $demo ) { if ( ! is_array( $demo ) || empty( $demo['id'] ) || empty( $demo['file'] ) ) { continue; } $file = esc_url_raw( $demo['file'] ); if ( ! $file || ! in_array( wp_parse_url( $file, PHP_URL_SCHEME ), array( 'http', 'https' ), true ) ) { continue; } $demos[] = array( 'id' => sanitize_key( $demo['id'] ), 'name' => isset( $demo['name'] ) ? sanitize_text_field( $demo['name'] ) : $demo['id'], 'description' => isset( $demo['description'] ) ? sanitize_text_field( $demo['description'] ) : '', 'version' => isset( $demo['version'] ) ? sanitize_text_field( $demo['version'] ) : '', 'requires' => isset( $demo['requires'] ) ? sanitize_text_field( $demo['requires'] ) : '', 'category' => isset( $demo['category'] ) ? sanitize_text_field( $demo['category'] ) : '', 'tags' => isset( $demo['tags'] ) && is_array( $demo['tags'] ) ? array_map( 'sanitize_text_field', $demo['tags'] ) : array(), 'featured' => ! empty( $demo['featured'] ), 'is_new' => ! empty( $demo['new'] ), 'preview' => isset( $demo['preview'] ) ? esc_url_raw( $demo['preview'] ) : '', 'file' => $file, ); } if ( ! $demos ) { return new \WP_Error( 'at_manifest', __( 'The demo library is empty right now.', 'advanced-testimonial' ) ); } return array( 'schema_version' => isset( $data['schema_version'] ) ? absint( $data['schema_version'] ) : 1, 'demos' => $demos, ); } /** * Render the Demo Library page. * * @return void */ public function page() { // A nonce-protected "Refresh" link bypasses the 6h manifest cache. $refresh = isset( $_GET['at_refresh'], $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_wpnonce'] ) ), 'at_demo_refresh' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified inline. $manifest = self::get_manifest( $refresh ); $refresh_url = wp_nonce_url( add_query_arg( array( 'post_type' => CPT::POST_TYPE, 'page' => self::PAGE, 'at_refresh' => 1, ), admin_url( 'edit.php' ) ), 'at_demo_refresh' ); ?>


get_error_message() ); ?>

bundled_card(); ?>
1 ) : ?>
$cat_label ) : ?>
card( $demo ); } ?>
=' ); $haystack = strtolower( trim( $demo['name'] . ' ' . $demo['description'] . ' ' . $demo['category'] . ' ' . implode( ' ', $demo['tags'] ) ) ); ?>
<?php echo esc_attr( $demo['name'] ); ?>

import_demo( $demo_id ) : new \WP_Error( 'at_demo', __( 'Unknown demo.', 'advanced-testimonial' ) ); } $args = array( 'post_type' => CPT::POST_TYPE ); if ( is_wp_error( $result ) || empty( $result['testimonials'] ) ) { $args['at_demo_lib'] = 'fail'; } else { $args['at_demo_lib'] = 'ok'; $args['at_t'] = (int) $result['testimonials']; } wp_safe_redirect( add_query_arg( $args, admin_url( 'edit.php' ) ) ); exit; } /** * Look up a demo in the manifest, fetch its file and import it. * * @param string $demo_id Demo id. * @return array|\WP_Error Import counts or error. */ private function import_demo( $demo_id ) { $manifest = self::get_manifest(); if ( is_wp_error( $manifest ) ) { return $manifest; } // Resolve the demo entry from the manifest (never trust a posted URL). $entry = null; foreach ( $manifest['demos'] as $demo ) { if ( $demo['id'] === $demo_id ) { $entry = $demo; break; } } if ( ! $entry ) { return new \WP_Error( 'at_demo', __( 'That demo is no longer available.', 'advanced-testimonial' ) ); } // Re-check the version requirement server-side. if ( '' !== $entry['requires'] && ! version_compare( ADVANCED_TESTIMONIAL_VERSION, $entry['requires'], '>=' ) ) { return new \WP_Error( 'at_demo', __( 'This demo needs a newer plugin version.', 'advanced-testimonial' ) ); } $response = wp_remote_get( $entry['file'], array( 'timeout' => 15 ) ); if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) { return new \WP_Error( 'at_demo', __( 'The demo could not be downloaded.', 'advanced-testimonial' ) ); } $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! is_array( $data ) || empty( $data['testimonials'] ) ) { return new \WP_Error( 'at_demo', __( 'The demo data was invalid.', 'advanced-testimonial' ) ); } // Imported testimonials are published; images are sideloaded from their URLs. return Demo::import( $data, 'append' ); } /** * Show the import result notice on the testimonial screens. * * @return void */ public function notice() { if ( ! isset( $_GET['at_demo_lib'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } $status = sanitize_key( wp_unslash( $_GET['at_demo_lib'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( 'ok' === $status ) { $count = isset( $_GET['at_t'] ) ? absint( wp_unslash( $_GET['at_t'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended echo '

' . sprintf( /* translators: %d: number of imported testimonials. */ esc_html__( 'Demo imported — %d testimonials added. Display them with the block or the [advanced_testimonial] shortcode.', 'advanced-testimonial' ), (int) $count ) . '

'; } elseif ( 'fail' === $status ) { echo '

' . esc_html__( 'Sorry, that demo could not be imported. Please try again.', 'advanced-testimonial' ) . '

'; } } }