$post_type, 'posts_per_page' => 5000, 'post_status' => 'any' ) ); $data = array(); foreach ( $posts as $p ) { $terms = array(); foreach ( get_object_taxonomies( $post_type ) as $tax ) { $ids = wp_get_post_terms( $p->ID, $tax, array( 'fields' => 'ids' ) ); if ( ! is_wp_error( $ids ) ) { $terms[ $tax ] = $ids; } } $data[] = array( 'ID' => $p->ID, 'post_title' => $p->post_title, 'post_name' => $p->post_name, 'post_status' => $p->post_status, 'post_content' => $p->post_content, 'post_excerpt' => $p->post_excerpt, 'post_author' => (int) $p->post_author, 'post_date' => $p->post_date, 'menu_order' => $p->menu_order, 'post_parent' => $p->post_parent, 'meta' => get_post_meta( $p->ID ), 'terms' => $terms, ); } $file = 'snapshot-' . sanitize_key( $post_type ) . '-' . gmdate( 'Ymd-His' ) . '-' . Storage::token() . '.json'; $ok = file_put_contents( self::dir() . $file, wp_json_encode( array( 'post_type' => $post_type, 'created' => gmdate( 'c' ), 'items' => $data ) ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents if ( false === $ok ) { return new \WP_Error( 'rafgrid_snapshot_failed', __( 'Cannot write snapshot file.', 'rafgrid' ) ); } return array( 'file' => $file, 'count' => count( $data ) ); } /** * @return array list of {file, size, post_type} */ public static function listing(): array { $out = array(); foreach ( glob( self::dir() . 'snapshot-*.json' ) ?: array() as $f ) { if ( ! preg_match( self::FILE_PATTERN, basename( $f ) ) ) { continue; } $out[] = array( 'file' => basename( $f ), 'size' => filesize( $f ), 'mtime' => filemtime( $f ) ); } usort( $out, static fn( $a, $b ) => $b['mtime'] <=> $a['mtime'] ); return array_slice( $out, 0, 20 ); } /** * Restore existing posts from a snapshot (updates by ID, skips deleted). * * @param string $file File name. * @return array {restored, skipped} */ public static function restore( string $file ) { $path = Storage::path( 'snapshots', $file, self::FILE_PATTERN ); if ( null === $path ) { return array( 'restored' => 0, 'skipped' => 0 ); } $raw = json_decode( (string) file_get_contents( $path ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_get_contents $restored = 0; $skipped = 0; foreach ( (array) ( $raw['items'] ?? array() ) as $item ) { $post = get_post( (int) ( $item['ID'] ?? 0 ) ); if ( ! $post || ! Access::can_edit_post( $post->ID ) ) { ++$skipped; continue; } wp_update_post( array( 'ID' => $post->ID, 'post_title' => $item['post_title'], 'post_status' => $item['post_status'], 'post_content' => $item['post_content'], 'post_excerpt' => $item['post_excerpt'], ) ); foreach ( (array) ( $item['meta'] ?? array() ) as $k => $vals ) { delete_post_meta( $post->ID, $k ); foreach ( (array) $vals as $v ) { add_post_meta( $post->ID, $k, maybe_unserialize( $v ) ); } } foreach ( (array) ( $item['terms'] ?? array() ) as $tax => $ids ) { wp_set_post_terms( $post->ID, array_map( 'intval', (array) $ids ), $tax, false ); } ++$restored; } return array( 'restored' => $restored, 'skipped' => $skipped ); } }