Skip to content
Merged
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
31 changes: 31 additions & 0 deletions inc/admin/metabox/manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ final class Manager {
*/
private $control_classes;

/**
* Meta keys registered for the block editor sidebar, keyed by meta key.
*
* @var array<string, bool>
*/
private $registered_meta_keys = array();
Comment thread
girishpanchal30 marked this conversation as resolved.

/**
* Init function
*/
Expand All @@ -53,6 +60,7 @@ public function init() {
*/
add_action( 'init', array( $this, 'neve_register_meta' ) );
add_action( 'enqueue_block_editor_assets', array( $this, 'meta_sidebar_script_enqueue' ) );
add_filter( 'is_protected_meta', array( $this, 'protect_post_sidebar_meta' ), 10, 3 );
}

/**
Expand Down Expand Up @@ -331,7 +339,30 @@ public function neve_register_meta() {
$control['id'],
$meta_settings
);

$this->registered_meta_keys[ $control['id'] ] = true;
}
}

/**
* Mark the meta data as protected.
*
* @param bool $is_protected whether the key is protected.
* @param string $meta_key the meta key.
* @param string $meta_type the type of meta object this key belongs to.
*
* @return bool
*/
public function protect_post_sidebar_meta( $is_protected, $meta_key, $meta_type ) {
if (
$meta_type === 'post' &&
isset( $this->registered_meta_keys[ $meta_key ] ) &&
$this->registered_meta_keys[ $meta_key ]
) {
return true;
}

return $is_protected;
}

/**
Expand Down
173 changes: 173 additions & 0 deletions tests/test-neve-metabox-meta.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php
/**
* Tests for the block editor sidebar meta save flow.
*
* @package neve
*/

/**
* Class TestNeveMetaboxMeta
*/
class TestNeveMetaboxMeta extends WP_UnitTestCase {

/**
* Page used in the save flow.
*
* @var int
*/
private $page_id;

/**
* REST server in place before the test replaced it.
*
* @var WP_REST_Server|null
*/
private $previous_rest_server;

/**
* Setup.
*/
public function setUp(): void {
parent::setUp();

global $wp_rest_server;

require_once ABSPATH . 'wp-admin/includes/post.php';

$this->previous_rest_server = $wp_rest_server;

// The test case unregisters every meta key on teardown.
$manager = new \Neve\Admin\Metabox\Manager();
$manager->neve_register_meta();

$wp_rest_server = new WP_REST_Server();
do_action( 'rest_api_init', $wp_rest_server );

Comment thread
girishpanchal30 marked this conversation as resolved.
wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );

$this->page_id = self::factory()->post->create(
array(
'post_type' => 'page',
'post_title' => 'Neve meta page',
'post_status' => 'publish',
)
);

$_POST = array();
}

/**
* Teardown.
*/
public function tearDown(): void {
global $wp_rest_server;

$wp_rest_server = $this->previous_rest_server;
$_POST = array();

parent::tearDown();
}

/**
* Save the sidebar meta the way the editor sidebar does, over the REST API.
*
* @param string $value the value to save.
*
* @return WP_REST_Response
*/
private function rest_save_sidebar_meta( $value ) {
$request = new WP_REST_Request( 'POST', '/wp/v2/pages/' . $this->page_id );
$request->set_body_params( array( 'meta' => array( 'neve_meta_sidebar' => $value ) ) );

return rest_get_server()->dispatch( $request );
}

/**
* Submit the meta box form the way post.php does when the editor saves meta boxes.
*
* @param array $meta meta id => [ key, value ] pairs, as rendered by the Custom Fields box.
*/
private function submit_meta_boxes( $meta ) {
$_POST = array(
'post_ID' => $this->page_id,
'post_type' => 'page',
'post_title' => 'Neve meta page',
'post_status' => 'publish',
'meta' => $meta,
);

edit_post();

$_POST = array();
}
Comment on lines +90 to +102

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edit_post() does not contain check_admin_referer() or any nonce handling. It only performs capability checks such as current_user_can( 'edit_post', ... ) and current_user_can( 'edit_post_meta', ... ). The administrator role is set up before each test case, so all test cases pass successfully.


/**
* The value picked in the Neve sidebar is saved over REST.
*/
public function test_sidebar_meta_is_saved_over_rest() {
$response = $this->rest_save_sidebar_meta( 'full-width' );

$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 'full-width', get_post_meta( $this->page_id, 'neve_meta_sidebar', true ) );
}

/**
* With the Custom Fields panel on, the meta box form is submitted right after the REST save.
*
* It carries the key/value pairs rendered when the editor was loaded, so the stale value
* must not be written back over the one just saved from the sidebar.
*/
public function test_custom_fields_submit_does_not_revert_sidebar_meta() {
update_post_meta( $this->page_id, 'neve_meta_sidebar', 'default' );

$meta_id = $this->get_meta_id( 'neve_meta_sidebar' );

$this->rest_save_sidebar_meta( 'full-width' );
$this->assertEquals( 'full-width', get_post_meta( $this->page_id, 'neve_meta_sidebar', true ) );

// The Custom Fields box submits the value loaded with the page.
$this->submit_meta_boxes(
array(
$meta_id => array(
'key' => 'neve_meta_sidebar',
'value' => 'default',
),
)
);

$this->assertEquals( 'full-width', get_post_meta( $this->page_id, 'neve_meta_sidebar', true ) );
}

/**
* Meta that is not ours still goes through the Custom Fields panel.
*/
public function test_custom_fields_submit_still_updates_other_meta() {
update_post_meta( $this->page_id, 'some_other_key', 'first' );

$this->submit_meta_boxes(
array(
$this->get_meta_id( 'some_other_key' ) => array(
'key' => 'some_other_key',
'value' => 'second',
),
)
);

$this->assertEquals( 'second', get_post_meta( $this->page_id, 'some_other_key', true ) );
}

/**
* Get the meta id for a key on the test page.
*
* @param string $key the meta key.
*
* @return int
*/
private function get_meta_id( $key ) {
global $wpdb;

return (int) $wpdb->get_var(
$wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $this->page_id, $key )
);
}
}
Loading