Skip to content

Commit

Permalink
PLANET-7527 Move blocks report into master theme
Browse files Browse the repository at this point in the history
  • Loading branch information
sagarsdeshmukh committed Jun 5, 2024
1 parent c5985de commit 57bde5a
Show file tree
Hide file tree
Showing 27 changed files with 3,551 additions and 0 deletions.
278 changes: 278 additions & 0 deletions src/BlockReportSearch/Block/BlockUsage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
<?php
/**
* Table displaying blocks usage
*
* @package P4BKS\Controllers
*/

namespace P4\MasterTheme\BlockReportSearch\Block;

use WP_Block_Parser;
use P4\MasterTheme\BlockReportSearch\BlockSearch;
use P4\MasterTheme\BlockReportSearch\Block\Query\Parameters;

/**
* Present block usage, using native WordPress table
*/
class BlockUsage {
/**
* @var BlockSearch
*/
private $search;

/**
* @var WP_Block_Parser
*/
private $parser;

/**
* @var int[]
*/
private $posts_ids;

/**
* @var WP_Post[]
*/
private $posts;

/**
* @var array
*/
private $blocks;

/**
* @param BlockSearch $search Search class.
* @param WP_Block_Parser $parser Block parser.
*/
public function __construct(
?BlockSearch $search = null,
?WP_Block_Parser $parser = null
) {
$this->search = $search ?? new BlockSearch();
$this->parser = $parser ?? new WP_Block_Parser();
}

/**
* @param Parameters $params Query parameters.
* @return array
*/
public function get_blocks( Parameters $params ): array {
$this->posts_ids = $this->search->get_posts( $params );

return $this->get_filtered_blocks( $this->posts_ids, $params );
}

/**
* @param Parameters $params Query parameters.
* @return int[]
*/
public function get_posts( Parameters $params ): array {
$block_list = $this->get_blocks( $this->posts_ids, $params );

return array_unique( array_column( $block_list, 'post_id' ) );
}

/**
* @param int[] $posts_ids Posts IDs.
* @param Parameters $params Query parameters.
* @return array
*/
private function get_filtered_blocks( $posts_ids, Parameters $params ) {
$this->fetch_blocks( $posts_ids, $params );
$this->filter_blocks( $params );
$this->sort_blocks( $params->order() );

return $this->blocks;
}

/**
* @param int[] $posts_ids Posts IDs.
* @param Parameters $params Query parameters.
*/
private function fetch_blocks( array $posts_ids, Parameters $params ): void {
$posts_args = [
'include' => $posts_ids,
'orderby' => empty( $params->order() ) ? null : array_fill_keys( $params->order(), 'ASC' ),
'post_status' => $params->post_status(),
'post_type' => $params->post_type(),
];

$this->posts = get_posts( $posts_args ) ?? [];

$block_listblock_list = [];
foreach ( $this->posts as $post ) {
$block_listblock_list = array_merge( $block_listblock_list, $this->parse_post( $post ) );
}
$this->blocks = $block_listblock_list;
}

/**
* Filter parsed search items
*
* @param Parameters $params Query parameters.
* @return array
*/
private function filter_blocks( Parameters $params ): void {
if (
empty( $params->namespace() )
&& empty( $params->name() )
&& empty( $params->content() )
) {
return;
}

$filtered = $this->blocks;

$text = $params->content();
$filters = [
'block_ns' => $params->namespace(),
'block_type' => $params->name(),
'local_name' => false !== strpos( $params->name(), '/' )
? explode( '/', $params->name() )[1]
: $params->name(),
];

if ( ! empty( $filters['block_type'] ) ) {
$filtered = array_filter(
$filtered,
function ( $i ) use ( $filters ) {
return $i['block_type'] === $filters['block_type']
|| $i['local_name'] === $filters['local_name'];
}
);
} elseif ( ! empty( $filters['block_ns'] ) ) {
$filtered = array_filter(
$filtered,
function ( $i ) use ( $filters ) {
return $i['block_ns'] === $filters['block_ns'];
}
);
}

if ( ! empty( $text ) ) {
$filtered = array_filter(
$filtered,
function ( $i ) use ( $text ) {
return strpos( $i['block_type'], $text ) !== false
//phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
|| strpos( serialize( $i['block_attrs'] ), $text ) !== false;
}
);
}

$this->blocks = $filtered;
}

/**
* Sort parsed blocks
*
* @param null|array $sort Sort dimensions.
* @return array
*/
private function sort_blocks( ?array $sort = [] ): void {
if ( empty( $sort ) ) {
return;
}

$args = [];
$block_list = $this->blocks;
foreach ( $sort as $name ) {
$args[] = array_column( $block_list, $name );
$args[] = SORT_NATURAL;
}
$args[] = &$block_list;

array_multisort( ...$args );

$this->blocks = $block_list;
}

/**
* Parse posts content to blocks.
*
* @param object $post WP_Post.
* @return array[]
*/
private function parse_post( $post ): array {
$output = $this->parser->parse( $post->post_content );

$block_list = array_filter(
$output,
function ( $block ) {
return ! empty( $block['blockName'] );
}
);

$items = [];
while ( ! empty( $block_list ) ) {
$block = array_shift( $block_list );
$items[] = $this->format_block_data( $block, $post );

if ( ! empty( $block['innerBlocks'] ) ) {
$block_list = array_merge( $block_list, $block['innerBlocks'] );
}
}

return $items;
}

/**
* Format block information.
*
* @param array $block A block.
* @param object $post WP_Post.
* @return array[]
*/
private function format_block_data( array $block, $post ): array {
$type = $block['blockName'];
$attrs = $block['attrs'] ?? [];
$has_ns = strpos( $type, '/' ) !== false;

[ $namespace, $local_name ] = $has_ns ? explode( '/', $type ) : [ 'core', $type ];

$classes = empty( $attrs['className'] ) ? [] : explode( ' ', $attrs['className'] );
$styles = array_filter(
array_map(
function ( $c ): ?string {
return 'is-style-' === substr( $c, 0, 9 ) ? substr( $c, 9 ) : null;
},
$classes
)
);

return [
'post_id' => $post->ID,
'post_title' => $post->post_title
? $post->post_title : __( '(no title)', 'planet4-blocks-backend' ),
'post_status' => $post->post_status,
'post_type' => $post->post_type,
'post_date' => $post->post_date,
'post_modified' => $post->post_modified,
'post_status' => $post->post_status,
'guid' => $post->guid,
'block_ns' => $namespace,
'block_type' => $type,
'local_name' => $local_name,
'block_attrs' => $attrs,
'block_styles' => $styles,
];
}

/**
* Block count in search result.
*
* @return int
*/
public function block_count(): int {
return count( $this->blocks );
}

/**
* Post count in search result.
*
* @return int
*/
public function post_count(): int {
return count( $this->posts_ids );
}
}
95 changes: 95 additions & 0 deletions src/BlockReportSearch/Block/BlockUsageApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* Table displaying blocks usage
*
* @package P4BKS\Controllers
*/

namespace P4\MasterTheme\BlockReportSearch\Block;

use P4\MasterTheme\BlockReportSearch\Block\Query\Parameters;

/**
* Block usage API
*/
class BlockUsageApi {

public const DEFAULT_POST_STATUS = [ 'publish' ];

/**
* @var BlockUsage
*/
private $usage;

/**
* @var Parameters
*/
private $params;

/**
* @var array[] Blocks.
*/
private $items;

/**
* Constructor
*/
public function __construct() {
$this->usage = new BlockUsage();
$this->params = ( new Parameters() )
->with_post_status( self::DEFAULT_POST_STATUS )
->with_post_type(
\get_post_types(
[
'public' => true,
'exclude_from_search' => false,
]
)
);
}

/**
* Count blocks by type and style
*
* If style is not specified, an empty key 'n/a' is used.
*/
public function get_count(): array {
if ( null === $this->items ) {
$this->fetch_items();
}

$types = array_unique(
array_column( $this->items, 'block_type' )
);
$blocks = array_fill_keys(
$types,
[
'total' => 0,
'styles' => [],
]
);
ksort( $blocks );

foreach ( $this->items as $item ) {
$styles = empty( $item['block_styles'] ) ? [ 'n/a' ] : $item['block_styles'];
foreach ( $styles as $style ) {
$type = $item['block_type'];
if ( ! isset( $blocks[ $type ]['styles'][ $style ] ) ) {
$blocks[ $type ]['styles'][ $style ] = 0;
}
$blocks[ $type ]['styles'][ $style ]++;
$blocks[ $type ]['total']++;
}
ksort( $blocks[ $type ]['styles'] );
}

return $blocks;
}

/**
* Fetch parsed blocks
*/
private function fetch_items(): void {
$this->items = $this->usage->get_blocks( $this->params );
}
}
Loading

0 comments on commit 57bde5a

Please sign in to comment.