From 0ae2777ffc50613bbe3a2e6e1b482f98a96998e7 Mon Sep 17 00:00:00 2001 From: Thomas Navarro Date: Sat, 7 Jun 2025 22:40:37 +0200 Subject: [PATCH 1/5] feat: Enhance query filter block with display type options and layout direction - Updated package.json to include @wordpress/env as a dev dependency. - Added new attributes `displayType` and `layoutDirection` to block.json for post-type and taxonomy blocks. - Modified the Edit component for post-type and taxonomy blocks to include SelectControl for display type and ToggleGroupControl for layout direction. - Implemented conditional rendering for select, radio, and checkbox inputs based on the selected display type. - Updated render.php files for post-type and taxonomy blocks to handle new display type and layout direction attributes. - Added styles for radio and checkbox groups in style-index.css to support vertical and horizontal layouts. - refactor: Remove shared styles registration and update label classes in taxonomy render Build changes to render files --- build/post-type/block.json | 8 ++ build/post-type/index-rtl.css | 1 + build/post-type/index.asset.php | 2 +- build/post-type/index.css | 1 + build/post-type/index.js | 2 +- build/post-type/render.php | 46 ++++++++++- build/taxonomy/block.json | 8 ++ build/taxonomy/index-rtl.css | 2 +- build/taxonomy/index.asset.php | 2 +- build/taxonomy/index.css | 2 +- build/taxonomy/index.js | 2 +- build/taxonomy/render.php | 58 ++++++++++++-- inc/namespace.php | 31 ++++++-- src/post-type/block.json | 8 ++ src/post-type/edit.js | 133 ++++++++++++++++++++++++++++---- src/post-type/render.php | 46 ++++++++++- src/taxonomy/block.json | 8 ++ src/taxonomy/edit.js | 132 ++++++++++++++++++++++++++++--- src/taxonomy/index.js | 1 - src/taxonomy/render.php | 58 ++++++++++++-- src/taxonomy/style-index.css | 30 +++++++ 21 files changed, 524 insertions(+), 57 deletions(-) create mode 100644 build/post-type/index-rtl.css create mode 100644 build/post-type/index.css diff --git a/build/post-type/block.json b/build/post-type/block.json index 89b513f..b74dc0c 100644 --- a/build/post-type/block.json +++ b/build/post-type/block.json @@ -56,6 +56,14 @@ "showLabel": { "type": "boolean", "default": true + }, + "displayType": { + "type": "string", + "default": "select" + }, + "layoutDirection": { + "type": "string", + "default": "vertical" } }, "textdomain": "query-filter", diff --git a/build/post-type/index-rtl.css b/build/post-type/index-rtl.css new file mode 100644 index 0000000..5943bcd --- /dev/null +++ b/build/post-type/index-rtl.css @@ -0,0 +1 @@ +@view-transition{navigation:auto}.wp-block-query-filter{display:flex;flex-direction:column;justify-content:stretch}.wp-block-query-filter__checkbox-group,.wp-block-query-filter__radio-group{display:flex;flex-direction:column;gap:.5rem}.wp-block-query-filter__checkbox-group label,.wp-block-query-filter__radio-group label{align-items:center;cursor:pointer;display:flex;gap:.5rem;padding:.25rem 0}.wp-block-query-filter__checkbox-group input,.wp-block-query-filter__radio-group input{margin:0}.wp-block-query-filter__checkbox-group.horizontal,.wp-block-query-filter__radio-group.horizontal{flex-direction:row;flex-wrap:wrap;gap:1rem} diff --git a/build/post-type/index.asset.php b/build/post-type/index.asset.php index ff3a7fb..c114f80 100644 --- a/build/post-type/index.asset.php +++ b/build/post-type/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-i18n'), 'version' => 'ad8227c21a432607ccaf'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-i18n'), 'version' => '9f82697921081e520599'); diff --git a/build/post-type/index.css b/build/post-type/index.css new file mode 100644 index 0000000..5943bcd --- /dev/null +++ b/build/post-type/index.css @@ -0,0 +1 @@ +@view-transition{navigation:auto}.wp-block-query-filter{display:flex;flex-direction:column;justify-content:stretch}.wp-block-query-filter__checkbox-group,.wp-block-query-filter__radio-group{display:flex;flex-direction:column;gap:.5rem}.wp-block-query-filter__checkbox-group label,.wp-block-query-filter__radio-group label{align-items:center;cursor:pointer;display:flex;gap:.5rem;padding:.25rem 0}.wp-block-query-filter__checkbox-group input,.wp-block-query-filter__radio-group input{margin:0}.wp-block-query-filter__checkbox-group.horizontal,.wp-block-query-filter__radio-group.horizontal{flex-direction:row;flex-wrap:wrap;gap:1rem} diff --git a/build/post-type/index.js b/build/post-type/index.js index 67b97d8..4fe7f98 100644 --- a/build/post-type/index.js +++ b/build/post-type/index.js @@ -1 +1 @@ -(()=>{"use strict";const e=window.wp.blocks,l=window.wp.i18n,t=window.wp.blockEditor,r=window.wp.components,o=window.wp.data,s=window.ReactJSXRuntime,i=JSON.parse('{"UU":"query-filter/post-type"}');(0,e.registerBlockType)(i.UU,{edit:function({attributes:e,setAttributes:i,context:n}){const{emptyLabel:a,label:p,showLabel:c}=e,u=(0,o.useSelect)((e=>(e("core").getPostTypes({per_page:100})||[]).filter((e=>e.viewable))||[]),[]);let y=(n.query.postType||"").split(",").map((e=>e.trim()));Array.isArray(n.query.multiple_posts)&&(y=y.concat(n.query.multiple_posts));const _=y.map((e=>u.find((l=>l.slug===e))||{slug:e,name:e}));return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.InspectorControls,{children:(0,s.jsxs)(r.PanelBody,{title:(0,l.__)("Post Type Settings","query-filter"),children:[(0,s.jsx)(r.TextControl,{label:(0,l.__)("Label","query-filter"),value:p,defaultValue:(0,l.__)("Content Type","query-filter"),help:(0,l.__)("If empty then no label will be shown","query-filter"),onChange:e=>i({label:e})}),(0,s.jsx)(r.ToggleControl,{label:(0,l.__)("Show Label","query-filter"),checked:c,onChange:e=>i({showLabel:e})}),(0,s.jsx)(r.TextControl,{label:(0,l.__)("Empty Choice Label","query-filter"),value:a,placeholder:(0,l.__)("All","query-filter"),onChange:e=>i({emptyLabel:e})})]})}),(0,s.jsxs)("div",{...(0,t.useBlockProps)({className:"wp-block-query-filter"}),children:[c&&(0,s.jsx)("label",{className:"wp-block-query-filter-post-type__label wp-block-query-filter__label",children:p||(0,l.__)("Content Type","query-filter")}),(0,s.jsxs)("select",{className:"wp-block-query-filter-post-type__select wp-block-query-filter__select",inert:!0,children:[(0,s.jsx)("option",{children:a||(0,l.__)("All","query-filter")}),_.map((e=>(0,s.jsx)("option",{children:e.name},e.slug)))]})]})]})}})})(); \ No newline at end of file +(()=>{"use strict";const e=window.wp.blocks,l=window.wp.i18n,t=window.wp.blockEditor,r=window.wp.components,o=window.wp.data,i=window.ReactJSXRuntime,a=JSON.parse('{"UU":"query-filter/post-type"}');(0,e.registerBlockType)(a.UU,{edit:function({attributes:e,setAttributes:a,context:n}){const{emptyLabel:s,label:p,showLabel:c,displayType:u,layoutDirection:_}=e,y=(0,o.useSelect)((e=>(e("core").getPostTypes({per_page:100})||[]).filter((e=>e.viewable))||[]),[]);let b=(n.query.postType||"").split(",").map((e=>e.trim()));Array.isArray(n.query.multiple_posts)&&(b=b.concat(n.query.multiple_posts));const d=b.map((e=>y.find((l=>l.slug===e))||{slug:e,name:e}));return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.InspectorControls,{children:(0,i.jsxs)(r.PanelBody,{title:(0,l.__)("Post Type Settings","query-filter"),children:[(0,i.jsx)(r.SelectControl,{label:(0,l.__)("Display Type","query-filter"),value:u,options:[{label:(0,l.__)("Select (Dropdown)","query-filter"),value:"select"},{label:(0,l.__)("Radio (Single Choice)","query-filter"),value:"radio"},{label:(0,l.__)("Checkbox (Multiple Choice)","query-filter"),value:"checkbox"}],onChange:e=>a({displayType:e})}),("radio"===u||"checkbox"===u)&&(0,i.jsxs)(r.__experimentalToggleGroupControl,{label:(0,l.__)("Layout Direction","query-filter"),value:_,onChange:e=>a({layoutDirection:e}),isBlock:!0,__nextHasNoMarginBottom:!0,__next40pxDefaultSize:!0,children:[(0,i.jsx)(r.__experimentalToggleGroupControlOption,{value:"vertical",label:(0,l.__)("Vertical","query-filter")}),(0,i.jsx)(r.__experimentalToggleGroupControlOption,{value:"horizontal",label:(0,l.__)("Horizontal","query-filter")})]}),(0,i.jsx)(r.TextControl,{label:(0,l.__)("Label","query-filter"),value:p,defaultValue:(0,l.__)("Content Type","query-filter"),help:(0,l.__)("If empty then no label will be shown","query-filter"),onChange:e=>a({label:e})}),(0,i.jsx)(r.ToggleControl,{label:(0,l.__)("Show Label","query-filter"),checked:c,onChange:e=>a({showLabel:e})}),(0,i.jsx)(r.TextControl,{label:(0,l.__)("Empty Choice Label","query-filter"),value:s,placeholder:(0,l.__)("All","query-filter"),onChange:e=>a({emptyLabel:e})})]})}),(0,i.jsxs)("div",{...(0,t.useBlockProps)({className:"wp-block-query-filter"}),children:[c&&(0,i.jsx)("label",{className:"wp-block-query-filter-post-type__label wp-block-query-filter__label",children:p||(0,l.__)("Content Type","query-filter")}),"select"===u&&(0,i.jsxs)("select",{className:"wp-block-query-filter-post-type__select wp-block-query-filter__select",inert:!0,children:[(0,i.jsx)("option",{children:s||(0,l.__)("All","query-filter")}),d.map((e=>(0,i.jsx)("option",{children:e.name},e.slug)))]}),"radio"===u&&(0,i.jsxs)("div",{className:"wp-block-query-filter-post-type__radio-group wp-block-query-filter__radio-group"+("horizontal"===_?" horizontal":""),children:[(0,i.jsxs)("label",{children:[(0,i.jsx)("input",{type:"radio",name:"post-type-preview",defaultChecked:!0,inert:!0}),s||(0,l.__)("All","query-filter")]}),d.map((e=>(0,i.jsxs)("label",{children:[(0,i.jsx)("input",{type:"radio",name:"post-type-preview",inert:!0}),e.name]},e.slug)))]}),"checkbox"===u&&(0,i.jsx)("div",{className:"wp-block-query-filter-post-type__checkbox-group wp-block-query-filter__checkbox-group"+("horizontal"===_?" horizontal":""),children:d.map((e=>(0,i.jsxs)("label",{children:[(0,i.jsx)("input",{type:"checkbox",inert:!0}),e.name]},e.slug)))})]})]})}})})(); \ No newline at end of file diff --git a/build/post-type/render.php b/build/post-type/render.php index 70d43f2..2ce8ea8 100644 --- a/build/post-type/render.php +++ b/build/post-type/render.php @@ -2,6 +2,8 @@ global $wp_query; $id = 'query-filter-' . wp_generate_uuid4(); +$display_type = $attributes['displayType'] ?? 'select'; +$layout_direction = $attributes['layoutDirection'] ?? 'vertical'; if ( $block->context['query']['inherit'] ) { $query_var = 'query-post_type'; @@ -45,10 +47,50 @@ - - + + +
+ + + + +
+ +
+ + + name, $selected_types ); + $new_types = $is_checked + ? array_diff( $selected_types, [ $post_type->name ] ) + : array_merge( $selected_types, [ $post_type->name ] ); + $new_types = array_filter( $new_types ); + $checkbox_url = empty( $new_types ) + ? $base_url + : add_query_arg( [ $query_var => implode( ',', $new_types ), $page_var => false, ], $base_url ); + ?> + + +
+ diff --git a/build/taxonomy/block.json b/build/taxonomy/block.json index 6cdb93d..ea0ca35 100644 --- a/build/taxonomy/block.json +++ b/build/taxonomy/block.json @@ -59,6 +59,14 @@ "showLabel": { "type": "boolean", "default": true + }, + "displayType": { + "type": "string", + "default": "select" + }, + "layoutDirection": { + "type": "string", + "default": "vertical" } }, "textdomain": "query-filter", diff --git a/build/taxonomy/index-rtl.css b/build/taxonomy/index-rtl.css index 39bc4f5..5943bcd 100644 --- a/build/taxonomy/index-rtl.css +++ b/build/taxonomy/index-rtl.css @@ -1 +1 @@ -@view-transition{navigation:auto}.wp-block-query-filter{display:flex;flex-direction:column;justify-content:stretch} +@view-transition{navigation:auto}.wp-block-query-filter{display:flex;flex-direction:column;justify-content:stretch}.wp-block-query-filter__checkbox-group,.wp-block-query-filter__radio-group{display:flex;flex-direction:column;gap:.5rem}.wp-block-query-filter__checkbox-group label,.wp-block-query-filter__radio-group label{align-items:center;cursor:pointer;display:flex;gap:.5rem;padding:.25rem 0}.wp-block-query-filter__checkbox-group input,.wp-block-query-filter__radio-group input{margin:0}.wp-block-query-filter__checkbox-group.horizontal,.wp-block-query-filter__radio-group.horizontal{flex-direction:row;flex-wrap:wrap;gap:1rem} diff --git a/build/taxonomy/index.asset.php b/build/taxonomy/index.asset.php index 4b3ef34..efe8b7c 100644 --- a/build/taxonomy/index.asset.php +++ b/build/taxonomy/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-i18n'), 'version' => 'f1456d24ac8e3da497aa'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-i18n'), 'version' => '2f97bf84853a01e2ed52'); diff --git a/build/taxonomy/index.css b/build/taxonomy/index.css index 39bc4f5..5943bcd 100644 --- a/build/taxonomy/index.css +++ b/build/taxonomy/index.css @@ -1 +1 @@ -@view-transition{navigation:auto}.wp-block-query-filter{display:flex;flex-direction:column;justify-content:stretch} +@view-transition{navigation:auto}.wp-block-query-filter{display:flex;flex-direction:column;justify-content:stretch}.wp-block-query-filter__checkbox-group,.wp-block-query-filter__radio-group{display:flex;flex-direction:column;gap:.5rem}.wp-block-query-filter__checkbox-group label,.wp-block-query-filter__radio-group label{align-items:center;cursor:pointer;display:flex;gap:.5rem;padding:.25rem 0}.wp-block-query-filter__checkbox-group input,.wp-block-query-filter__radio-group input{margin:0}.wp-block-query-filter__checkbox-group.horizontal,.wp-block-query-filter__radio-group.horizontal{flex-direction:row;flex-wrap:wrap;gap:1rem} diff --git a/build/taxonomy/index.js b/build/taxonomy/index.js index 5868836..dab208b 100644 --- a/build/taxonomy/index.js +++ b/build/taxonomy/index.js @@ -1 +1 @@ -(()=>{"use strict";const e=window.wp.blocks,l=window.wp.i18n,t=window.wp.blockEditor,o=window.wp.components,n=window.wp.data,r=window.ReactJSXRuntime,a=JSON.parse('{"UU":"query-filter/taxonomy"}');(0,e.registerBlockType)(a.UU,{edit:function({attributes:e,setAttributes:a}){const{taxonomy:i,emptyLabel:s,label:c,showLabel:u}=e,b=(0,n.useSelect)((e=>{const l=(e("core").getTaxonomies({per_page:100})||[]).filter((e=>e.visibility.publicly_queryable));return l&&l.length>0&&!i&&a({taxonomy:l[0].slug,label:l[0].name}),l}),[i]),y=(0,n.useSelect)((e=>e("core").getEntityRecords("taxonomy",i,{number:50})||[]),[i]);return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.InspectorControls,{children:(0,r.jsxs)(o.PanelBody,{title:(0,l.__)("Taxonomy Settings","query-filter"),children:[(0,r.jsx)(o.SelectControl,{label:(0,l.__)("Select Taxonomy","query-filter"),value:i,options:(b||[]).map((e=>({label:e.name,value:e.slug}))),onChange:e=>a({taxonomy:e,label:b.find((l=>l.slug===e)).name})}),(0,r.jsx)(o.TextControl,{label:(0,l.__)("Label","query-filter"),value:c,help:(0,l.__)("If empty then no label will be shown","query-filter"),onChange:e=>a({label:e})}),(0,r.jsx)(o.ToggleControl,{label:(0,l.__)("Show Label","query-filter"),checked:u,onChange:e=>a({showLabel:e})}),(0,r.jsx)(o.TextControl,{label:(0,l.__)("Empty Choice Label","query-filter"),value:s,placeholder:(0,l.__)("All","query-filter"),onChange:e=>a({emptyLabel:e})})]})}),(0,r.jsxs)("div",{...(0,t.useBlockProps)({className:"wp-block-query-filter"}),children:[u&&(0,r.jsx)("label",{className:"wp-block-query-filter-taxonomy__label wp-block-query-filter__label",children:c}),(0,r.jsxs)("select",{className:"wp-block-query-filter-taxonomy__select wp-block-query-filter__select",inert:!0,children:[(0,r.jsx)("option",{children:s||(0,l.__)("All","query-filter")}),y.map((e=>(0,r.jsx)("option",{children:e.name},e.slug)))]})]})]})}})})(); \ No newline at end of file +(()=>{"use strict";const e=window.wp.blocks,l=window.wp.i18n,o=window.wp.blockEditor,t=window.wp.components,r=window.wp.data,a=window.ReactJSXRuntime,i=JSON.parse('{"UU":"query-filter/taxonomy"}');(0,e.registerBlockType)(i.UU,{edit:function({attributes:e,setAttributes:i}){const{taxonomy:n,emptyLabel:s,label:c,showLabel:u,displayType:p,layoutDirection:y}=e,_=(0,r.useSelect)((e=>{const l=(e("core").getTaxonomies({per_page:100})||[]).filter((e=>e.visibility.publicly_queryable));return l&&l.length>0&&!n&&i({taxonomy:l[0].slug,label:l[0].name}),l}),[n]),b=(0,r.useSelect)((e=>e("core").getEntityRecords("taxonomy",n,{number:50})||[]),[n]);return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(o.InspectorControls,{children:(0,a.jsxs)(t.PanelBody,{title:(0,l.__)("Taxonomy Settings","query-filter"),children:[(0,a.jsx)(t.SelectControl,{label:(0,l.__)("Select Taxonomy","query-filter"),value:n,options:(_||[]).map((e=>({label:e.name,value:e.slug}))),onChange:e=>i({taxonomy:e,label:_.find((l=>l.slug===e)).name})}),(0,a.jsx)(t.SelectControl,{label:(0,l.__)("Display Type","query-filter"),value:p,options:[{label:(0,l.__)("Select (Dropdown)","query-filter"),value:"select"},{label:(0,l.__)("Radio (Single Choice)","query-filter"),value:"radio"},{label:(0,l.__)("Checkbox (Multiple Choice)","query-filter"),value:"checkbox"}],onChange:e=>i({displayType:e})}),("radio"===p||"checkbox"===p)&&(0,a.jsxs)(t.__experimentalToggleGroupControl,{label:(0,l.__)("Layout Direction","query-filter"),value:y,onChange:e=>i({layoutDirection:e}),isBlock:!0,__nextHasNoMarginBottom:!0,__next40pxDefaultSize:!0,children:[(0,a.jsx)(t.__experimentalToggleGroupControlOption,{value:"vertical",label:(0,l.__)("Vertical","query-filter")}),(0,a.jsx)(t.__experimentalToggleGroupControlOption,{value:"horizontal",label:(0,l.__)("Horizontal","query-filter")})]}),(0,a.jsx)(t.TextControl,{label:(0,l.__)("Label","query-filter"),value:c,help:(0,l.__)("If empty then no label will be shown","query-filter"),onChange:e=>i({label:e})}),(0,a.jsx)(t.ToggleControl,{label:(0,l.__)("Show Label","query-filter"),checked:u,onChange:e=>i({showLabel:e})}),(0,a.jsx)(t.TextControl,{label:(0,l.__)("Empty Choice Label","query-filter"),value:s,placeholder:(0,l.__)("All","query-filter"),onChange:e=>i({emptyLabel:e})})]})}),(0,a.jsxs)("div",{...(0,o.useBlockProps)({className:"wp-block-query-filter"}),children:[u&&(0,a.jsx)("label",{className:"wp-block-query-filter-taxonomy__label wp-block-query-filter__label",children:c}),"select"===p&&(0,a.jsxs)("select",{className:"wp-block-query-filter-taxonomy__select wp-block-query-filter__select",inert:!0,children:[(0,a.jsx)("option",{children:s||(0,l.__)("All","query-filter")}),b.map((e=>(0,a.jsx)("option",{children:e.name},e.slug)))]}),"radio"===p&&(0,a.jsxs)("div",{className:"wp-block-query-filter-taxonomy__radio-group wp-block-query-filter__radio-group"+("horizontal"===y?" horizontal":""),children:[(0,a.jsxs)("label",{children:[(0,a.jsx)("input",{type:"radio",name:"taxonomy-preview",defaultChecked:!0,inert:!0}),s||(0,l.__)("All","query-filter")]}),b.map((e=>(0,a.jsxs)("label",{children:[(0,a.jsx)("input",{type:"radio",name:"taxonomy-preview",inert:!0}),e.name]},e.slug)))]}),"checkbox"===p&&(0,a.jsx)("div",{className:"wp-block-query-filter-taxonomy__checkbox-group wp-block-query-filter__checkbox-group"+("horizontal"===y?" horizontal":""),children:b.map((e=>(0,a.jsxs)("label",{children:[(0,a.jsx)("input",{type:"checkbox",inert:!0}),e.name]},e.slug)))})]})]})}})})(); \ No newline at end of file diff --git a/build/taxonomy/render.php b/build/taxonomy/render.php index 97258b4..1c2ea5d 100644 --- a/build/taxonomy/render.php +++ b/build/taxonomy/render.php @@ -4,6 +4,8 @@ } $id = 'query-filter-' . wp_generate_uuid4(); +$display_type = $attributes['displayType'] ?? 'select'; +$layout_direction = $attributes['layoutDirection'] ?? 'vertical'; $taxonomy = get_taxonomy( $attributes['taxonomy'] ); @@ -30,13 +32,55 @@ ?>
'wp-block-query-filter' ] ); ?> data-wp-interactive="query-filter" data-wp-context="{}"> -
diff --git a/inc/namespace.php b/inc/namespace.php index 6457f8f..34e3820 100644 --- a/inc/namespace.php +++ b/inc/namespace.php @@ -73,7 +73,7 @@ function filter_query_loop_block_query_vars( array $query, \WP_Block $block, int /** * Fires after the query variable object is created, but before the actual query is run. * - * @param WP_Query $query The WP_Query instance (passed by reference). + * @param WP_Query $query The WP_Query instance (passed by reference). */ function pre_get_posts_transpose_query_vars( WP_Query $query ) : void { $query_id = $query->get( 'query_id', null ); @@ -106,11 +106,28 @@ function pre_get_posts_transpose_query_vars( WP_Query $query ) : void { // Handle taxonomies specifically. if ( get_taxonomy( $key ) ) { $tax_query['relation'] = 'AND'; - $tax_query[] = [ - 'taxonomy' => $key, - 'terms' => [ $value ], - 'field' => 'slug', - ]; + + // Handle multiple values separated by commas (for checkbox mode) + $values = explode( ',', $value ); + $values = array_map( 'trim', $values ); + $values = array_filter( $values ); + + if ( count( $values ) > 1 ) { + // Multiple values: OR logic (posts with ANY of these terms) + $tax_query[] = [ + 'taxonomy' => $key, + 'terms' => $values, + 'field' => 'slug', + 'operator' => 'IN', // This creates OR logic + ]; + } else { + // Single value: normal behavior + $tax_query[] = [ + 'taxonomy' => $key, + 'terms' => $values, + 'field' => 'slug', + ]; + } } else { // Other options should map directly to query vars. $key = sanitize_key( $key ); @@ -176,7 +193,7 @@ function render_block_search( string $block_content, array $block, \WP_Block $in ? sprintf( 'query-%d-s', $instance->context['queryId'] ?? 0 ) : 'query-s'; - $action = str_replace( '/page/'. get_query_var( 'paged', 1 ), '', add_query_arg( [ $query_var => '' ] ) ); + $action = str_replace( '/page/' . get_query_var( 'paged', 1 ), '', add_query_arg( [ $query_var => '' ] ) ); // Note sanitize_text_field trims whitespace from start/end of string causing unexpected behaviour. $value = wp_unslash( $_GET[ $query_var ] ?? '' ); diff --git a/src/post-type/block.json b/src/post-type/block.json index 0d1af2e..e768992 100644 --- a/src/post-type/block.json +++ b/src/post-type/block.json @@ -51,6 +51,14 @@ "showLabel": { "type": "boolean", "default": true + }, + "displayType": { + "type": "string", + "default": "select" + }, + "layoutDirection": { + "type": "string", + "default": "vertical" } }, "textdomain": "query-filter", diff --git a/src/post-type/edit.js b/src/post-type/edit.js index 5bbd52c..9d1c88b 100644 --- a/src/post-type/edit.js +++ b/src/post-type/edit.js @@ -1,10 +1,18 @@ import { __ } from '@wordpress/i18n'; import { useBlockProps, InspectorControls } from '@wordpress/block-editor'; -import { PanelBody, TextControl, ToggleControl } from '@wordpress/components'; +import { + PanelBody, + TextControl, + ToggleControl, + SelectControl, + __experimentalToggleGroupControl as ToggleGroupControl, + __experimentalToggleGroupControlOption as ToggleGroupControlOption, +} from '@wordpress/components'; import { useSelect } from '@wordpress/data'; export default function Edit( { attributes, setAttributes, context } ) { - const { emptyLabel, label, showLabel } = attributes; + const { emptyLabel, label, showLabel, displayType, layoutDirection } = + attributes; const allPostTypes = useSelect( ( select ) => { return ( @@ -38,6 +46,58 @@ export default function Edit( { attributes, setAttributes, context } ) { <> + + setAttributes( { displayType } ) + } + /> + { ( displayType === 'radio' || + displayType === 'checkbox' ) && ( + + setAttributes( { layoutDirection } ) + } + isBlock + __nextHasNoMarginBottom + __next40pxDefaultSize + > + + + + ) } ) } - + { displayType === 'select' && ( + + ) } + { displayType === 'radio' && ( +
+ + { postTypes.map( ( type ) => ( + + ) ) } +
+ ) } + { displayType === 'checkbox' && ( +
+ { postTypes.map( ( type ) => ( + + ) ) } +
+ ) } ); diff --git a/src/post-type/render.php b/src/post-type/render.php index 70d43f2..2ce8ea8 100644 --- a/src/post-type/render.php +++ b/src/post-type/render.php @@ -2,6 +2,8 @@ global $wp_query; $id = 'query-filter-' . wp_generate_uuid4(); +$display_type = $attributes['displayType'] ?? 'select'; +$layout_direction = $attributes['layoutDirection'] ?? 'vertical'; if ( $block->context['query']['inherit'] ) { $query_var = 'query-post_type'; @@ -45,10 +47,50 @@ - - + + +
+ + + + +
+ +
+ + + name, $selected_types ); + $new_types = $is_checked + ? array_diff( $selected_types, [ $post_type->name ] ) + : array_merge( $selected_types, [ $post_type->name ] ); + $new_types = array_filter( $new_types ); + $checkbox_url = empty( $new_types ) + ? $base_url + : add_query_arg( [ $query_var => implode( ',', $new_types ), $page_var => false, ], $base_url ); + ?> + + +
+ diff --git a/src/taxonomy/block.json b/src/taxonomy/block.json index 1f1a331..f0992b4 100644 --- a/src/taxonomy/block.json +++ b/src/taxonomy/block.json @@ -54,6 +54,14 @@ "showLabel": { "type": "boolean", "default": true + }, + "displayType": { + "type": "string", + "default": "select" + }, + "layoutDirection": { + "type": "string", + "default": "vertical" } }, "textdomain": "query-filter", diff --git a/src/taxonomy/edit.js b/src/taxonomy/edit.js index 5562901..205a77a 100644 --- a/src/taxonomy/edit.js +++ b/src/taxonomy/edit.js @@ -5,11 +5,20 @@ import { SelectControl, TextControl, ToggleControl, + __experimentalToggleGroupControl as ToggleGroupControl, + __experimentalToggleGroupControlOption as ToggleGroupControlOption, } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; export default function Edit( { attributes, setAttributes } ) { - const { taxonomy, emptyLabel, label, showLabel } = attributes; + const { + taxonomy, + emptyLabel, + label, + showLabel, + displayType, + layoutDirection, + } = attributes; const taxonomies = useSelect( ( select ) => { @@ -60,6 +69,58 @@ export default function Edit( { attributes, setAttributes } ) { } ) } /> + + setAttributes( { displayType } ) + } + /> + { ( displayType === 'radio' || + displayType === 'checkbox' ) && ( + + setAttributes( { layoutDirection } ) + } + isBlock + __nextHasNoMarginBottom + __next40pxDefaultSize + > + + + + ) } ) } - + { displayType === 'select' && ( + + ) } + { displayType === 'radio' && ( +
+ + { terms.map( ( term ) => ( + + ) ) } +
+ ) } + { displayType === 'checkbox' && ( +
+ { terms.map( ( term ) => ( + + ) ) } +
+ ) } ); diff --git a/src/taxonomy/index.js b/src/taxonomy/index.js index 30d8967..0157b8f 100644 --- a/src/taxonomy/index.js +++ b/src/taxonomy/index.js @@ -1,7 +1,6 @@ import { registerBlockType } from '@wordpress/blocks'; import Edit from './edit'; import metadata from './block.json'; -import './style-index.css'; registerBlockType( metadata.name, { /** diff --git a/src/taxonomy/render.php b/src/taxonomy/render.php index 97258b4..1c2ea5d 100644 --- a/src/taxonomy/render.php +++ b/src/taxonomy/render.php @@ -4,6 +4,8 @@ } $id = 'query-filter-' . wp_generate_uuid4(); +$display_type = $attributes['displayType'] ?? 'select'; +$layout_direction = $attributes['layoutDirection'] ?? 'vertical'; $taxonomy = get_taxonomy( $attributes['taxonomy'] ); @@ -30,13 +32,55 @@ ?>
'wp-block-query-filter' ] ); ?> data-wp-interactive="query-filter" data-wp-context="{}"> -
diff --git a/src/taxonomy/style-index.css b/src/taxonomy/style-index.css index 621fee1..29f189a 100644 --- a/src/taxonomy/style-index.css +++ b/src/taxonomy/style-index.css @@ -7,3 +7,33 @@ flex-direction: column; justify-content: stretch; } + +/* Radio group styles */ +.wp-block-query-filter__radio-group, +.wp-block-query-filter__checkbox-group { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.wp-block-query-filter__radio-group label, +.wp-block-query-filter__checkbox-group label { + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + padding: 0.25rem 0; +} + +.wp-block-query-filter__radio-group input, +.wp-block-query-filter__checkbox-group input { + margin: 0; +} + +/* Horizontal layout option */ +.wp-block-query-filter__radio-group.horizontal, +.wp-block-query-filter__checkbox-group.horizontal { + flex-direction: row; + flex-wrap: wrap; + gap: 1rem; +} From b0a0c79370a9c25a3dafdf1c840574494f046298 Mon Sep 17 00:00:00 2001 From: goldenapples Date: Wed, 4 Mar 2026 15:23:55 -0500 Subject: [PATCH 2/5] Use core wp_parse_list method for parsing list --- inc/namespace.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/inc/namespace.php b/inc/namespace.php index 34e3820..162b5a5 100644 --- a/inc/namespace.php +++ b/inc/namespace.php @@ -108,9 +108,7 @@ function pre_get_posts_transpose_query_vars( WP_Query $query ) : void { $tax_query['relation'] = 'AND'; // Handle multiple values separated by commas (for checkbox mode) - $values = explode( ',', $value ); - $values = array_map( 'trim', $values ); - $values = array_filter( $values ); + $values = wp_parse_list( $value ); if ( count( $values ) > 1 ) { // Multiple values: OR logic (posts with ANY of these terms) From f642d79e05056889d54cf94027666fe9a6e973b1 Mon Sep 17 00:00:00 2001 From: goldenapples Date: Wed, 4 Mar 2026 15:31:50 -0500 Subject: [PATCH 3/5] Pass "true" for strict comparison in in_array call --- build/post-type/render.php | 2 +- build/taxonomy/render.php | 2 +- src/post-type/render.php | 2 +- src/taxonomy/render.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/post-type/render.php b/build/post-type/render.php index 2ce8ea8..d6e3b1c 100644 --- a/build/post-type/render.php +++ b/build/post-type/render.php @@ -77,7 +77,7 @@ ?> name, $selected_types ); + $is_checked = in_array( $post_type->name, $selected_types, true ); $new_types = $is_checked ? array_diff( $selected_types, [ $post_type->name ] ) : array_merge( $selected_types, [ $post_type->name ] ); diff --git a/build/taxonomy/render.php b/build/taxonomy/render.php index 1c2ea5d..e80208b 100644 --- a/build/taxonomy/render.php +++ b/build/taxonomy/render.php @@ -67,7 +67,7 @@ ?> slug, $selected_terms ); + $is_checked = in_array( $term->slug, $selected_terms, true ); $new_terms = $is_checked ? array_diff( $selected_terms, [ $term->slug ] ) : array_merge( $selected_terms, [ $term->slug ] ); diff --git a/src/post-type/render.php b/src/post-type/render.php index 2ce8ea8..d6e3b1c 100644 --- a/src/post-type/render.php +++ b/src/post-type/render.php @@ -77,7 +77,7 @@ ?> name, $selected_types ); + $is_checked = in_array( $post_type->name, $selected_types, true ); $new_types = $is_checked ? array_diff( $selected_types, [ $post_type->name ] ) : array_merge( $selected_types, [ $post_type->name ] ); diff --git a/src/taxonomy/render.php b/src/taxonomy/render.php index 1c2ea5d..e80208b 100644 --- a/src/taxonomy/render.php +++ b/src/taxonomy/render.php @@ -67,7 +67,7 @@ ?> slug, $selected_terms ); + $is_checked = in_array( $term->slug, $selected_terms, true ); $new_terms = $is_checked ? array_diff( $selected_terms, [ $term->slug ] ) : array_merge( $selected_terms, [ $term->slug ] ); From 862cfa7ef409c385c7341bf95a51496c20e1513e Mon Sep 17 00:00:00 2001 From: goldenapples Date: Wed, 25 Mar 2026 10:06:12 -0400 Subject: [PATCH 4/5] Unset layout direction if type is "select" --- src/post-type/edit.js | 15 ++++++++++++--- src/taxonomy/edit.js | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/post-type/edit.js b/src/post-type/edit.js index 9d1c88b..4a68bc9 100644 --- a/src/post-type/edit.js +++ b/src/post-type/edit.js @@ -72,9 +72,18 @@ export default function Edit( { attributes, setAttributes, context } ) { value: 'checkbox', }, ] } - onChange={ ( displayType ) => - setAttributes( { displayType } ) - } + onChange={ ( nextDisplayType ) => { + if ( nextDisplayType === 'select' ) { + setAttributes( { + displayType: nextDisplayType, + layoutDirection: undefined, + } ); + } else { + setAttributes( { + displayType: nextDisplayType, + } ); + } + } } /> { ( displayType === 'radio' || displayType === 'checkbox' ) && ( diff --git a/src/taxonomy/edit.js b/src/taxonomy/edit.js index 205a77a..4855e3d 100644 --- a/src/taxonomy/edit.js +++ b/src/taxonomy/edit.js @@ -95,9 +95,18 @@ export default function Edit( { attributes, setAttributes } ) { value: 'checkbox', }, ] } - onChange={ ( displayType ) => - setAttributes( { displayType } ) - } + onChange={ ( nextDisplayType ) => { + if ( nextDisplayType === 'select' ) { + setAttributes( { + displayType: nextDisplayType, + layoutDirection: undefined, + } ); + } else { + setAttributes( { + displayType: nextDisplayType, + } ); + } + } } /> { ( displayType === 'radio' || displayType === 'checkbox' ) && ( From b31e55876bab801dedef4f1796e5fea38d088661 Mon Sep 17 00:00:00 2001 From: goldenapples Date: Wed, 25 Mar 2026 10:34:13 -0400 Subject: [PATCH 5/5] Clarify description of filter boolean AND/OR logic --- inc/namespace.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/inc/namespace.php b/inc/namespace.php index 162b5a5..63a0ecb 100644 --- a/inc/namespace.php +++ b/inc/namespace.php @@ -105,18 +105,20 @@ function pre_get_posts_transpose_query_vars( WP_Query $query ) : void { // Handle taxonomies specifically. if ( get_taxonomy( $key ) ) { + // If multiple taxonomy filters are selected, ALL of them must match. $tax_query['relation'] = 'AND'; // Handle multiple values separated by commas (for checkbox mode) $values = wp_parse_list( $value ); if ( count( $values ) > 1 ) { - // Multiple values: OR logic (posts with ANY of these terms) + // If multiple terms in a taxonomy are selected, posts with + // ANY of the selected terms should be returned. $tax_query[] = [ 'taxonomy' => $key, 'terms' => $values, 'field' => 'slug', - 'operator' => 'IN', // This creates OR logic + 'operator' => 'IN', ]; } else { // Single value: normal behavior