Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TECH-84: [wp-conditional-blocks] Basic Conditions #75

Merged
merged 16 commits into from
May 6, 2024
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
13 changes: 0 additions & 13 deletions blocks/condition/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,6 @@
"attributes": {
"condition": {
"type": "string"
},
"custom": {
"type": "string"
},
"post": {
"type": "string"
},
"query": {
"type": "string"
},
"index": {
"type": "object",
"default": { "": "" }
}
}
}
127 changes: 38 additions & 89 deletions blocks/condition/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { useEffect, useState } from '@wordpress/element';
import { InnerBlocks, InspectorControls, useBlockProps } from '@wordpress/block-editor';
import {
PanelBody, PanelRow, SelectControl, TextControl,
PanelBody, PanelRow, SelectControl,
} from '@wordpress/components';

import { useParentBlock } from '@alleyinteractive/block-editor-tools';

interface EditProps {
attributes: {
condition?: string;
custom?: string;
post?: string;
query?: string;
index?: object;
};
setAttributes: (attributes: any) => void;
clientId: string;
}

// Structure for the SelectControl options.
interface Conditions {
value: string;
label: string;
}

// Structure coming from Conditions API.
interface BlockCondition {
slug: string;
name: string;
}

/**
Expand All @@ -26,16 +33,26 @@
export default function Edit({
attributes: {
condition = '',
custom = '',
post = '',
query = '',
index = { '': '' },
},
setAttributes,
clientId,
}: EditProps) {
const { name: parentBlock } = useParentBlock(clientId) as { name?: string } || {};
const [operator, compared] = Object.entries(index)[0];
const [conditions, setConditions] = useState<Conditions[]>([]);

// Fetch and set the Conditions data.
useEffect(() => {
apiFetch({ path: '/conditional-blocks/v1/get-conditions/' })
.then((response: any) => {
if (Array.isArray(response.message) && response.message.length > 0) {
const nextConditions = response.message.map((blockCondition: BlockCondition) => ({
value: blockCondition.slug ?? '',
label: blockCondition.name ?? '',
}));
setConditions(nextConditions);
} else {
console.error('[wp-block-conditions] Failed to retrieve conditions.');

Check warning on line 52 in blocks/condition/edit.tsx

View workflow job for this annotation

GitHub Actions / node-tests / Install, build, and test

Unexpected console statement
}
});
}, []);

return (
<>
Expand All @@ -48,90 +65,22 @@
<InspectorControls>
{/* @ts-ignore-next-line */}
<PanelBody
title={__('Condition', 'wp-conditional-blocks')}
title={__('Conditions', 'wp-conditional-blocks')}
initialOpen
>
{/* @ts-ignore-next-line */}
<PanelRow>
{/* @ts-ignore-next-line */}
<TextControl
label={__('Query', 'wp-conditional-blocks')}
help={__('Query condition, ie "is_home" or "is_category"', 'wp-conditional-blocks')}
onChange={(next) => setAttributes({ query: next })}
value={query}
/>
</PanelRow>
{/* @ts-ignore-next-line */}
<PanelRow>
{/* @ts-ignore-next-line */}
<TextControl
label={__('Post', 'wp-conditional-blocks')}
help={__('Post condition, ie "is_content"', 'wp-conditional-blocks')}
onChange={(next) => setAttributes({ post: next })}
value={post}
/>
</PanelRow>

{/* @ts-ignore-next-line */}
<PanelRow>
{/* @ts-ignore-next-line */}
<TextControl
label={__('Custom', 'wp-conditional-blocks')}
help={__('Custom condition, ie "is_column"', 'wp-conditional-blocks')}
onChange={(next) => setAttributes({ custom: next })}
value={custom}
/>
</PanelRow>

{/* @ts-ignore-next-line */}
<PanelRow>
{/* @ts-ignore-next-line */}
<TextControl
label={__('Condition', 'wp-conditional-blocks')}
help={__('Any other condition', 'wp-conditional-blocks')}
<SelectControl
label={__('Conditions', 'wp-conditional-blocks')}
help={__('Select condition, e.g. "Is Home" or "Is Archive"', 'wp-conditional-blocks')}
onChange={(next) => setAttributes({ condition: next })}
multiple={false}
value={condition}
options={conditions}
/>
</PanelRow>
</PanelBody>

{ parentBlock === 'wp-conditional-blocks/query' ? (
/* @ts-ignore-next-line */
<PanelBody
title={__('Index Condition', 'wp-conditional-blocks')}
>
<p>{__('Checks the index of how many times the parent condition block has been rendered, ie "Equal to 0", "Greater than 5"', 'wp-conditional-blocks')}</p>

{/* @ts-ignore-next-line */}
<PanelRow>
<SelectControl
label={__('Index Operator', 'wp-conditional-blocks')}
value={operator}
options={[
{ value: '', label: __('Select Operator', 'wp-conditional-blocks') },
{ value: '===', label: __('Equal', 'wp-conditional-blocks') },
{ value: '!==', label: __('Not equal', 'wp-conditional-blocks') },
{ value: '>', label: __('Greater than', 'wp-conditional-blocks') },
{ value: '<', label: __('Less than', 'wp-conditional-blocks') },
{ value: '>=', label: __('Greater than or equal to', 'wp-conditional-blocks') },
{ value: '<=', label: __('Less than or equal to', 'wp-conditional-blocks') },
]}
onChange={(next: string) => setAttributes({ index: { [next]: compared } })}
/>
</PanelRow>

{/* @ts-ignore-next-line */}
<PanelRow>
{/* @ts-ignore-next-line */}
<TextControl
label={__('Index compared', 'wp-conditional-blocks')}
onChange={(next) => setAttributes({ index: { [operator]: next } })}
type="number"
value={compared}
/>
</PanelRow>
</PanelBody>
) : null}
</InspectorControls>
</>
);
Expand Down
167 changes: 20 additions & 147 deletions blocks/condition/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use Alley\WP\WP_Conditional_Blocks\Global_Post_Query;
use Alley\WP\WP_Conditional_Blocks\Validator\Slug_Is_In_Category;
use Alley\WP\WP_Conditional_Blocks\Conditions;

/**
* Registers the block using the metadata loaded from the `block.json` file.
Expand All @@ -34,11 +35,7 @@ function wp_conditional_blocks_condition_block_init(): void {
*
* @param array{
* attrs?: array{
* query?: string|array<string|callable>,
* post?: mixed[],
* custom?: mixed[],
* condition?: string[],
* index?: array<string, int>
* condition?: string,
* }
* } $parsed_block Parsed condition block.
* @param array{'postId'?: int} $context Available context.
Expand All @@ -47,154 +44,30 @@ function wp_conditional_blocks_condition_block_init(): void {
function wp_conditional_blocks_condition_block_result( array $parsed_block, array $context ): bool {
global $wp_query;

$num_conditions = 0;
$num_true = 0;
$condition_slug = '';

$conditions = [];

if ( isset( $parsed_block['attrs'] ) ) {
$conditions = $parsed_block['attrs'];
}

if ( isset( $conditions['query'] ) && $wp_query instanceof WP_Query ) {
// Map `{"query": "is_home"} to {"query": {"is_home": true}}`.
if ( is_string( $conditions['query'] ) ) {
$conditions['query'] = array_fill_keys( (array) $conditions['query'], true );
}

foreach ( $conditions['query'] as $condition => $expect ) {
$num_conditions++;

switch ( true ) {
case 'is_singular' === $condition && ( is_string( $expect ) || is_array( $expect ) ):
$result = $wp_query->is_singular( $expect );
break;

case 'is_page' === $condition && ( is_string( $expect ) || is_array( $expect ) ):
$result = $wp_query->is_page( $expect );
break;

case 'is_tax' === $condition && ( is_string( $expect ) || is_array( $expect ) ):
$result = $wp_query->is_tax( $expect );
break;

case method_exists( $wp_query, $condition ) && is_callable( [ $wp_query, $condition ] ):
$result = call_user_func( [ $wp_query, $condition ] ) === $expect; // @phpstan-ignore-line
break;

default:
$result = false;
break;
}

if ( false === $result ) {
break;
}

$num_true++;
}
}

/*
* Checks the index of how many times the parent condition block has been rendered, like:
*
* {"index": {"===": 0}}
* {"index": {">": 2}}
* {"index": {">": 2, "<": 4}}
*
* @see \Alley\Validator\Comparison for the available operators.
*
* Note that this approach means that two identical conditions with two identical set of
* child blocks will use the same counter.
*/
if ( isset( $conditions['index'] ) ) {
$num_conditions++;

$validator = new \Laminas\Validator\ValidatorChain();

foreach ( $conditions['index'] as $operator => $compared ) {
try {
$validator->attach(
validator: new \Alley\Validator\Comparison(
[
'operator' => $operator,
'compared' => $compared,
],
),
breakChainOnFailure: true,
);
} catch ( Exception $exception ) {
// Nothing yet.
unset( $exception );
}
}

if ( count( $validator ) > 0 ) {
if ( $validator->isValid( wp_conditional_blocks_current_counter_block() ) ) {
$num_true++;
}
}
if ( isset( $parsed_block['attrs']['condition'] ) ) {
$condition_slug = $parsed_block['attrs']['condition'];
}

$wp_block_condition = Conditions::get_instance()->get_condition( $condition_slug );
// Validate callable function.
if (
isset( $conditions['post'] )
&& isset( $context['postId'] )
&& $context['postId'] > 0
empty( $wp_block_condition['callable'] )
|| ! $wp_query instanceof WP_Query
) {
$conditions['post'] = (array) $conditions['post'];

foreach ( $conditions['post'] as $condition ) {
$num_conditions++;

if ( 'has_content' === $condition ) {
if ( '' !== get_the_content( null, false, $context['postId'] ) ) {
$num_true++;
}

continue;
}

/**
* Filters the condition block's result for the given post condition.
*
* @param bool $result Condition result.
* @param mixed $condition Condition name.
* @param int $post_id Post ID.
*/
if ( true === apply_filters( 'wp_conditional_blocks_condition_block_post_condition', false, $condition, $context['postId'] ) ) {
$num_true++;
}
}
}

if ( isset( $conditions['custom'] ) ) {
$conditions['custom'] = (array) $conditions['custom'];

foreach ( $conditions['custom'] as $condition ) {
$num_conditions++;
}
return false;
}

if ( isset( $conditions['condition'] ) ) {
$conditions['condition'] = (array) $conditions['condition'];

foreach ( $conditions['condition'] as $name ) {
$num_conditions++;

/**
* Filters the condition block's result for the given condition.
*
* @param bool $result Condition result.
* @param array $context Available context.
* @param WP_Query $wp_query Global query object.
*/
$result = apply_filters( "wp_conditional_blocks_condition_block_{$name}_condition", false, $context, $wp_query );
// Execute conditional's callable.
$callable_result = call_user_func( $wp_block_condition['callable'] );

if ( true === $result ) {
$num_true++;
}
}
}

return $num_conditions > 0 && $num_conditions === $num_true;
/**
* Filters the condition block's result for the given condition.
*
* @param bool $result Condition result.
* @param array $context Available context.
* @param WP_Query $wp_query Global query object.
*/
return apply_filters( "wp_conditional_blocks_condition_block_{$wp_block_condition['slug']}_condition", $callable_result, $context, $wp_query );
}
Loading