{"id":43,"date":"2025-09-26T08:50:53","date_gmt":"2025-09-26T08:50:53","guid":{"rendered":"https:\/\/ska-blocks.com\/docs\/2025\/09\/26\/query-filters\/"},"modified":"2025-09-26T09:40:59","modified_gmt":"2025-09-26T09:40:59","slug":"query-filters","status":"publish","type":"post","link":"https:\/\/ska-blocks.com\/docs\/query-filters\/","title":{"rendered":"Query filters"},"content":{"rendered":"\n<p>The WordPress <a href=\"https:\/\/wordpress.org\/documentation\/article\/query-loop-block\/\" target=\"_blank\" rel=\"noreferrer noopener\">Query Loop block<\/a> can be used to display posts in the Block Editor. It has settings for a <strong>post type<\/strong>, <strong>ordering<\/strong>, whether to include <strong>sticky posts<\/strong> or not and some <strong>filtering<\/strong> capabilities. <\/p>\n\n\n\n<p class=\"lead\">ska-blocks plugin provides an <strong>API<\/strong> to create Query <strong>filters<\/strong> for overriding what posts a specific Query Loop block will render.<\/p>\n\n\n\n<p>By default the <strong>Previous post<\/strong>, <strong>Next post<\/strong> and <strong>Related posts<\/strong> filters are defined. These are used by ska-theme to provide Template parts for <strong>Posts navigation<\/strong> as well as <strong>Related posts<\/strong> which are both using the Query Loop block with query filters to achieve their functionality.<\/p>\n\n\n\n<p>When a filter is selected, the WordPress core <code>query_loop_block_query_vars<\/code> filter is used to override the query that the block will use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Add a custom filter<\/h2>\n\n\n\n<p>Additional query filters can be registered with the following code:<\/p>\n\n\n\n<div class=\"wp-block-ska-code not-prose ska-preset--ska-theme--code\"><header><span class=\"title\">Registering a custom query<\/span><span class=\"label language-php\">PHP<\/span><\/header><div class=\"content\"><pre class=\"code php language-php\"><code class=\"language-php\">add_action('ska_blocks_init', function() {\n\n\tska_blocks()->get('query-filters')->register_filter(&#91;\n\t\t'slug' => 'query-slug',\n\t\t'label' => 'Query label',\n\t\t'callback' => function($query, $block, $page) {\n\t\t\treturn &#91;];\n\t\t},\n\t]);\n});<\/code><\/pre><button :class=\"{error: state === &apos;error&apos;, success: state === &apos;success&apos;}\" x-data=\"{state:&apos;&apos;}\" x-on:click=\"navigator.clipboard ? (navigator.clipboard.writeText($el.previousElementSibling.innerText), $el.innerText = `Copied!`, state = &apos;success&apos;) : ($el.innerText = `Can&amp;#039;t copy`, state = &apos;error&apos;)\" class=\"copy\" type=\"button\">Copy<\/button><\/div><\/div>\n\n\n\n<p>You should provide a <strong>slug<\/strong>, <strong>label<\/strong> and a <strong>callback<\/strong> to the <code>register_filter<\/code> function. The callback function should return an array of arguments for <a href=\"https:\/\/developer.wordpress.org\/reference\/classes\/wp_query\/\" target=\"_blank\" rel=\"noreferrer noopener\">WP_Query<\/a>.<\/p>\n\n\n\n<p>The arguments for the callback function are as follows:<\/p>\n\n\n\n<div class=\"wp-block-ska-code not-prose ska-preset--ska-theme--code\"><div class=\"content\"><pre class=\"code php language-php\"><code class=\"language-php\">\/**\n * @param array $query Array containing parameters for `WP_Query` as parsed by the block context.\n * @param WP_Block $block Block instance.\n * @param int $page Current query's page.\n *\/<\/code><\/pre><\/div><\/div>\n\n\n\n<p>Once added your custom query filter should show up in the controls for the Query Loop block:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/ska-blocks.com\/docs\/wp-content\/uploads\/sites\/3\/2024\/03\/image-106.png\" alt=\"\" class=\"wp-image-1095\"\/><\/figure>\n\n\n\n<p>Enabling a filter will use the arguments from the callback function when rendering the block on the <strong>front end<\/strong>. In the <strong>block editor<\/strong> the posts that are shown will still use the configuration from the original Query Loop block.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Examples<\/h2>\n\n\n\n<p>Copy and modify the example code to create your own custom query filters. Ideally such code should be placed in your child theme&#8217;s <code>functions.php<\/code> file. Using the <code>ska_blocks_init<\/code> action instead of <code>init<\/code> ensures that the code is only run when the ska-block plugin is activated and the <code>ska_blocks()<\/code> functions is available.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Randomize results<\/h3>\n\n\n\n<p>At the time of writing the Query Loop block doesn&#8217;t support random ordering, but it can be implemented by adding a query filter that set&#8217;s the WP_Query&#8217;s <code>orderby<\/code> argument to <code>rand<\/code> and passes the rest of the query on.<\/p>\n\n\n\n<div class=\"wp-block-ska-code not-prose ska-preset--ska-theme--code\"><header><span class=\"title\">Previous post query filter<\/span><span class=\"label language-php\">PHP<\/span><\/header><div class=\"content\"><pre class=\"code php language-php\"><code class=\"language-php\">add_action('ska_blocks_init', function() {\n\n\tska_blocks()->get('query-filters')->register_filter(&#91;\n\t\t'slug' => 'randomized-results',\n\t\t'label' => 'Randomize results',\n\t\t'callback' => function($query, $block, $page) {\n\t\t\t$query&#91;'orderby'] = 'rand';\n\t\t\treturn $query;\n\t\t},\n\t]);\n});<\/code><\/pre><button :class=\"{error: state === &apos;error&apos;, success: state === &apos;success&apos;}\" x-data=\"{state:&apos;&apos;}\" x-on:click=\"navigator.clipboard ? (navigator.clipboard.writeText($el.previousElementSibling.innerText), $el.innerText = `Copied!`, state = &apos;success&apos;) : ($el.innerText = `Can&amp;#039;t copy`, state = &apos;error&apos;)\" class=\"copy\" type=\"button\">Copy<\/button><\/div><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Previous post<\/h3>\n\n\n\n<p>Here&#8217;s how the Previous post query filter is implemented:<\/p>\n\n\n\n<div class=\"wp-block-ska-code not-prose ska-preset--ska-theme--code\"><header><span class=\"title\">Previous post query filter<\/span><span class=\"label language-php\">PHP<\/span><\/header><div class=\"content\"><pre class=\"code php language-php\"><code class=\"language-php\">add_action('ska_blocks_init', function() {\n\n\tska_blocks()->get('query-filters')->register_filter(&#91;\n\t\t'slug' => 'previous-post',\n\t\t'label' => __('Previous post', 'ska-blocks'),\n\t\t'callback' => function($query, $block, $page) {\n\n\t\t\tif($prev_post = get_adjacent_post(false, '', true, 'category')) {\n\t\t\t\treturn &#91;\n\t\t\t\t\t'post__in' => &#91;$prev_post->ID],\n\t\t\t\t\t'posts_per_page' => 1,\n\t\t\t\t\t'ignore_sticky_posts' => true,\n\t\t\t\t];\n\t\t\t}\n\n\t\t\treturn &#91;];\n\t\t},\n\t]);\n});<\/code><\/pre><button :class=\"{error: state === &apos;error&apos;, success: state === &apos;success&apos;}\" x-data=\"{state:&apos;&apos;}\" x-on:click=\"navigator.clipboard ? (navigator.clipboard.writeText($el.previousElementSibling.innerText), $el.innerText = `Copied!`, state = &apos;success&apos;) : ($el.innerText = `Can&amp;#039;t copy`, state = &apos;error&apos;)\" class=\"copy\" type=\"button\">Copy<\/button><\/div><\/div>\n\n\n\n<p>Since WordPress already comes with the <code>get_adjacent_post()<\/code> function, it is used to retrieve the ID of the previous post. Once the ID is known, it is simply passed to the <code>WP_Query<\/code> arguments so that it returns this particular post.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Related posts<\/h3>\n\n\n\n<p>Here&#8217;s how the Related posts filter is implemented:<\/p>\n\n\n\n<div class=\"wp-block-ska-code not-prose ska-preset--ska-theme--code\"><header><span class=\"title\">Related posts query filter<\/span><span class=\"label language-php\">PHP<\/span><\/header><div class=\"content\"><pre class=\"code php language-php\"><code class=\"language-php\">add_action('ska_blocks_init', function() {\n\n\tska_blocks()->get('query-filters')->register_filter(&#91;\n\t\t'slug' => 'related-posts',\n\t\t'label' => __('Related posts', 'ska-blocks'),\n\t\t'callback' => function($query, $block, $page) {\n\n\t\t\t$related_query = array_merge($query, &#91;\n\t\t\t\t'post_type' => get_post_type(),\n\t\t\t\t'post__not_in' => array_merge(&#91;get_the_ID()], $query&#91;'post__not_in'] ?? &#91;]),\n\t\t\t\t'orderby' => 'rand',\n\t\t\t\t'ignore_sticky_posts' => true,\n\t\t\t\t'tax_query' => &#91;],\n\t\t\t]);\n\n\t\t\t$post = get_post();\n\t\t\t$taxonomies = get_object_taxonomies($post, 'names');\n\n\t\t\tforeach($taxonomies as $taxonomy) {\n\n\t\t\t\t$terms = get_the_terms($post->ID, $taxonomy);\n\t\t\t\tif(empty($terms)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t$term_list = wp_list_pluck($terms, 'slug');\n\t\t\t\t$related_query&#91;'tax_query']&#91;] = &#91;\n\t\t\t\t\t'taxonomy' => $taxonomy,\n\t\t\t\t\t'field' => 'slug',\n\t\t\t\t\t'terms' => $term_list,\n\t\t\t\t];\n\t\t\t}\n\n\t\t\tif(count($related_query&#91;'tax_query']) > 1) {\n\t\t\t\t$related_query&#91;'tax_query']&#91;'relation'] = 'OR';\n\t\t\t}\n\n\t\t\treturn $related_query;\n\t\t},\n\t]);\n});<\/code><\/pre><button :class=\"{error: state === &apos;error&apos;, success: state === &apos;success&apos;}\" x-data=\"{state:&apos;&apos;}\" x-on:click=\"navigator.clipboard ? (navigator.clipboard.writeText($el.previousElementSibling.innerText), $el.innerText = `Copied!`, state = &apos;success&apos;) : ($el.innerText = `Can&amp;#039;t copy`, state = &apos;error&apos;)\" class=\"copy\" type=\"button\">Copy<\/button><\/div><\/div>\n\n\n\n<p>That one is a lot more complex, it merges arguments from the original Query Loop block to retain the necessary post type, and post count arguments. The current post is excluded from being a related post, and additional info about the current post is gathered for inclusion as a <code>tax_query<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The WordPress Query Loop block can be used to display posts in the Block Editor. It has settings for a post type, ordering, whether to include sticky posts or not and some filtering capabilities. ska-blocks plugin provides an API to create Query filters for overriding what posts a specific Query Loop block will render. By&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-43","post","type-post","status-publish","format-standard","hentry","category-ska-blocks"],"_links":{"self":[{"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/posts\/43","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/comments?post=43"}],"version-history":[{"count":1,"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/posts\/43\/revisions"}],"predecessor-version":[{"id":214,"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/posts\/43\/revisions\/214"}],"wp:attachment":[{"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/media?parent=43"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/categories?post=43"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ska-blocks.com\/docs\/wp-json\/wp\/v2\/tags?post=43"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}