$type, 'message' => $message, ), 60 ); wp_safe_redirect( $this->tools_url() ); exit; } /** * Handle the maintenance/import actions. * * @return void */ public function handle() { $this->guard(); $tool = isset( $_POST['at_tool'] ) ? sanitize_key( wp_unslash( $_POST['at_tool'] ) ) : ''; switch ( $tool ) { case 'starter': $result = Demo::import_starter(); if ( is_wp_error( $result ) ) { $this->redirect_back( 'error', $result->get_error_message() ); } $this->redirect_back( 'success', sprintf( /* translators: 1: testimonials count, 2: groups count, 3: images count. */ __( 'Starter demo imported: %1$d testimonials, %2$d groups, %3$d images.', 'advanced-testimonial' ), $result['testimonials'], $result['groups'], $result['images'] ) ); break; case 'import': $this->do_import(); break; case 'reset': delete_option( Settings::OPTION ); $this->redirect_back( 'success', __( 'Settings reset to defaults.', 'advanced-testimonial' ) ); break; case 'clear': Query::bust_cache(); delete_transient( DemoLibrary::TRANSIENT ); $this->redirect_back( 'success', __( 'Caches cleared — testimonial queries and the demo library list.', 'advanced-testimonial' ) ); break; case 'debug': $on = ! get_option( self::DEBUG_OPTION ); update_option( self::DEBUG_OPTION, $on ? 1 : 0, false ); $this->redirect_back( 'success', $on ? __( 'Debug mode enabled (query cache bypassed).', 'advanced-testimonial' ) : __( 'Debug mode disabled.', 'advanced-testimonial' ) ); break; default: $this->redirect_back( 'error', __( 'Unknown action.', 'advanced-testimonial' ) ); } } /** * Handle an uploaded demo file import. * * @return void */ private function do_import() { if ( empty( $_FILES['at_import_file']['tmp_name'] ) || ! is_uploaded_file( $_FILES['at_import_file']['tmp_name'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- verifying a PHP upload before reading it. $this->redirect_back( 'error', __( 'Please choose a .json file to import.', 'advanced-testimonial' ) ); } $tmp = sanitize_text_field( wp_unslash( $_FILES['at_import_file']['tmp_name'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $name = isset( $_FILES['at_import_file']['name'] ) ? sanitize_file_name( wp_unslash( $_FILES['at_import_file']['name'] ) ) : ''; if ( 'json' !== strtolower( pathinfo( $name, PATHINFO_EXTENSION ) ) ) { $this->redirect_back( 'error', __( 'The file must be a .json export.', 'advanced-testimonial' ) ); } $data = wp_json_file_decode( $tmp, array( 'associative' => true ) ); if ( ! is_array( $data ) || ( empty( $data['testimonials'] ) && empty( $data['groups'] ) ) ) { $this->redirect_back( 'error', __( 'That file is not a valid Advanced Testimonial export.', 'advanced-testimonial' ) ); } $strategy = isset( $_POST['at_strategy'] ) ? sanitize_key( wp_unslash( $_POST['at_strategy'] ) ) : 'append'; $with_settings = ! empty( $_POST['at_with_settings'] ); if ( ! $with_settings ) { unset( $data['settings'] ); } $result = Demo::import( $data, $strategy ); $this->redirect_back( 'success', sprintf( /* translators: 1: testimonials, 2: groups, 3: images, 4: skipped. */ __( 'Import complete: %1$d testimonials, %2$d groups, %3$d images (%4$d skipped).', 'advanced-testimonial' ), $result['testimonials'], $result['groups'], $result['images'], $result['skipped'] ) ); } /** * Stream a JSON export as a download. * * @return void */ public function handle_export() { $this->guard(); $include = array( 'testimonials' => ! empty( $_POST['at_export_testimonials'] ), 'groups' => ! empty( $_POST['at_export_groups'] ), 'settings' => ! empty( $_POST['at_export_settings'] ), ); if ( ! $include['testimonials'] && ! $include['groups'] && ! $include['settings'] ) { $include['testimonials'] = true; $include['groups'] = true; } $data = Demo::export( $include ); $filename = 'advanced-testimonial-export-' . gmdate( 'Y-m-d' ) . '.json'; nocache_headers(); header( 'Content-Type: application/json; charset=utf-8' ); header( 'Content-Disposition: attachment; filename=' . $filename ); echo wp_json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); exit; } /** * Output any one-time notice (called by the Settings page). * * @return void */ public static function maybe_notice() { $notice = get_transient( self::NOTICE_TRANSIENT ); if ( ! $notice ) { return; } delete_transient( self::NOTICE_TRANSIENT ); $class = ( 'error' === $notice['type'] ) ? 'notice-error' : ( 'warning' === $notice['type'] ? 'notice-warning' : 'notice-success' ); printf( '
%2$s
' . esc_html__( 'One-click sample content: 6 testimonials, 2 groups, ratings, companies and images. Existing testimonials are skipped.', 'advanced-testimonial' ) . '
'; echo ''; self::action_button( $post_url, 'clear', __( 'Clear Cache', 'advanced-testimonial' ), 'secondary' ); self::action_button( $post_url, 'debug', $debug_on ? __( 'Disable Debug Mode', 'advanced-testimonial' ) : __( 'Enable Debug Mode', 'advanced-testimonial' ), 'secondary' ); self::action_button( $post_url, 'reset', __( 'Reset Settings', 'advanced-testimonial' ), 'delete', true ); echo '
'; echo '' . ( $debug_on ? esc_html__( 'Debug mode is ON — query cache is bypassed.', 'advanced-testimonial' ) : esc_html__( 'Reset restores default settings. Testimonials are never deleted.', 'advanced-testimonial' ) ) . '
'; echo '