| @@ -43,8 +43,9 @@ | ||
| 43 | 43 | * @return string Returns the post content with latest posts added. |
| 44 | 44 | */ |
| 45 | 45 | function gutenberg_render_block_core_latest_posts( $attributes ) { |
| 46 | 46 | global $post, $block_core_latest_posts_excerpt_length; |
| 47 | + static $rendering_stack = array(); | |
| 47 | 48 | |
| 48 | 49 | $args = array( |
| 49 | 50 | 'posts_per_page' => $attributes['postsToShow'], |
| 50 | 51 | 'post_status' => 'publish', |
| @@ -56,17 +57,17 @@ | ||
| 56 | 57 | |
| 57 | 58 | $block_core_latest_posts_excerpt_length = $attributes['excerptLength']; |
| 58 | 59 | add_filter( 'excerpt_length', 'gutenberg_block_core_latest_posts_get_excerpt_length', 20 ); |
| 59 | 60 | |
| 60 | - if ( ! empty( $attributes['categories'] ) ) { | |
| 61 | - $args['category__in'] = array_column( $attributes['categories'], 'id' ); | |
| 61 | + $categories = $attributes['categories'] ?? null; | |
| 62 | + if ( ! empty( $categories ) && is_array( $categories ) ) { | |
| 63 | + $args['category__in'] = array_column( $categories, 'id' ); | |
| 62 | 64 | } |
| 63 | 65 | if ( isset( $attributes['selectedAuthor'] ) ) { |
| 64 | 66 | $args['author'] = $attributes['selectedAuthor']; |
| 65 | 67 | } |
| 66 | 68 | |
| 67 | - $query = new WP_Query(); | |
| 68 | - $recent_posts = $query->query( $args ); | |
| 69 | + $query = new WP_Query( $args ); | |
| 69 | 70 | |
| 70 | 71 | if ( isset( $attributes['displayFeaturedImage'] ) && $attributes['displayFeaturedImage'] ) { |
| 71 | 72 | update_post_thumbnail_cache( $query ); |
| 72 | 73 | } |
| @@ -71,12 +72,18 @@ | ||
| 71 | 72 | update_post_thumbnail_cache( $query ); |
| 72 | 73 | } |
| 73 | 74 | |
| 74 | 75 | $list_items_markup = ''; |
| 76 | + // Snapshot the current global post so it can be restored after the loop. | |
| 77 | + // We use have_posts()/the_post() rather than foreach so that setup_postdata() | |
| 78 | + // is called for each post, establishing the correct global context for | |
| 79 | + // do_blocks() and other filters that run during full-content rendering. | |
| 80 | + $previous_post = $post ?? null; | |
| 75 | 81 | |
| 76 | - foreach ( $recent_posts as $post ) { | |
| 77 | - $post_link = esc_url( get_permalink( $post ) ); | |
| 78 | - $title = get_the_title( $post ); | |
| 82 | + while ( $query->have_posts() ) { | |
| 83 | + $query->the_post(); | |
| 84 | + $post_link = esc_url( get_permalink() ); | |
| 85 | + $title = get_the_title(); | |
| 79 | 86 | |
| 80 | 87 | if ( ! $title ) { |
| 81 | 88 | $title = __( '(no title)' ); |
| 82 | 89 | } |
| @@ -82,9 +89,9 @@ | ||
| 82 | 89 | } |
| 83 | 90 | |
| 84 | 91 | $list_items_markup .= '<li>'; |
| 85 | 92 | |
| 86 | - if ( $attributes['displayFeaturedImage'] && has_post_thumbnail( $post ) ) { | |
| 93 | + if ( $attributes['displayFeaturedImage'] && has_post_thumbnail() ) { | |
| 87 | 94 | $image_style = ''; |
| 88 | 95 | if ( isset( $attributes['featuredImageSizeWidth'] ) ) { |
| 89 | 96 | $image_style .= sprintf( 'max-width:%spx;', $attributes['featuredImageSizeWidth'] ); |
| 90 | 97 | } |
| @@ -97,9 +104,9 @@ | ||
| 97 | 104 | $image_classes .= ' align' . $attributes['featuredImageAlign']; |
| 98 | 105 | } |
| 99 | 106 | |
| 100 | 107 | $featured_image = get_the_post_thumbnail( |
| 101 | - $post, | |
| 108 | + null, | |
| 102 | 109 | $attributes['featuredImageSizeSlug'], |
| 103 | 110 | array( |
| 104 | 111 | 'style' => esc_attr( $image_style ), |
| 105 | 112 | ) |
| @@ -125,9 +132,9 @@ | ||
| 125 | 132 | $title |
| 126 | 133 | ); |
| 127 | 134 | |
| 128 | 135 | if ( isset( $attributes['displayAuthor'] ) && $attributes['displayAuthor'] ) { |
| 129 | - $author_display_name = get_the_author_meta( 'display_name', $post->post_author ); | |
| 136 | + $author_display_name = get_the_author_meta( 'display_name' ); | |
| 130 | 137 | |
| 131 | 138 | /* translators: byline. %s: author. */ |
| 132 | 139 | $byline = sprintf( __( 'by %s' ), $author_display_name ); |
| 133 | 140 | |
| @@ -141,10 +148,10 @@ | ||
| 141 | 148 | |
| 142 | 149 | if ( isset( $attributes['displayPostDate'] ) && $attributes['displayPostDate'] ) { |
| 143 | 150 | $list_items_markup .= sprintf( |
| 144 | 151 | '<time datetime="%1$s" class="wp-block-latest-posts__post-date">%2$s</time>', |
| 145 | - esc_attr( get_the_date( 'c', $post ) ), | |
| 146 | - get_the_date( '', $post ) | |
| 152 | + esc_attr( get_the_date( 'c' ) ), | |
| 153 | + get_the_date( '' ) | |
| 147 | 154 | ); |
| 148 | 155 | } |
| 149 | 156 | |
| 150 | 157 | if ( isset( $attributes['displayPostContent'] ) && $attributes['displayPostContent'] |
| @@ -149,9 +156,9 @@ | ||
| 149 | 156 | |
| 150 | 157 | if ( isset( $attributes['displayPostContent'] ) && $attributes['displayPostContent'] |
| 151 | 158 | && isset( $attributes['displayPostContentRadio'] ) && 'excerpt' === $attributes['displayPostContentRadio'] ) { |
| 152 | 159 | |
| 153 | - $trimmed_excerpt = get_the_excerpt( $post ); | |
| 160 | + $trimmed_excerpt = get_the_excerpt(); | |
| 154 | 161 | |
| 155 | 162 | /* |
| 156 | 163 | * Adds a "Read more" link with screen reader text. |
| 157 | 164 | * […] is the default excerpt ending from wp_trim_excerpt() in Core. |
| @@ -169,9 +176,9 @@ | ||
| 169 | 176 | ); |
| 170 | 177 | } |
| 171 | 178 | } |
| 172 | 179 | |
| 173 | - if ( post_password_required( $post ) ) { | |
| 180 | + if ( post_password_required() ) { | |
| 174 | 181 | $trimmed_excerpt = __( 'This content is password protected.' ); |
| 175 | 182 | } |
| 176 | 183 | |
| 177 | 184 | $list_items_markup .= sprintf( |
| @@ -182,17 +189,32 @@ | ||
| 182 | 189 | |
| 183 | 190 | if ( isset( $attributes['displayPostContent'] ) && $attributes['displayPostContent'] |
| 184 | 191 | && isset( $attributes['displayPostContentRadio'] ) && 'full_post' === $attributes['displayPostContentRadio'] ) { |
| 185 | 192 | |
| 186 | - $post_content = html_entity_decode( $post->post_content, ENT_QUOTES, get_option( 'blog_charset' ) ); | |
| 193 | + if ( post_password_required() ) { | |
| 194 | + $post_content = __( 'This content is password protected.' ); | |
| 195 | + } else { | |
| 196 | + $post_id = get_the_ID(); | |
| 197 | + $post_content = get_post_field( 'post_content', $post_id, 'raw' ); | |
| 198 | + // Check if we're already rendering this post to prevent infinite recursion. | |
| 199 | + if ( in_array( $post_id, $rendering_stack, true ) ) { | |
| 200 | + $post_content = ''; | |
| 201 | + } else { | |
| 202 | + $rendering_stack[] = $post_id; | |
| 187 | 203 | |
| 188 | - if ( post_password_required( $post ) ) { | |
| 189 | - $post_content = __( 'This content is password protected.' ); | |
| 204 | + try { | |
| 205 | + // Run through the actions that are typically taken on the_content. | |
| 206 | + $post_content = _wp_apply_block_content_filters( $post_content, 'latest-posts' ); | |
| 207 | + } finally { | |
| 208 | + array_pop( $rendering_stack ); | |
| 209 | + } | |
| 210 | + } | |
| 190 | 211 | } |
| 191 | 212 | |
| 213 | + $post_content = str_replace( ']]>', ']]>', $post_content ); | |
| 192 | 214 | $list_items_markup .= sprintf( |
| 193 | 215 | '<div class="wp-block-latest-posts__post-full-content">%1$s</div>', |
| 194 | - wp_kses_post( $post_content ) | |
| 216 | + $post_content | |
| 195 | 217 | ); |
| 196 | 218 | } |
| 197 | 219 | |
| 198 | 220 | $list_items_markup .= "</li>\n"; |
| @@ -197,16 +219,36 @@ | ||
| 197 | 219 | |
| 198 | 220 | $list_items_markup .= "</li>\n"; |
| 199 | 221 | } |
| 200 | 222 | |
| 223 | + // Restore the post context that was active before this secondary query. | |
| 224 | + // wp_reset_postdata() is intentionally not used here: when this block is | |
| 225 | + // rendered inside another post's content (e.g. via do_blocks()), it would | |
| 226 | + // restore to the main query post rather than the outer rendering post. | |
| 227 | + $post = $previous_post; | |
| 228 | + if ( $previous_post instanceof WP_Post ) { | |
| 229 | + setup_postdata( $previous_post ); | |
| 230 | + } | |
| 231 | + | |
| 201 | 232 | remove_filter( 'excerpt_length', 'gutenberg_block_core_latest_posts_get_excerpt_length', 20 ); |
| 202 | 233 | |
| 234 | + $layout = $attributes['layout'] ?? array(); | |
| 235 | + $legacy_layout_type = ( | |
| 236 | + isset( $attributes['postLayout'] ) && | |
| 237 | + 'grid' === $attributes['postLayout'] | |
| 238 | + ) ? 'grid' : 'default'; | |
| 239 | + $layout_type = $layout['type'] ?? $legacy_layout_type; | |
| 240 | + $column_count = $layout['columnCount'] ?? ( $attributes['columns'] ?? null ); | |
| 241 | + | |
| 203 | 242 | $classes = array( 'wp-block-latest-posts__list' ); |
| 204 | - if ( isset( $attributes['postLayout'] ) && 'grid' === $attributes['postLayout'] ) { | |
| 243 | + if ( 'grid' === $layout_type ) { | |
| 205 | 244 | $classes[] = 'is-grid'; |
| 206 | 245 | } |
| 207 | - if ( isset( $attributes['columns'] ) && 'grid' === $attributes['postLayout'] ) { | |
| 208 | - $classes[] = 'columns-' . $attributes['columns']; | |
| 246 | + if ( 'grid' === $layout_type && ! empty( $column_count ) ) { | |
| 247 | + $classes[] = sanitize_title( 'columns-' . $column_count ); | |
| 248 | + } | |
| 249 | + if ( 'grid' === $layout_type && ! empty( $column_count ) && ! empty( $layout['minimumColumnWidth'] ) ) { | |
| 250 | + $classes[] = 'has-native-responsive-grid'; | |
| 209 | 251 | } |
| 210 | 252 | if ( isset( $attributes['displayPostDate'] ) && $attributes['displayPostDate'] ) { |
| 211 | 253 | $classes[] = 'has-dates'; |
| 212 | 254 | } |