vuehaus icon indicating copy to clipboard operation
vuehaus copied to clipboard

Proposal: Allow router to accept query_data array for what data to include in $post

Open drewbaker opened this issue 6 years ago • 2 comments

OK so 99% of the time whenever I need a custom filter, it is to one of these scenarios:

  1. Add pages to related
  2. Include "featured" pages/posts on the homepage (or a shop landing page etc)
  3. Add some detail to the site data object (like News page name, URL etc).
  4. Manipulate a post meta data value in someway (like format a date, or add in gallery images or related posts out of a meta field)

Now it seems that some of that (3) would be best as a filter, but (1) and (2) are using the rez_gather_related filter and thus the most dangerous and confusing things to do.

Using rez_gather_related It's super easy to get an infinite loop, or make an insane query that slows down your server. The filters end up looking like a mess of if() statements testing against the dev_ids to see when to load all siblings etc...

So could we make an alternative to the rez_gather_related filter? And it seems to me we could do this in a WordPress way by defining an array of settings on the route (trying to match the wp_query syntax).

Now I'm not exactly sure how these settings get used behind the scenes, like do they go on the loop posts? Perhaps anytime a post with the matching dev_id is queried it factors in the provided settings?

This method would also be backwards compatible, which is nice. You could also opt out of data this way too, making things even faster!

I was thinking something like this in router.php:

    $story_args = array(
        'title'         => true,
        'post_content'  => true,
        'post_excerpt'  => true,
        'relative_path' => true,
        'meta'          => array('all', 'meta_key_1', 'meta_key_2'),
        'attachments'   => array('all', 'image/jpeg', 'image/gif'),
        'related'       => array('parent', 'siblings', 'children', 'next', 'previous'),
        'taxonomies'    => array('all', 'category', 'custom_taxonomy_name')
    );
    
    $programmed_routes = array(
    
        path_from_dev_id('stories')     => array(
    		'component' => 'StoriesGrid',
    		'name'      => 'StoriesGridPage',
    		'query_data'      => $story_args
    	)
    
    );

I think there is also an opportunity to include more things in the $post object by default (all attachments, all ACF content, all meta etc). We have some of this all ready, but it's good to look at it again now that we are down the road a little with Vuepress. Also change the name! LOL!

Then most themes would only need to use the rez_serialize_post or the rez_build_site_data filters, which are way easier to understand and less dangerous.

drewbaker avatar Sep 20 '18 00:09 drewbaker

These are awesome thoughts! Going to go through them some here:

rez_gather_related is definitely a dangerous area for infinite loops, so the more we can avoid it (or the easier we can make it), the better!

I like the query idea you’re suggesting - it looks a lot like a GraphQL query like @lwaldner mentioned in Slack. I don’t think router.php would be the place for a server-side query, though - $programmed_routes maps directly to the routes object here, which is used to build the router client-side, so any extra data you’d be requesting would end up being fetched client-side.

If we were okay with that slight delay that comes with fetching data client-side, we could use route meta fields to do something like this:

$story_args = array(
        	'title'         => true,
	// …etc
);
    
$programmed_routes = array(
    
	path_from_dev_id('stories')     => array(
		‘component' => 'StoriesGrid',
		'name'      => 'StoriesGridPage',
		‘meta’		=> array(
			'query_data'      => $story_args
		)
	)
    
);

and write a handler that fetches the data specified in query_data on load.

That doesn’t actually solve the issue, though, since Rest-Easy filters prepare content server-side instead of putting the work on the client.

Maybe it’d be more robust to add a widget to posts that lets you check additional data you’d want attached to the post. We could then add a filter in Rest-Easy core that checks for the values you’ve selected and adds them whenever serializing that particular post.

We should definitely make sure we’re getting everything we want from the default $post object - I’ll raise a new issue where we can make and complete a list!

SaFrMo avatar Sep 20 '18 21:09 SaFrMo

I don't think we want to fetch data client side, the SEO hit would be bad as I understand it.

I know what you mean by the $programmed_routes mapping to the routes object, but I wonder if the $programmed_routes array can be used for two things. Like it gets feed into a function in PHP like parse_routes($programmed_routes) and that makes the routes object and also sets up what data is going with each route, maybe using a pre_get_posts filter and the query_data array provided in $programmed_routes?

Maybe the idea of defining it all in $programmed_routes is too confusing. Could we do something that tapped into route name in another place perhaps? Maybe the easiest thing to do is just include the route name as a parameter in the related filter?

// Our filter callback function
function example_callback( $related, $post, $route_name ) {
    if($route_name == 'StoriesGrid') {
        // Do a get_posts() here for children
    }
    return $related;
}
add_filter( 'build_related', 'add_children,);

That is sort of like how we used to use $state in the old themes.

drewbaker avatar Sep 24 '18 23:09 drewbaker