Skip to content

Commit acd3beb

Browse files
swissspidyclaude
andauthored
Guard the block subcommands on older WordPress and quiet the wp-compat false positives (#647)
Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1758308 commit acd3beb

4 files changed

Lines changed: 145 additions & 0 deletions

File tree

‎features/post-block.feature‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ Feature: Manage blocks in post content
4747
"""
4848
And the return code should be 1
4949

50+
@less-than-wp-5.0
51+
Scenario: Checking for a specific block requires WordPress 5.0
52+
Given a WP install
53+
When I run `wp post create --post_title="Block Post" --post_content="<!-- wp:paragraph --><p>Hello</p><!-- /wp:paragraph -->" --porcelain`
54+
Then save STDOUT as {POST_ID}
55+
56+
# has-blocks goes through the bundled WP_Block_Processor polyfill, so it keeps working.
57+
When I run `wp post has-blocks {POST_ID}`
58+
Then STDOUT should contain:
59+
"""
60+
Success: Post {POST_ID} contains blocks.
61+
"""
62+
63+
# has-block relies on the has_block() function that WordPress only added in 5.0.
64+
When I try `wp post has-block {POST_ID} core/paragraph`
65+
Then STDERR should contain:
66+
"""
67+
Error: Requires WordPress 5.0 or greater.
68+
"""
69+
And the return code should be 1
70+
5071
@require-wp-5.0
5172
Scenario: Parse blocks in a post
5273
Given a WP install

‎phpstan.neon.dist‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,95 @@ parameters:
1919
- identifier: missingType.property
2020
- identifier: missingType.parameter
2121
- identifier: missingType.return
22+
23+
24+
# johnbillion/wp-compat checks every WordPress symbol against the WordPress 4.9
25+
# baseline that wp-cli-tests configures. It only recognizes function_exists() and
26+
# method_exists() guards, so it cannot see the `before_invoke` version checks in
27+
# entity-command.php or the polyfills in src/Compat/, and reports those as errors.
28+
#
29+
# Every entry below matches on the message as well as the identifier, so that a call
30+
# to something introduced later than the version a command is gated on still gets
31+
# reported rather than swallowed by a file-wide ignore.
32+
33+
# `WP_Block_Processor` and its dependencies are polyfilled in src/Compat/ and loaded
34+
# on demand through `BlockProcessorLoader::load()`, so they are available on every
35+
# supported WordPress version, not just 6.9+.
36+
-
37+
identifier: WPCompat.methodNotAvailable
38+
message: '#^WP_Block_Processor::(allocate_and_return_parsed_attributes|extract_full_block_and_advance|get_block_type|get_delimiter_type|get_depth|get_span|next_block)\(\) is only available since WordPress version 6\.9\.0\.$#'
39+
path: src/Block_Processor_Helper.php
40+
41+
# `wp font collection|face|family` aborts on WordPress < 6.5 via `before_invoke`.
42+
-
43+
identifier: WPCompat.methodNotAvailable
44+
message: '#^(WP_Font_Collection::get_data|WP_Font_Library::(get_font_collection|get_font_collections|get_instance))\(\) is only available since WordPress version 6\.5\.0\.$#'
45+
paths:
46+
- src/Font_Collection_Command.php
47+
- src/Font_Family_Command.php
48+
49+
# `wp user application-password` aborts on WordPress < 5.6 via `before_invoke`.
50+
-
51+
identifier: WPCompat.methodNotAvailable
52+
message: '#^WP_Application_Passwords::(create_new_application_password|delete_all_application_passwords|delete_application_password|get_user_application_password|get_user_application_passwords|record_application_password_usage|update_application_password)\(\) is only available since WordPress version 5\.6\.0\.$#'
53+
path: src/User_Application_Password_Command.php
54+
55+
# The single WordPress 5.7 method is additionally behind a `wp_version_compare()`
56+
# check in `application_name_exists_for_user()`, which reimplements it for 5.6.
57+
-
58+
identifier: WPCompat.methodNotAvailable
59+
message: '#^WP_Application_Passwords::application_name_exists_for_user\(\) is only available since WordPress version 5\.7\.0\.$#'
60+
path: src/User_Application_Password_Command.php
61+
62+
# `wp user privacy-request` aborts on WordPress < 4.9.6 via `before_invoke`.
63+
-
64+
identifier: WPCompat.functionNotAvailable
65+
message: '#^(_wp_privacy_completed_request|wp_create_user_request|wp_get_user_request_data|wp_privacy_exports_dir|wp_privacy_generate_personal_data_export_file|wp_send_user_request)\(\) is only available since WordPress version 4\.9\.6\.$#'
66+
path: src/User_Privacy_Request_Command.php
67+
68+
# `wp site meta` aborts via `before_invoke` unless `is_site_meta_supported()`
69+
# exists, which is the WordPress 5.1 function that introduced site meta support
70+
# along with the `*_site_meta()` functions used here.
71+
-
72+
identifier: WPCompat.functionNotAvailable
73+
message: '#^(add_site_meta|delete_site_meta|get_site_meta|update_site_meta)\(\) is only available since WordPress version 5\.1\.0\.$#'
74+
path: src/Site_Meta_Command.php
75+
76+
# `wp post block` aborts on WordPress < 5.0 via `before_invoke`. `serialize_blocks()`
77+
# is WordPress 5.3.1+ and is guarded separately in the mutating subcommands, so it
78+
# must keep being reported if that guard ever goes away.
79+
-
80+
identifier: WPCompat.functionNotAvailable
81+
message: '#^(has_blocks|parse_blocks|render_block)\(\) is only available since WordPress version 5\.0\.0\.$#'
82+
path: src/Post_Block_Command.php
83+
84+
# Only the uppercase `'ID'` alias for the `$field` parameter of `get_term_by()`
85+
# is WordPress 5.5+. These call sites pass `'id'`, `'term_id'` or `'slug'`, all
86+
# supported since WordPress 2.3.
87+
-
88+
identifier: WPCompat.parameterNotAvailable.gettermby.field
89+
paths:
90+
- src/Menu_Item_Command.php
91+
- src/Term_Command.php
92+
- src/WP_CLI/CommandWithTerms.php
93+
94+
# WordPress 6.0 only formalized the already documented `...$args` parameter of
95+
# `apply_filters()` by adding it to the function signature. Additional arguments
96+
# were collected through `func_get_args()` before that.
97+
-
98+
identifier: WPCompat.parameterNotAvailable.applyfilters.args
99+
path: src/Post_Block_Command.php
100+
101+
# Same for `wpdb::prepare()`, where WordPress 5.3 formalized the already
102+
# documented `...$args` parameter. Passing a single array of values is even
103+
# handled explicitly by `wpdb::prepare()` itself.
104+
-
105+
identifier: WPCompat.parameterNotAvailable.wpdbprepare.args
106+
path: src/Site_Command.php
107+
108+
# The `$force_cache` parameter of `wp_load_alloptions()` is WordPress 5.3.1+, but
109+
# older versions simply ignore the extra argument. The cache refresh in
110+
# `wp option set-autoload` degrades to a no-op there instead of failing.
111+
-
112+
identifier: WPCompat.parameterNotAvailable.wploadalloptions.forcecache
113+
path: src/Option_Command.php

‎src/Post_Block_Command.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ public function get( $args, $assoc_args ) {
224224
* @subcommand update
225225
*/
226226
public function update( $args, $assoc_args ) {
227+
if ( ! function_exists( 'serialize_blocks' ) ) {
228+
WP_CLI::error( 'Requires WordPress 5.3.1 or greater.' );
229+
}
230+
227231
$post = $this->fetcher->get_check( $args[0] );
228232
$index = (int) $args[1];
229233
$blocks = parse_blocks( $post->post_content );
@@ -340,6 +344,10 @@ public function update( $args, $assoc_args ) {
340344
* @subcommand move
341345
*/
342346
public function move( $args, $assoc_args ) {
347+
if ( ! function_exists( 'serialize_blocks' ) ) {
348+
WP_CLI::error( 'Requires WordPress 5.3.1 or greater.' );
349+
}
350+
343351
$post = $this->fetcher->get_check( $args[0] );
344352
$from_index = (int) $args[1];
345353
$to_index = (int) $args[2];
@@ -607,6 +615,10 @@ function ( $block ) {
607615
* @subcommand import
608616
*/
609617
public function import( $args, $assoc_args ) {
618+
if ( ! function_exists( 'serialize_blocks' ) ) {
619+
WP_CLI::error( 'Requires WordPress 5.3.1 or greater.' );
620+
}
621+
610622
$post = $this->fetcher->get_check( $args[0] );
611623
$file = Utils\get_flag_value( $assoc_args, 'file', null );
612624
$position = Utils\get_flag_value( $assoc_args, 'position', 'end' );
@@ -914,6 +926,10 @@ public function count( $args, $assoc_args ) {
914926
* @subcommand clone
915927
*/
916928
public function clone_block( $args, $assoc_args ) {
929+
if ( ! function_exists( 'serialize_blocks' ) ) {
930+
WP_CLI::error( 'Requires WordPress 5.3.1 or greater.' );
931+
}
932+
917933
$post = $this->fetcher->get_check( $args[0] );
918934
$source_index = (int) $args[1];
919935
$position = Utils\get_flag_value( $assoc_args, 'position', 'after' );
@@ -1393,6 +1409,10 @@ public function list_( $args, $assoc_args ) {
13931409
* @subcommand insert
13941410
*/
13951411
public function insert( $args, $assoc_args ) {
1412+
if ( ! function_exists( 'serialize_blocks' ) ) {
1413+
WP_CLI::error( 'Requires WordPress 5.3.1 or greater.' );
1414+
}
1415+
13961416
$post = $this->fetcher->get_check( $args[0] );
13971417
$block_name = $args[1];
13981418
$content = Utils\get_flag_value( $assoc_args, 'content', '' );
@@ -1492,6 +1512,10 @@ public function insert( $args, $assoc_args ) {
14921512
* @subcommand remove
14931513
*/
14941514
public function remove( $args, $assoc_args ) {
1515+
if ( ! function_exists( 'serialize_blocks' ) ) {
1516+
WP_CLI::error( 'Requires WordPress 5.3.1 or greater.' );
1517+
}
1518+
14951519
$post = $this->fetcher->get_check( $args[0] );
14961520
$block_name = isset( $args[1] ) ? $args[1] : null;
14971521
$indices = Utils\get_flag_value( $assoc_args, 'index', null );
@@ -1637,6 +1661,10 @@ function ( $idx ) use ( $index_map ) {
16371661
* @subcommand replace
16381662
*/
16391663
public function replace( $args, $assoc_args ) {
1664+
if ( ! function_exists( 'serialize_blocks' ) ) {
1665+
WP_CLI::error( 'Requires WordPress 5.3.1 or greater.' );
1666+
}
1667+
16401668
$post = $this->fetcher->get_check( $args[0] );
16411669
$old_block_name = $args[1];
16421670
$new_block_name = $args[2];

‎src/Post_Command.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,10 @@ public function has_blocks( $args, $assoc_args ) {
14301430
* @subcommand has-block
14311431
*/
14321432
public function has_block( $args, $assoc_args ) {
1433+
if ( ! function_exists( 'has_block' ) ) {
1434+
WP_CLI::error( 'Requires WordPress 5.0 or greater.' );
1435+
}
1436+
14331437
$post = $this->fetcher->get_check( $args[0] );
14341438
$block_name = $args[1];
14351439

0 commit comments

Comments
 (0)