Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Product Collection - Add Created filter in inspector controls #11562

Merged
merged 13 commits into from
Nov 8, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/js/blocks/product-collection/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const DEFAULT_QUERY: ProductCollectionQuery = {
woocommerceStockStatus: getDefaultStockStatuses(),
woocommerceAttributes: [],
woocommerceHandPickedProducts: [],
timeFrame: undefined,
};

export const DEFAULT_ATTRIBUTES: Partial< ProductCollectionAttributes > = {
Expand Down Expand Up @@ -86,4 +87,5 @@ export const DEFAULT_FILTERS: Partial< ProductCollectionQuery > = {
woocommerceAttributes: [],
taxQuery: DEFAULT_QUERY.taxQuery,
woocommerceHandPickedProducts: [],
timeFrame: undefined,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* External dependencies
*/
import { __, _x } from '@wordpress/i18n';
import {
Flex,
FlexItem,
RadioControl,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - Ignoring because `__experimentalToggleGroupControl` is not yet in the type definitions.
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToggleGroupControl as ToggleGroupControl,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - Ignoring because `__experimentalToggleGroupControlOption` is not yet in the type definitions.
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
// @ts-expect-error Using experimental features
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { ETimeFrameOperator, QueryControlProps } from '../types';

const CreatedControl = ( props: QueryControlProps ) => {
const { query, setQueryAttribute } = props;
const { timeFrame } = query;

return (
<ToolsPanelItem
label={ __( 'Created', 'woo-gutenberg-products-block' ) }
hasValue={ () => timeFrame?.operator && timeFrame?.value }
onDeselect={ () => {
setQueryAttribute( {
timeFrame: undefined,
} );
} }
>
<Flex direction="column" gap={ 3 }>
<FlexItem>
<ToggleGroupControl
label={ __(
'Created',
'woo-gutenberg-products-block'
) }
isBlock
onChange={ ( value: ETimeFrameOperator ) => {
setQueryAttribute( {
timeFrame: {
...timeFrame,
operator: value,
},
} );
} }
value={ timeFrame?.operator || ETimeFrameOperator.IN }
>
<ToggleGroupControlOption
value={ ETimeFrameOperator.IN }
label={ _x(
'Within',
'Product Collection query operator',
'woo-gutenberg-products-block'
) }
/>
<ToggleGroupControlOption
value={ ETimeFrameOperator.NOT_IN }
label={ _x(
'Before',
'Product Collection query operator',
'woo-gutenberg-products-block'
) }
/>
</ToggleGroupControl>
</FlexItem>
<FlexItem>
<RadioControl
onChange={ ( value: string ) => {
setQueryAttribute( {
timeFrame: {
operator: ETimeFrameOperator.IN,
...timeFrame,
value,
},
} );
} }
options={ [
{
label: 'last 24 hours',
value: '-1 day',
},
{
label: 'last 7 days',
value: '-7 days',
},
{
label: 'last 30 days',
value: '-30 days',
},
{
label: 'last 3 months',
value: '-3 months',
},
] }
selected={ timeFrame?.value }
/>
</FlexItem>
</Flex>
</ToolsPanelItem>
);
};

export default CreatedControl;
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import AttributesControl from './attributes-control';
import TaxonomyControls from './taxonomy-controls';
import HandPickedProductsControl from './hand-picked-products-control';
import LayoutOptionsControl from './layout-options-control';
import CreatedControl from './created-control';

const ProductCollectionInspectorControls = (
props: BlockEditProps< ProductCollectionAttributes >
Expand Down Expand Up @@ -98,6 +99,7 @@ const ProductCollectionInspectorControls = (
<KeywordControl { ...queryControlProps } />
<AttributesControl { ...queryControlProps } />
<TaxonomyControls { ...queryControlProps } />
<CreatedControl { ...queryControlProps } />
</ToolsPanel>
) : null }
<ProductCollectionFeedbackPrompt />
Expand Down
11 changes: 11 additions & 0 deletions assets/js/blocks/product-collection/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ export interface ProductCollectionDisplayLayout {
shrinkColumns?: boolean;
}

export enum ETimeFrameOperator {
IN = 'in',
NOT_IN = 'not-in',
}

export interface TimeFrame {
operator?: ETimeFrameOperator;
value?: string;
}

export interface ProductCollectionQuery {
exclude: string[];
inherit: boolean | null;
Expand All @@ -39,6 +49,7 @@ export interface ProductCollectionQuery {
postType: string;
search: string;
taxQuery: Record< string, number[] >;
timeFrame: TimeFrame | undefined;
woocommerceOnSale: boolean;
/**
* Filter products by their stock status.
Expand Down
41 changes: 40 additions & 1 deletion src/BlockTypes/ProductCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ public function update_rest_query_in_editor( $args, $request ): array {
$stock_status = $request->get_param( 'woocommerceStockStatus' );
$product_attributes = $request->get_param( 'woocommerceAttributes' );
$handpicked_products = $request->get_param( 'woocommerceHandPickedProducts' );
$time_frame = $request->get_param( 'timeFrame' );
// This argument is required for the tests to PHP Unit Tests to run correctly.
// Most likely this argument is being accessed in the test environment image.
$args['author'] = '';
Expand All @@ -219,6 +220,7 @@ public function update_rest_query_in_editor( $args, $request ): array {
'stock_status' => $stock_status,
'product_attributes' => $product_attributes,
'handpicked_products' => $handpicked_products,
'timeFrame' => $time_frame,
)
);
}
Expand Down Expand Up @@ -305,6 +307,7 @@ private function get_final_frontend_query( $query, $page = 1, $is_exclude_applie
$product_attributes = $query['woocommerceAttributes'] ?? [];
$taxonomies_query = $this->get_filter_by_taxonomies_query( $query['tax_query'] ?? [] );
$handpicked_products = $query['woocommerceHandPickedProducts'] ?? [];
$time_frame = $query['timeFrame'] ?? null;

$final_query = $this->get_final_query_args(
$common_query_values,
Expand All @@ -315,6 +318,7 @@ private function get_final_frontend_query( $query, $page = 1, $is_exclude_applie
'product_attributes' => $product_attributes,
'taxonomies_query' => $taxonomies_query,
'handpicked_products' => $handpicked_products,
'timeFrame' => $time_frame,
),
$is_exclude_applied_filters
);
Expand All @@ -338,11 +342,12 @@ private function get_final_query_args( $common_query_values, $query, $is_exclude
$attributes_query = $this->get_product_attributes_query( $query['product_attributes'] );
$taxonomies_query = $query['taxonomies_query'] ?? [];
$tax_query = $this->merge_tax_queries( $visibility_query, $attributes_query, $taxonomies_query );
$date_query = $this->get_date_query( $query['timeFrame'] ?? [] );

// We exclude applied filters to generate product ids for the filter blocks.
$applied_filters_query = $is_exclude_applied_filters ? [] : $this->get_queries_by_applied_filters();

$merged_query = $this->merge_queries( $common_query_values, $orderby_query, $on_sale_query, $stock_query, $tax_query, $applied_filters_query );
$merged_query = $this->merge_queries( $common_query_values, $orderby_query, $on_sale_query, $stock_query, $tax_query, $applied_filters_query, $date_query );

return $this->filter_query_to_only_include_ids( $merged_query, $handpicked_products );
}
Expand Down Expand Up @@ -959,4 +964,38 @@ function( $rating ) use ( $product_visibility_terms ) {
),
);
}

/**
* Constructs a date query for product filtering based on a specified time frame.
*
* @param array $time_frame {
* Associative array with 'operator' (in or not-in) and 'value' (date string).
*
* @type string $operator Determines the inclusion or exclusion of the date range.
* @type string $value The date around which the range is applied.
* }
* @return array Date query array; empty if parameters are invalid.
*/
private function get_date_query( array $time_frame ) : array {
// Validate time_frame elements.
if ( empty( $time_frame['operator'] ) || empty( $time_frame['value'] ) ) {
return array();
}

// Determine the query operator based on the 'operator' value.
$query_operator = 'in' === $time_frame['operator'] ? 'after' : 'before';

// Construct and return the date query.
return array(
'date_query' => array(
array(
'column' => 'post_date_gmt',
$query_operator => $time_frame['value'],
'inclusive' => true,
),
),
);
}


}