Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replicate Genesis-SB logic to display posts on the home page and archives using 3 different layouts #13

Closed
4 tasks done
bobbingwide opened this issue Mar 26, 2021 · 11 comments
Assignees
Labels
enhancement New feature or request

Comments

@bobbingwide
Copy link
Owner

bobbingwide commented Mar 26, 2021

In the Genesis-SB theme the home page and certain archive pages display the result of the main query in three parts.

  • Hero
  • Thumbnail grid - up to 4 by 4
  • Links section

followed by a pagination block.

60 bigrams are displayed per page.

The logic I need to replicate includes a routine to rearrange the posts per page so that those with a Featured image come first.
This is genesis_sb_the_posts( $posts, $query ) which is hooked into the_posts. It's run on every page.

Note: I assume there'll be at least one featured image in a block of 60 bigrams.

Then in the loop to display the posts there's logic to check which format to use, based on the index and the number of posts which have a featured image.

function genesis_sb_do_loop() {
	$count = 0;
	$images = genesis_sb_featured_images( 1 );
	
	if ( have_posts() ) {
		while ( have_posts() ) {
			the_post();
			//do_action( 'genesis_before_entry' );
			if ( $count == 0 ) {
				genesis_sb_hero();
			} elseif ( $count < $images  ) {
				genesis_sb_images();
			} elseif ( $count == $images ) {
				printf( '<div %s>', genesis_attr( "links" ) );
				genesis_sb_after_images();
            } else {
				genesis_sb_after_images();
			}
			$count++;
		}
		echo '</div>';
		do_action( 'genesis_after_endwhile' );
	} else {
		do_action( 'genesis_loop_else' );
	}
}
  • genesis_sb_featured_images() will return 0, 4, 8, 12 or 16
  • it uses genesis_sb_full_rows() to determine this
  • genesis_sb_hero(), genesis_sb_images() and genesis_sb_after_images are the functions being replaced by the three query blocks.

Proposed solution

  • I'll implement the the_posts filter first.
  • I have to find a way of detecting which query block is being processed to determine which of the (up to 60) posts returned in the main query should be processed per block.
  • I'm going to try to override the gutenberg_render_block_core_query_loop() to either fiddle with the main query's posts or handle the loop myself.
  • The override logic will be similar to the solution for Fizzie; I've already implemented logic to override tag-cloud and template-part.
@bobbingwide bobbingwide added the enhancement New feature or request label Mar 26, 2021
@bobbingwide bobbingwide self-assigned this Mar 26, 2021
@bobbingwide
Copy link
Owner Author

I have to find a way of detecting which query block is being processed to determine which of the (up to 60) posts returned in the main query should be processed per block.

This can be done by setting the className on each query-loop block in the Block settings > Advanced > Additional CSS class(es).

Main query part CSS classes
Hero sb hero
Thumbnails sb thumbails
Links sb links

Additionally, as with Fizzie, we can also consider eliminating the core/query block.
... But this would prevent us from adjusting grid layout.

@bobbingwide
Copy link
Owner Author

The following simple typo hindered my progress for a while.

<!-- wp:query-loop {"className": "sb hero" } /-->

Here I unintentionally added a self ending slash in the query-loop block.

This was the first query block in the template part.

I couldn't understand why the subsequent query blocks in the template part weren't being processed.
Nor did it make sense that the query-loop's inner blocks were being processed, since in the block's override logic
the actual processing of the inner blocks was in the else part of an if statement. And the results I could see indicated that the if condition was true.

This is what it should have been like.

<!-- wp:query {"queryId":6,"query":{"perPage":1,"pages":0,"offset":0,"postType":"bigram","categoryIds":[],"tagIds":[],"order":"desc","orderBy":"date","author":"","search":"","exclude":[],"sticky":"","inherit":true},"layout":{"type":"list","columns":2}} -->
<!-- wp:query-loop {"className": "sb hero" } -->

<!-- wp:post-featured-image {"isLink":true,"align":"wide"} /-->
<!-- wp:post-title {"isLink":true} /-->
<!-- wp:post-content /-->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:post-date /-->
<!-- /wp:query-loop -->
<!-- /wp:query -->

... second and third query blocks omitted.

Explanation

  • The unwanted slash meant that the query-loop was basically an empty block.
  • So the blocks that followed were outside of the query-loop
  • And they displayed the output for the current post. The output I wanted but wasnt yet expecting.
  • The end query loop was ignored.
  • And so it seems were the query and query-loops that followed.

@bobbingwide
Copy link
Owner Author

This is what I was actually expecting to get.

image

This is what I was getting.
image

When the code is wrong the subsequent query-loop blocks are not run, even though they're coded correctly.
Other blocks, such as the separator, were being processed.

Oh, and now I've just noticed that my footer's gone back to wide width not full width!

@bobbingwide
Copy link
Owner Author

bobbingwide commented Mar 26, 2021

I'm going to try to override the gutenberg_render_block_core_query_loop() to either fiddle with the main query's posts or handle the loop myself.

It was easier to handle the loop myself than to fiddle with the main query's posts.
In order to get the grid/flex layout I had to copy some of the new code that sets the block wrapper attributes.

Here's an unstyled screenshot of the bottom of the thumbnail grid and the top of the links.
Note: I need to add "isLink": "true" as to both the featured image and the post title blocks.

image

@bobbingwide
Copy link
Owner Author

bobbingwide commented May 1, 2022

With Gutenberg 12.9.0 the post title block is showing the same value for each post in the thumbnail grid and links section.
But the link is to the correct post.

image

Is this an issue with Gutenberg?
How do we find out?

Note: Also using WordPress 6.0-beta2

@bobbingwide
Copy link
Owner Author

Reverting to an earlier version of Gutenberg the title is correctly displayed.
Now I need to find out where it went wrong.

Version OK ?
12.0.0 Yes
12.1.0 Yes
12.2.0 Yes
12.3.0 No

@bobbingwide
Copy link
Owner Author

bobbingwide commented May 2, 2022

I tracked the problem down to code changes implemented in WordPress/gutenberg#37622
For both the post-title and post-content blocks the $post_id is no longer being passed to the function that gets the post title or content for the given post.

Local fix

By setting $GLOBAL[ 'post'] to the current post in the loop
I was able to rework my code in sb_render_block_core_post_template_main_query() to fiddle the logic for the post title.
See below.

But I couldn't do it easily for the post content.
When the post ID is not set and the the_post action has been invoked, the logic in get_the_content() reuses globals.
It assumes you're processing the same post each time.

I don't need the post content anyway.

If necessary, I could get by using the post-excerpt field which hasn't been changed for preview processing.

Reproducing without override logic

The problem occurs in my overriding of the post-template block, when sb_render_block_core_post_template_main_query() uses the WP_Block::render() method directly.
The new logic implemented for PR 37622 ignores the values set in the $available_context.

$content = '';
    $saved_post = $GLOBALS['post'];
    //in_the_loop();
    //global $wp_query;
    //set_query_var( 'in_the_loop', ;
    //$wp_query->in_the_loop = true;

    foreach ( $wp_query->posts as $index => $post ) {
    	$GLOBALS['post'] = $post;
        if ( $index >= $attributes['offset'] && $index < $attributes['limit']) {
        	//$content = get_the_content( null, false, $post );
            $block_content = (
            new WP_Block(
                $block->parsed_block,
                array(
                    'postType' => $post->post_type,
                    'postId' => $post->ID,
                )
            )
            )->render(array('dynamic' => false));
            $content .= "<li>{$block_content}</li>";
        }
    }
	$GLOBALS['post'] = $saved_post;

I would have thought that anyone else writing their own code to dynamically display inner blocks would experience the same problem.

So far I've been unable to reproduce the problem with a standard theme like Twenty Twenty Two.

@bobbingwide
Copy link
Owner Author

bobbingwide commented May 2, 2022

But I couldn't do it easily for the post content.

I hadn't considered overriding the post-content block. This would be a fairly easy fix; revert the change so that the $post_id is passed to get_the_content().

Another hacky change would be to reset the count of the number of times the_post action was invoked.

$saved_post = $GLOBALS['post'];
    //in_the_loop();
    //global $wp_query;
    //set_query_var( 'in_the_loop', ;
    //$wp_query->in_the_loop = true;
	global $wp_actions;

    foreach ( $wp_query->posts as $index => $post ) {
    	$GLOBALS['post'] = $post;
    	$wp_actions['the_post'] = 0;
        if ( $index >= $attributes['offset'] && $index < $attributes['limit']) {
        	//$content = get_the_content( null, false, $post );
            $block_content = (
            new WP_Block(
                $block->parsed_block,
                array(
                    'postType' => $post->post_type,
                    'postId' => $post->ID,
                )
            )
            )->render(array('dynamic' => false));
            $content .= "<li>{$block_content}</li>";
        }
    }
	$GLOBALS['post'] = $saved_post;

@bobbingwide
Copy link
Owner Author

I found the correct solution when I looked at the code for gutenberg_render_block_core_post_template()
This uses a standard query loop. I changed my foreach loop to a while loop
which calls WP_Query::the_post() for each post before rendering the block.

$index = 0;
while ( $wp_query->have_posts() ) {
    $wp_query->the_post();
    if ... {
        render block
    }    
    $index++;
}

This solution works for both the post title and the post content.

@bobbingwide
Copy link
Owner Author

bobbingwide commented May 3, 2022

The 3 query loops now work but the second and third use the full width of the 66% ( left hand) column.
The query loop blocks need to have the Inherit default layout toggled on.

@bobbingwide
Copy link
Owner Author

This solution is now delivered in v0.2.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant