Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<exclude name="Generic.Commenting" />
<exclude name="Squiz.Commenting.FileComment.Missing" />
<exclude name="NormalizedArrays.Arrays.ArrayBraceSpacing" />

<!-- Requiring inline tags to be on newlines makes render.php partials harder to read. -->
<exclude name="Squiz.PHP.EmbeddedPhp.ContentBeforeOpen" />
<exclude name="Squiz.PHP.EmbeddedPhp.ContentAfterEnd" />
</rule>

<rule ref="HM.Files.NamespaceDirectoryName.NoIncDirectory">
Expand Down
37 changes: 30 additions & 7 deletions inc/namespace.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -105,12 +105,29 @@ 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';
$tax_query[] = [
'taxonomy' => $key,
'terms' => [ $value ],
'field' => 'slug',
];

// Handle multiple values separated by commas (for checkbox mode)
$values = wp_parse_list( $value );

if ( count( $values ) > 1 ) {
// 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',
];
} 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 );
Expand All @@ -119,6 +136,12 @@ function pre_get_posts_transpose_query_vars( WP_Query $query ) : void {
continue;
}

// post_type accepts multiple comma-separated values in checkbox mode.
// Parse as list so WP_Query returns results from any selected post_type.
if ( $key === 'post_type' ) {
$value = wp_parse_list( $value );
}

$query->set(
$key,
$value
Expand Down Expand Up @@ -176,7 +199,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.
// phpcs:ignore HM.Security.ValidatedSanitizedInput.InputNotSanitized
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style --fix",
"lint:js": "wp-scripts lint-js",
"lint:php": "composer phpcs",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Human Made Limited",
Expand Down
10 changes: 9 additions & 1 deletion src/post-type/block.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"apiVersion": 3,
"name": "query-filter/post-type",
"version": "0.1.0",
"title": "Post Type Filter",
Expand Down Expand Up @@ -51,6 +51,14 @@
"showLabel": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"default": "select"
},
"layoutDirection": {
"type": "string",
"default": "vertical"
}
},
"textdomain": "query-filter",
Expand Down
142 changes: 129 additions & 13 deletions src/post-type/edit.js
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down Expand Up @@ -38,6 +46,67 @@ export default function Edit( { attributes, setAttributes, context } ) {
<>
<InspectorControls>
<PanelBody title={ __( 'Post Type Settings', 'query-filter' ) }>
<SelectControl
label={ __( 'Display Type', 'query-filter' ) }
value={ displayType }
options={ [
Comment thread
kadamwhite marked this conversation as resolved.
{
label: __(
'Select (Dropdown)',
'query-filter'
),
value: 'select',
},
{
label: __(
'Radio (Single Choice)',
'query-filter'
),
value: 'radio',
},
{
label: __(
'Checkbox (Multiple Choice)',
'query-filter'
),
value: 'checkbox',
},
] }
onChange={ ( nextDisplayType ) => {
if ( nextDisplayType === 'select' ) {
setAttributes( {
displayType: nextDisplayType,
layoutDirection: undefined,
} );
} else {
setAttributes( {
displayType: nextDisplayType,
} );
}
} }
/>
{ ( displayType === 'radio' ||
displayType === 'checkbox' ) && (
<ToggleGroupControl
Comment thread
kadamwhite marked this conversation as resolved.
label={ __( 'Layout Direction', 'query-filter' ) }
value={ layoutDirection }
onChange={ ( layoutDirection ) =>
setAttributes( { layoutDirection } )
}
isBlock
__nextHasNoMarginBottom
__next40pxDefaultSize
>
<ToggleGroupControlOption
value="vertical"
label={ __( 'Vertical', 'query-filter' ) }
/>
<ToggleGroupControlOption
value="horizontal"
label={ __( 'Horizontal', 'query-filter' ) }
/>
</ToggleGroupControl>
) }
<TextControl
label={ __( 'Label', 'query-filter' ) }
value={ label }
Expand Down Expand Up @@ -71,17 +140,64 @@ export default function Edit( { attributes, setAttributes, context } ) {
{ label || __( 'Content Type', 'query-filter' ) }
</label>
) }
<select
className="wp-block-query-filter-post-type__select wp-block-query-filter__select"
inert
>
<option>
{ emptyLabel || __( 'All', 'query-filter' ) }
</option>
{ postTypes.map( ( type ) => (
<option key={ type.slug }>{ type.name }</option>
) ) }
</select>
{ displayType === 'select' && (
<select
className="wp-block-query-filter-post-type__select wp-block-query-filter__select"
inert
>
<option>
{ emptyLabel || __( 'All', 'query-filter' ) }
</option>
{ postTypes.map( ( type ) => (
<option key={ type.slug }>{ type.name }</option>
) ) }
</select>
) }
{ displayType === 'radio' && (
<div
className={ `wp-block-query-filter-post-type__radio-group wp-block-query-filter__radio-group${
layoutDirection === 'horizontal'
? ' horizontal'
: ''
}` }
>
<label>
<input
type="radio"
name="post-type-preview"
defaultChecked
inert
/>
{ emptyLabel || __( 'All', 'query-filter' ) }
</label>
{ postTypes.map( ( type ) => (
<label key={ type.slug }>
<input
type="radio"
name="post-type-preview"
inert
/>
{ type.name }
</label>
) ) }
</div>
) }
{ displayType === 'checkbox' && (
<div
className={ `wp-block-query-filter-post-type__checkbox-group wp-block-query-filter__checkbox-group${
layoutDirection === 'horizontal'
? ' horizontal'
: ''
}` }
>
{ postTypes.map( ( type ) => (
<label key={ type.slug }>
<input type="checkbox" inert />
{ type.name }
</label>
) ) }
</div>
) }
</div>
</>
);
Expand Down
53 changes: 51 additions & 2 deletions src/post-type/render.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
<?php
/**
* @var array $attributes Block attributes array.
* @var WP_Block $block WP_Block instance being rendered.
*/

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';
Expand Down Expand Up @@ -45,10 +52,52 @@
<label class="wp-block-query-filter-post-type__label wp-block-query-filter__label<?php echo $attributes['showLabel'] ? '' : ' screen-reader-text' ?>" for="<?php echo esc_attr( $id ); ?>">
<?php echo esc_html( $attributes['label'] ?? __( 'Content Type', 'query-filter' ) ); ?>
</label>
<select class="wp-block-query-filter-post-type__select wp-block-query-filter__select" id="<?php echo esc_attr( $id ); ?>" data-wp-on--change="actions.navigate">

<?php if ( $display_type === 'select' ) : ?>
<select class="wp-block-query-filter-post-type__select wp-block-query-filter__select" id="<?php echo esc_attr( $id ); ?>" data-wp-on--change="actions.navigate">
<option value="<?php echo esc_attr( $base_url ) ?>"><?php echo esc_html( $attributes['emptyLabel'] ?: __( 'All', 'query-filter' ) ); ?></option>
<?php foreach ( $post_types as $post_type ) : ?>
<option value="<?php echo esc_attr( add_query_arg( [ $query_var => $post_type->name, $page_var => false ], $base_url ) ) ?>" <?php selected( $post_type->name, sanitize_key( wp_unslash( $_GET[ $query_var ] ?? '' ) ) ); ?>><?php echo esc_html( $post_type->label ); ?></option>
<?php endforeach; ?>
</select>
</select>
<?php elseif ( $display_type === 'radio' ) : ?>
<div class="wp-block-query-filter-post-type__radio-group wp-block-query-filter__radio-group<?php echo $layout_direction === 'horizontal' ? ' horizontal' : ''; ?>">
<label>
<input type="radio" id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $id ); ?>" value="<?php echo esc_attr( $base_url ); ?>" data-wp-on--change="actions.navigate" <?php checked( empty( $_GET[ $query_var ] ) ); ?> />
<?php echo esc_html( $attributes['emptyLabel'] ?: __( 'All', 'query-filter' ) ); ?>
</label>
<?php foreach ( $post_types as $post_type ) : ?>
<label>
<input type="radio" name="<?php echo esc_attr( $id ); ?>" value="<?php
echo esc_attr( add_query_arg( [ $query_var => $post_type->name, $page_var => false ], $base_url ) );
?>" data-wp-on--change="actions.navigate" <?php checked( $post_type->name, sanitize_key( wp_unslash( $_GET[ $query_var ] ?? '' ) ) ); ?> />
<?php echo esc_html( $post_type->label ); ?>
</label>
<?php endforeach; ?>
</div>
<?php elseif ( $display_type === 'checkbox' ) : ?>
<div class="wp-block-query-filter-post-type__checkbox-group wp-block-query-filter__checkbox-group<?php echo $layout_direction === 'horizontal' ? ' horizontal' : ''; ?>">
<?php
$selected_types = isset( $_GET[ $query_var ] )
? array_map( 'sanitize_key', explode( ',', sanitize_text_field( wp_unslash( $_GET[ $query_var ] ) ) ) )
: [];
?>
<?php foreach ( $post_types as $post_type ) : ?>
<?php
$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 ] );
$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 );
?>
<label>
<input type="checkbox" value="<?php echo esc_attr( $checkbox_url ); ?>" data-wp-on--change="actions.navigate" <?php checked( $is_checked ); ?> />
<?php echo esc_html( $post_type->label ); ?>
</label>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
8 changes: 8 additions & 0 deletions src/taxonomy/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@
"showLabel": {
"type": "boolean",
"default": true
},
"displayType": {
"type": "string",
"default": "select"
},
"layoutDirection": {
"type": "string",
"default": "vertical"
}
},
"textdomain": "query-filter",
Expand Down
Loading