-
Notifications
You must be signed in to change notification settings - Fork 57
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
Try/all pattern exporting #747
Open
pbking
wants to merge
13
commits into
trunk
Choose a base branch
from
try/all-pattern-exporting
base: trunk
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+355
−108
Open
Changes from 11 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
dcb8d71
Tinkering with exporting both synced and unsynced patterns
pbking c51adda
WIP, exporting and managing both synced and unsynced patterns
pbking d788a64
Tweaked how unsynced patterns are loaded
pbking 4fb16af
Added dev mode env settings to wp-env config
pbking 79d0fc0
Update patterns copied from USER space to THEME space to use the assi…
pbking 507d0b6
register ALL patterns (hidden). Plus do work on synced pattern files…
pbking b299d79
Got replacing all synced patterns working as exected
pbking a71561b
Moved synced pattern handling stuff to a class
pbking ed4825d
Adding pattern loader class
pbking d15fa62
Correct remove_action syntax
pbking 294c5c6
Added the 'load synced patterns' utility
pbking f557137
Store both Synced and Unsynced patterns in the database AND files. S…
pbking ca8e4c3
Inserter false vs inserter 'no' for block registration
pbking File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,3 +35,5 @@ build/ | |
|
||
# phpunit | ||
*.result.* | ||
|
||
dev-env/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
|
||
//add action for when editor assets load | ||
add_action('init', function () { | ||
|
||
// if the CBT plugin is active we don't need to do anything | ||
if (class_exists('CBT_Synced_Pattern_Loader')) { | ||
return; | ||
} | ||
|
||
function CBT_render_pattern($pattern_file) | ||
{ | ||
ob_start(); | ||
include $pattern_file; | ||
return ob_get_clean(); | ||
} | ||
|
||
$theme = wp_get_theme(); | ||
$pattern_files = glob($theme->get_stylesheet_directory() . '/patterns/*.php'); | ||
|
||
foreach ($pattern_files as $pattern_file) { | ||
|
||
$pattern_data = get_file_data($pattern_file, array( | ||
'title' => 'Title', | ||
'slug' => 'Slug', | ||
'description' => 'Description', | ||
'inserter' => 'Inserter', | ||
'synced' => 'Synced', | ||
)); | ||
|
||
// if the pattern is not synced do nothing | ||
if ($pattern_data['synced'] !== 'yes') { | ||
continue; | ||
} | ||
|
||
$pattern_post = get_page_by_path(sanitize_title($pattern_data['slug']), OBJECT, 'wp_block'); | ||
if ($pattern_post) { | ||
// the post exists | ||
$pattern_data['id'] = $pattern_post->ID; | ||
// Note, we are NOT updating the post. If you want that behavior install the CBT plugin. | ||
} | ||
else { | ||
// the post does not exist. create it. | ||
$pattern_data['content'] = CBT_render_pattern($pattern_file); | ||
$pattern_data['id'] = wp_insert_post(array( | ||
'post_title' => $pattern_data['title'], | ||
'post_name' => $pattern_data['slug'], | ||
'post_content' => $pattern_data['content'], | ||
'post_type' => 'wp_block', | ||
'post_status' => 'publish', | ||
'ping_status' => 'closed', | ||
'comment_status' => 'closed', | ||
)); | ||
} | ||
|
||
// UN register the unsynced pattern and RE register it with the reference to the synced pattern | ||
// this pattern injects a synced pattern block as the content. | ||
// and allows it to be used by anything that uses the wp:pattern (rather than the wp:block) | ||
$pattern_registry = WP_Block_Patterns_Registry::get_instance(); | ||
|
||
if ( $pattern_registry->is_registered($pattern_data['slug'])){ | ||
$pattern_registry->unregister($pattern_data['slug']); | ||
} | ||
|
||
$pattern_registry->register( | ||
$pattern_data['slug'], | ||
array( | ||
'title' => $pattern_data['title'], | ||
'inserter' => false, | ||
'content' => '<!-- wp:block {"ref":' . $pattern_data['id'] . '} /-->', | ||
) | ||
); | ||
|
||
} | ||
}); |
264 changes: 264 additions & 0 deletions
264
includes/class-create-block-theme-synced-pattern-loader.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
<?php | ||
|
||
|
||
/** | ||
* The api functionality of the plugin leveraged by the site editor UI. | ||
* | ||
* @package Create_Block_Theme | ||
* @subpackage Create_Block_Theme/admin | ||
* @author WordPress.org | ||
*/ | ||
class CBT_Synced_Pattern_Loader | ||
{ | ||
|
||
public function __construct() | ||
{ | ||
// don't register the theme block patterns | ||
remove_action('init', '_register_theme_block_patterns'); | ||
add_action('init', [$this, 'CBT_register_theme_synced_block_patterns']); | ||
|
||
// add the theme block patterns to the block collection | ||
add_filter('rest_post_dispatch', [$this, 'CBT_filter_blocks_api_response'], 10, 3); | ||
add_filter('rest_pre_dispatch', [$this, 'CBT_filter_block_update'], 10, 3); | ||
} | ||
|
||
public function CBT_register_theme_synced_block_patterns() | ||
{ | ||
|
||
$patterns = self::CBT_get_theme_block_patterns(); | ||
|
||
foreach ($patterns as $pattern) { | ||
|
||
// if it is a synced pattern manage the post | ||
if ($pattern['synced'] === 'yes') { | ||
|
||
//search for post by slug | ||
$pattern_post = get_page_by_path(sanitize_title($pattern['slug']), OBJECT, 'wp_block'); | ||
|
||
if ($pattern_post) { | ||
$post_id = $pattern_post->ID; | ||
// the synced pattern already exists | ||
// update the post with the content in the file | ||
wp_update_post(array( | ||
'ID' => $post_id, | ||
'post_content' => $pattern['content'], | ||
)); | ||
} else { | ||
$post_id = wp_insert_post(array( | ||
'post_title' => $pattern['title'], | ||
'post_name' => $pattern['slug'], | ||
'post_content' => $pattern['content'], | ||
'post_type' => 'wp_block', | ||
'post_status' => 'publish', | ||
'ping_status' => 'closed', | ||
'comment_status' => 'closed', | ||
)); | ||
} | ||
|
||
// add the pattern as an UNsynced pattern TOO so that it can be used in templates. | ||
// this pattern injects a synced pattern block as the content. | ||
register_block_pattern( | ||
$pattern['slug'], | ||
array( | ||
'title' => $pattern['title'], | ||
'inserter' => false, | ||
'content' => '<!-- wp:block {"ref":' . $post_id . '} /-->', | ||
) | ||
); | ||
} else { | ||
// register the pattern and hide from the inserter | ||
register_block_pattern( | ||
$pattern['slug'], | ||
array( | ||
'title' => $pattern['title'], | ||
'inserter' => false, | ||
'content' => $pattern['content'], | ||
) | ||
); | ||
} | ||
} | ||
} | ||
|
||
private static function CBT_render_pattern($pattern_file) | ||
{ | ||
ob_start(); | ||
include $pattern_file; | ||
return ob_get_clean(); | ||
} | ||
|
||
|
||
public static function CBT_get_theme_block_patterns() | ||
{ | ||
$default_headers = array( | ||
'title' => 'Title', | ||
'slug' => 'Slug', | ||
'description' => 'Description', | ||
'viewportWidth' => 'Viewport Width', | ||
'inserter' => 'Inserter', | ||
'categories' => 'Categories', | ||
'keywords' => 'Keywords', | ||
'blockTypes' => 'Block Types', | ||
'postTypes' => 'Post Types', | ||
'templateTypes' => 'Template Types', | ||
'synced' => 'Synced', | ||
); | ||
|
||
$all_patterns = array(); | ||
$themes = array(); | ||
$theme = wp_get_theme(); | ||
$themes[] = $theme; | ||
|
||
if ($theme->parent()) { | ||
$themes[] = $theme->parent(); | ||
} | ||
|
||
foreach ($themes as $theme) { | ||
|
||
$pattern_files = glob($theme->get_stylesheet_directory() . '/patterns/*.php'); | ||
|
||
foreach ($pattern_files as $pattern_file) { | ||
|
||
$pattern_data = get_file_data($pattern_file, $default_headers); | ||
|
||
$pattern_data['pattern_file'] = $pattern_file; | ||
$pattern_data['content'] = self::CBT_render_pattern($pattern_file); | ||
|
||
// if the pattern is synced add the ID | ||
|
||
if ($pattern_data['synced'] === 'yes') { | ||
$pattern_post = get_page_by_path(sanitize_title($pattern_data['slug']), OBJECT, 'wp_block'); | ||
if ($pattern_post) { | ||
$pattern_data['id'] = $pattern_post->ID; | ||
} | ||
} | ||
|
||
$all_patterns[] = $pattern_data; | ||
} | ||
} | ||
|
||
return $all_patterns; | ||
} | ||
|
||
private static function format_pattern_for_response($pattern_data) | ||
{ | ||
return array( | ||
'id' => $pattern_data['id'] ?? 'CBT_' . $pattern_data['slug'], | ||
'file_path' => $pattern_data['pattern_file'], | ||
'slug' => $pattern_data['slug'] ?? null, | ||
'status' => 'publish', | ||
'type' => 'wp_block', | ||
'title' => array( | ||
'raw' => $pattern_data['title'] ?? null, | ||
), | ||
'content' => array( | ||
'raw' => $pattern_data['content'] ?? null, | ||
'protected' => false, | ||
'block_version' => null, | ||
), | ||
'excerpt' => array( | ||
'raw' => $pattern_data['description'] ?? null, | ||
'rendered' => null, | ||
'protected' => false, | ||
), | ||
'wp_pattern_category' => array(), | ||
'wp_pattern_sync_status' => $pattern_data['synced'] === 'yes' ? "" : "unsynced", | ||
); | ||
} | ||
|
||
// Add in the block patterns from the theme to the collection of blocks | ||
public function CBT_filter_blocks_api_response($response, $server, $request) | ||
{ | ||
if ($request->get_route() !== '/wp/v2/blocks') { | ||
return $response; | ||
} | ||
|
||
$data = $response->get_data(); | ||
$patterns = self::CBT_get_theme_block_patterns(); | ||
|
||
// filter out the synced patterns | ||
// filter out the patterns marked hidden | ||
$patterns = array_filter($patterns, function ($pattern) { | ||
return $pattern['synced'] !== 'yes' && $pattern['inserter'] !== 'no'; | ||
}); | ||
|
||
|
||
|
||
$patterns = array_map([self::class, 'format_pattern_for_response'], $patterns); | ||
|
||
$response->set_data(array_merge($data, $patterns)); | ||
|
||
return $response; | ||
} | ||
|
||
// Handle CBT block updates | ||
public function CBT_filter_block_update($result, $server, $request) | ||
{ | ||
$route = $request->get_route(); | ||
|
||
if (strpos($route, '/wp/v2/blocks/') !== 0) { | ||
return $result; | ||
} | ||
|
||
if (str_contains($route, 'CBT_')) { | ||
$pattern_slug = ltrim(strstr($route, 'CBT_'), 'CBT_'); | ||
} else { | ||
//get the slug for the post with the pattern id | ||
$pattern_id = $request->get_param('id'); | ||
if (! $pattern_id) { | ||
//get the ID from the route | ||
$pattern_id = str_replace('/wp/v2/blocks/', '', $route); | ||
} | ||
$pattern_slug = get_post_field('post_name', $pattern_id); | ||
} | ||
|
||
$theme_patterns = self::CBT_get_theme_block_patterns(); | ||
|
||
// if a pattern with a matching slug exists in the theme, do work on it | ||
foreach ($theme_patterns as $pattern) { | ||
|
||
if (sanitize_title($pattern['slug']) === sanitize_title($pattern_slug)) { | ||
|
||
// if the request is a GET, return the pattern content | ||
if ($request->get_method() === 'GET') { | ||
// which we do below | ||
} | ||
|
||
// if the request is a PUT or POST, create/update the pattern content file | ||
if ($request->get_method() === 'PUT' || $request->get_method() === 'POST') { | ||
$block_content = $request->get_param('content'); | ||
$synced_status = $pattern['synced'] === 'yes' ? 'Synced: yes' : ''; | ||
$file_content = <<<PHP | ||
<?php | ||
/** | ||
* Title: {$pattern['title']} | ||
* Slug: {$pattern['slug']} | ||
* Categories: {$pattern['categories']} | ||
* {$synced_status} | ||
*/ | ||
?> | ||
{$block_content} | ||
PHP; | ||
|
||
file_put_contents($pattern['pattern_file'], $file_content); | ||
|
||
$pattern['content'] = $block_content; | ||
} | ||
|
||
// if the request is a DELETE, delete the pattern content file | ||
if ($request->get_method() === 'DELETE') { | ||
unlink($pattern['pattern_file']); | ||
} | ||
|
||
// if we pulled the real ID then we also want to do work on the database; | ||
// return null to allow the natural action to happen too. | ||
if ($pattern_id) { | ||
return null; | ||
} | ||
|
||
return rest_ensure_response(self::format_pattern_for_response($pattern)); | ||
} | ||
} | ||
|
||
return $result; | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this was committed accidentally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it wasn't an accident, though I suppose that should probably go in a separate PR.
The environment variables feel pretty necessary, when running the wp-env environment, to be running in development mode (to prevent pattern cacheing). And the mappings allows us to actually interact with the theme assets from an environment spun up from wp-env.
Both important changes I think, so I'll open up a separate PR in which to discuss the merits.