Skip to content

Commit

Permalink
Add meta and query parameter to fetch patterns matching a list of all…
Browse files Browse the repository at this point in the history
…owed blocks (#540)

* Patterns: Add new meta to track which block types are used in a pattern

* API: Allow filtering the pattern directory by which block types are used

* Directory Bin: Update all patterns with the "contains block types" meta field.

* Add all meta to translated patterns

Adds wpop_keywords, wpop_block_types, wpop_contains_block_types, wpop_wp_version.

* Patterns: Add the block types used as meta when a post is updated
  • Loading branch information
ryelle committed Jan 2, 2023
1 parent 76b4942 commit 7b94374
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php
/**
* Update all patterns with the "contains block types" meta field.
*
* To run locally, use `wp-env`, ex:
* yarn wp-env run cli "php wp-content/plugins/pattern-directory/bin/update-contains-block-types.php --all --per_page=100 --apply"
*
* To run in a sandbox, use php directly, ex:
* php ./bin/update-contains-block-types.php --all --apply
*/

namespace WordPressdotorg\Pattern_Directory;

use const WordPressdotorg\Pattern_Directory\Pattern_Post_Type\{ POST_TYPE };

// This script should only be called in a CLI environment.
if ( 'cli' != php_sapi_name() ) {
die();
}

$opts = getopt( '', array( 'post:', 'url:', 'abspath:', 'per_page:', 'all', 'apply', 'verbose' ) );

if ( empty( $opts['url'] ) ) {
$opts['url'] = 'https://wordpress.org/patterns/';
}

if ( empty( $opts['abspath'] ) && false !== strpos( __DIR__, 'wp-content' ) ) {
$opts['abspath'] = substr( __DIR__, 0, strpos( __DIR__, 'wp-content' ) );
}

$opts['apply'] = isset( $opts['apply'] );
$opts['verbose'] = isset( $opts['verbose'] );
$opts['all'] = isset( $opts['all'] );

// Bootstrap WordPress
$_SERVER['HTTP_HOST'] = parse_url( $opts['url'], PHP_URL_HOST );
$_SERVER['REQUEST_URI'] = parse_url( $opts['url'], PHP_URL_PATH );

require rtrim( $opts['abspath'], '/' ) . '/wp-load.php';

if ( ! $opts['all'] && ! isset( $opts['post'] ) ) {
fwrite( STDERR, "Error! Either specify a post ID with --post=<ID> or explicitly run over --all.\n" );
die();
}

if ( ! $opts['apply'] ) {
echo "Dry run, will not update any patterns.\n";
}

$args = array(
'post_type' => POST_TYPE,
'post_status' => array( 'publish', 'pending' ),
'posts_per_page' => isset( $opts['per_page'] ) ? $opts['per_page'] : -1,
'post_parent' => 0,
'orderby' => 'date',
'order' => 'DESC',
'meta_query' => array(
// Only update patterns without this meta.
array(
'key' => 'wpop_contains_block_types',
'compare' => 'NOT EXISTS',
),
),
);
if ( isset( $opts['post'] ) ) {
$args = array(
'post_type' => POST_TYPE,
'p' => absint( $opts['post'] ),
);
}

$query = new \WP_Query( $args );
$meta_updated = 0;

while ( $query->have_posts() ) {
$query->the_post();
$pattern = get_post();
$pattern_id = $pattern->ID;
$blocks = parse_blocks( $pattern->post_content );
$all_blocks = _flatten_blocks( $blocks );

// Get the list of block names and convert it to a single string.
$block_names = wp_list_pluck( $all_blocks, 'blockName' );
$block_names = array_filter( $block_names );
$block_names = array_unique( $block_names );
sort( $block_names );
$used_blocks = implode( ',', $block_names );

if ( $opts['apply'] ) {
$result = update_post_meta( $pattern_id, 'wpop_contains_block_types', $used_blocks );
if ( $result ) {
$meta_updated++;
} else if ( $opts['verbose'] ) {
echo "Error updating {$pattern_id}.\n"; // phpcs:ignore
}
} else if ( $opts['verbose'] ) {
echo "Will update {$pattern_id} with '{$used_blocks}'.\n"; // phpcs:ignore
}
}

echo "Updated {$meta_updated} patterns.\n"; // phpcs:ignore
echo "Done.\n\n"; // phpcs:ignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
add_action( 'rest_api_init', __NAMESPACE__ . '\register_rest_fields' );
add_action( 'init', __NAMESPACE__ . '\register_post_statuses' );
add_action( 'transition_post_status', __NAMESPACE__ . '\status_transitions', 10, 3 );
add_action( 'post_updated', __NAMESPACE__ . '\update_contains_block_types_meta' );
add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\enqueue_editor_assets' );
add_filter( 'allowed_block_types_all', __NAMESPACE__ . '\remove_disallowed_blocks', 10, 2 );
add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\disable_block_directory', 0 );
Expand Down Expand Up @@ -249,6 +250,24 @@ function register_post_type_data() {
),
)
);

register_post_meta(
POST_TYPE,
'wpop_contains_block_types',
array(
'type' => 'string',
'description' => 'A list of block types used in this pattern',
'single' => true,
'default' => '',
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => __NAMESPACE__ . '\can_edit_this_pattern',
'show_in_rest' => array(
'schema' => array(
'type' => 'string',
),
),
)
);
}

/**
Expand Down Expand Up @@ -490,6 +509,26 @@ function status_transitions( $new_status, $old_status, $post ) {
}
}

/**
* Given a post ID, parse out the block types and update the `wpop_contains_block_types` meta field.
*
* @param int $pattern_id Pattern ID.
*/
function update_contains_block_types_meta( $pattern_id ) {
$pattern = get_post( $pattern_id );
$blocks = parse_blocks( $pattern->post_content );
$all_blocks = _flatten_blocks( $blocks );

// Get the list of block names and convert it to a single string.
$block_names = wp_list_pluck( $all_blocks, 'blockName' );
$block_names = array_filter( $block_names ); // Filter out null values (extra line breaks).
$block_names = array_unique( $block_names );
sort( $block_names );
$used_blocks = implode( ',', $block_names );

update_post_meta( $pattern_id, 'wpop_contains_block_types', $used_blocks );
}

/**
* Determines if the current user can edit the given pattern post.
*
Expand Down Expand Up @@ -635,6 +674,14 @@ function filter_patterns_collection_params( $query_params ) {
'type' => 'string',
);

$query_params['allowed_blocks'] = array(
'description' => __( 'Filter the request to only return patterns with blocks on this list.', 'wporg-patterns' ),
'type' => 'array',
'items' => array(
'type' => 'string',
),
);

return $query_params;
}

Expand Down Expand Up @@ -700,6 +747,16 @@ function filter_patterns_rest_query( $args, $request ) {
);
}

$allowed_blocks = $request->get_param( 'allowed_blocks' );
if ( $allowed_blocks ) {
// Only return a pattern if all contained blocks are in the allowed blocks list.
$args['meta_query']['allowed_blocks'] = array(
'key' => 'wpop_contains_block_types',
'compare' => 'REGEXP',
'value' => '^((' . implode( '|', $allowed_blocks ) . '),?)+$',
);
}

return $args;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,14 @@ function create_or_update_translated_pattern( Pattern $pattern ) {
'post_author' => $parent->post_author ?? 0,
'post_status' => $parent->post_status ?? 'pending',
'meta_input' => [
'wpop_description' => $pattern->description,
'wpop_locale' => $pattern->locale,
'wpop_viewport_width' => $parent->wpop_viewport_width,
'wpop_is_translation' => true,
'wpop_description' => $pattern->description,
'wpop_locale' => $pattern->locale,
'wpop_keywords' => $pattern->keywords,
'wpop_viewport_width' => $parent->wpop_viewport_width,
'wpop_block_types' => $parent->wpop_block_types,
'wpop_contains_block_types' => $parent->wpop_contains_block_types,
'wpop_wp_version' => $parent->wpop_wp_version,
'wpop_is_translation' => true,
],
];

Expand Down

0 comments on commit 7b94374

Please sign in to comment.