Skip to content
Open
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 1.2.0
* Fix: Resolve `Image` block import issues.
* Feat: Add custom hooks `cbtj_import_block`, `cbtj_export_block`, `cbtj_blocks`.
* Docs: Update README docs.
* Tested up to WP 6.8.

## 1.1.0
* Feat: Add REST namespace filter `cbtj_rest_namespace`.
* Refactor: Use classes for PHP codebase.
Expand Down
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,79 @@ https://github.com/user-attachments/assets/9dedf30f-9df0-4307-b634-cecef930a6e5

### Hooks

#### `cbtj_blocks`

This custom hook (filter) provides the ability to customise the block classes:

```php
add_filter( 'cbtj_blocks', [ $this, 'custom_blocks' ], 10 );

public function custom_blocks( $blocks ): array {
$blocks[] = \YourNameSpace\YourCustomBlock::class;

return $block;
}
```

**Parameters**

- blocks _`{Block[]}`_ By default, this is an array consisting of block classes.
<br/>

#### `cbtj_import_block`

This custom hook (filter) provides the ability to customise any block array during import:

```php
add_filter( 'cbtj_import_block', [ $this, 'custom_import_block' ], 10 );

public function custom_import_block( $block ): array {
if ( 'core/image' !== $block['name'] ) {
return $block;
}

// Get block attributes.
$block['attributes'] = json_decode( $block['attributes'], true );

// Set Caption using Post meta.
$block['attributes']['caption'] = get_post_meta( get_the_ID(), 'featured_image_caption', true );

// Encode attributes finally.
$block['attributes'] = wp_json_encode( $block['attributes'] );

return $block;
}
```

**Parameters**

- block _`{mixed[]}`_ By default, this would be a block array containing `name`, `originalContent`, `attributes` & `innerBlocks` key/value pairs.
<br/>

#### `cbtj_export_block`

This custom hook (filter) provides the ability to customise any block array during export:

```php
add_filter( 'cbtj_export_block', [ $this, 'custom_export_block' ], 10 );

public function custom_export_block( $block ): array {
if ( 'core/image' !== $block['name'] ) {
return $block;
}

// Set Caption using Post meta.
$block['attributes']['caption'] = get_post_meta( get_the_ID(), 'featured_image_caption', true );

return $block;
}
```

**Parameters**

- block _`{mixed[]}`_ By default, this would be a block array containing `name`, `content`, `filtered`, `attributes` & `innerBlocks` key/value pairs.
<br/>

#### `cbtj_rest_export`

This custom hook (filter) provides the ability to customise the REST response obtained:
Expand Down
37 changes: 37 additions & 0 deletions inc/Abstracts/Block.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
/**
* Block Abstraction.
*
* This base class describes the public methods accessible
* to the Block classes for implementation ease.
*
* @package ConvertBlocksToJSON
*/

namespace ConvertBlocksToJSON\Abstracts;

/**
* Block class.
*/
abstract class Block {
/**
* Modify Block.
*
* @since 1.2.0
*
* @param mixed[] $block Import Block.
* @return mixed[]
*/
abstract public function modify_block( $block ): array;

/**
* Subscribe to `cbtj_import_block`.
*
* @since 1.2.0
*
* @return void
*/
public function init(): void {
add_filter( 'cbtj_import_block', [ $this, 'modify_block' ] );
}
}
44 changes: 44 additions & 0 deletions inc/Blocks/Image.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Image Block.
*
* This class is responsible for customizing
* the Image block output.
*
* @package ConvertBlocksToJSON
*/

namespace ConvertBlocksToJSON\Blocks;

use ConvertBlocksToJSON\Abstracts\Block;

class Image extends Block {
/**
* Modify Block.
*
* @since 1.2.0
*
* @param mixed[] $block Import Block.
* @return mixed[]
*/
public function modify_block( $block ): array {
// Bail out, if undefined OR not Image block.
if ( empty( $block['name' ] ) || 'core/image' !== $block['name'] ) {
return $block;
}

// Decode attributes correctly.
$block['attributes'] = json_decode( $block['attributes'] ?? '', true );

// Ensure missing URL attribute is captured for image blocks.
preg_match( '/src="([^"]+)"/', $block['originalContent'] ?? '', $matches );
$block['attributes']['url'] = esc_url( $matches[1] ?? '' );

// Re-encode attributes correctly.
$block['attributes'] = wp_json_encode( $block['attributes'] );

return $block;
}
}


2 changes: 2 additions & 0 deletions inc/Core/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace ConvertBlocksToJSON\Core;

use ConvertBlocksToJSON\Services\Boot;
use ConvertBlocksToJSON\Services\Blocks;
use ConvertBlocksToJSON\Services\Routes;
use ConvertBlocksToJSON\Services\Scripts;
use ConvertBlocksToJSON\Interfaces\Kernel;
Expand All @@ -33,6 +34,7 @@ class Container implements Kernel {
public function __construct() {
static::$services = [
Boot::class,
Blocks::class,
Routes::class,
Scripts::class,
];
Expand Down
24 changes: 17 additions & 7 deletions inc/Routes/Export.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ public function rest_callback( $request ) {
];

/**
* Filter JSON Response.
* Filter Export.
*
* @since 1.0.0
*
* @param mixed[] $export Response Array.
* @param mixed[] $export Export data.
* @param integer $post_id Post ID.
*
* @return mixed[]
Expand Down Expand Up @@ -101,14 +101,14 @@ function ( $block ) {
}

/**
* Get JSON.
* Get Export Content.
*
* Get all JSON block arrays and recursively
* add children.
* Loop through the JSON blocks and recursively
* add children blocks.
*
* @since 1.0.0
*
* @param mixed[] $block WP Blocks.
* @param mixed[] $block Block array.
* @return mixed[]
*/
public function get_export( $block ): array {
Expand All @@ -120,12 +120,22 @@ public function get_export( $block ): array {
}
}

return [
$export_block = [
'name' => $block['blockName'] ?? '',
'content' => $block['innerHTML'] ?? '',
'filtered' => wp_strip_all_tags( $block['innerHTML'] ?? '' ),
'attributes' => $block['attrs'] ?? [],
'innerBlocks' => $children,
];

/**
* Filter Export Block.
*
* @since 1.2.0
*
* @param mixed[] $export_block Export Block.
* @return mixed[]
*/
return apply_filters( 'cbtj_export_block', $export_block );
}
}
54 changes: 37 additions & 17 deletions inc/Routes/Import.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,25 @@ public function rest_callback( $request ) {
}

// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$json = file_get_contents( $json_file );
$import = $this->get_blocks_import( json_decode( $json, true ), $post_id );
$json = json_decode( file_get_contents( $json_file ), true );
$blocks = $this->get_blocks_import( $json['content'] ?? [], $post_id );

// Make sure to weed out empty blocks.
$content = array_filter( $blocks, fn( $block ) => ! empty( $block ) );

// Add title.
$import = [
'title' => $json['title'] ?? '',
'content' => $content
];

/**
* Filter JSON Import.
* Filter Import.
*
* @since 1.0.1
*
* @param mixed[] $response Import Blocks.
* @param integer $post_id Post ID.
* @param mixed[] $import Import data.
* @param integer $post_id Post ID.
*
* @return mixed[]
*/
Expand All @@ -102,18 +111,13 @@ public function rest_callback( $request ) {
*
* @param 1.0.1
*
* @param array $json JSON Array of Blocks.
* @param array $content JSON content.
* @param integer $post_id Post ID.
*
* @return mixed[]
*/
public function get_blocks_import( $json, $post_id ): array {
$import_blocks = array_map(
[ $this, 'get_import' ],
$json['content'] ?? []
);

return $import_blocks;
public function get_blocks_import( $content, $post_id ): array {
return array_map( [ $this, 'get_import' ], $content );
}

/**
Expand All @@ -128,6 +132,11 @@ public function get_blocks_import( $json, $post_id ): array {
* @return mixed[]
*/
public function get_import( $block ): array {
// Bail out, if block has no name.
if ( '' === ( $block['name'] ?? '' ) ) {
return [];
}

$children = [];

if ( ! empty( $block['innerBlocks'] ) ) {
Expand All @@ -138,10 +147,21 @@ public function get_import( $block ): array {

$block['attributes']['content'] = $block['filtered'] ?? '';

return [
'name' => $block['name'] ?? '',
'attributes' => wp_json_encode( $block['attributes'] ?? [] ),
'innerBlocks' => $children ?? [],
$import_block = [
'name' => $block['name'] ?? '',
'originalContent' => $block['content'] ?? '',
'attributes' => wp_json_encode( $block['attributes'] ?? [] ),
'innerBlocks' => $children ?? [],
];

/**
* Filter Import Block.
*
* @since 1.2.0
*
* @param mixed[] $import_block Import Block.
* @return mixed[]
*/
return apply_filters( 'cbtj_import_block', $import_block );
}
}
55 changes: 55 additions & 0 deletions inc/Services/Blocks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* Blocks Service.
*
* This service is responsible for binding Block
* import customizations to WordPress.
*
* @package ConvertBlocksToJSON
*/

namespace ConvertBlocksToJSON\Services;

use ConvertBlocksToJSON\Blocks\Image;
use ConvertBlocksToJSON\Abstracts\Block;
use ConvertBlocksToJSON\Abstracts\Service;
use ConvertBlocksToJSON\Interfaces\Kernel;

class Blocks extends Service implements Kernel {
/**
* Bind to WP.
*
* @since 1.2.0
*
* @return void
*/
public function register(): void {
$blocks = [
Image::class
];

/**
* Filter Block classes.
*
* This provides a way to filter the block
* classes before they are called.
*
* @since 1.2.0
*
* @param Block[] $blocks Block classes.
* @return Block[]
*/
$blocks = apply_filters( 'cbtj_blocks', $blocks );

/**
* Run `init` to filter Block types.
*
* @since 1.2.0
*
* @var Block $block
*/
foreach ( $blocks as $block ) {
( new $block() )->init();
}
}
}
Loading