Skip to content

Commit

Permalink
Navigation Editor: Fix saving locations using the "Manage Locations" …
Browse files Browse the repository at this point in the history
…popup (#34714)

* Create SaveButton component.
It's needed to save menu locations.

* Fix code style.

* Remove SaveButton component.
It's better to put all "save" related logic into the manage-locations component.

* Implement a function that sends batch requests to update menu locations.

* 1. Fix request path for __experimental/menus route.
2. Small refactoring.

* Fix code style.

* Allow batch requests for `__experimental/menus` endpoints because we need to use batch API to save menus' locations in the Manage Locations popup.

* 1. Display an error or a success message when updating menus' locations.
2. Fix css classname for the save button.

* Add async/await to be sure we return get response instead of a Promise.

* Move "save" button to the right.

* In this context "Update" is better than "Save".

* Increase unit test code coverage by adding a unit test for WP_REST_Menus_Controller_Test.

* There was a type in the method's name.
We need to rename it.

* Fix code style.

* 1. Export createBatch function so that it can be used externally.

* 1. Refactor Manage Locations and use createBatch function to send batches to the batch REST API endpoint.
The previous method doesn't properly parse error responses.

* Update lib/class-wp-rest-menus-controller.php

Co-authored-by: Jonny Harris <[email protected]>

* Fix parent class name.

* Fix code style.

* Add default domain for translation because lint-php check fails.

* Fix the unit test.

* Move the test to the REST_Nav_Menus_Controller_Test.

* 1. We need to place this public method before protected and private methods, so I'm just moving it above them.
2. Update test fail message.

* Revert "1. We need to place this public method before protected and private methods, so I'm just moving it above them."

This reverts commit 400236d305ca4cb18da40f568c1bb09bd0231a38.

* Revert "Move the test to the REST_Nav_Menus_Controller_Test."

This reverts commit 72440411ad261191987c856de041a7be19962783.

* Fix the test.

* Fix the error inside the WP_REST_Menus_Controller::register_routes

* Revert "1. Export createBatch function so that it can be used externally."

This reverts commit b7fc4a12a2bd4353c131b994eff8fdc1d202cf5b.

* Refactor locations update logic and revert to apiFetch.
We can't use createBatch function from wordpress/core-data.

* Fix the import statement.

* Move the test to the REST_Nav_Menus_Controller_Test.

* Fix code style.

Co-authored-by: Jonny Harris <[email protected]>
  • Loading branch information
anton-vlasenko and spacedmonkey authored Sep 13, 2021
1 parent f74bbde commit b686c45
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
72 changes: 72 additions & 0 deletions lib/class-wp-rest-menus-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* @see WP_REST_Controller
*/
class WP_REST_Menus_Controller extends WP_REST_Terms_Controller {

/**
* Constructor.
*
Expand All @@ -22,6 +23,77 @@ public function __construct( $taxonomy ) {
$this->namespace = '__experimental';
}

/**
* Overrides the route registration to support "allow_batch".
*
* @since 11.5.0
*
* @see register_rest_route()
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_item' ),
'permission_callback' => array( $this, 'create_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);

register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/(?P<id>[\d]+)',
array(
'args' => array(
'id' => array(
'description' => __( 'Unique identifier for the term.', 'default' ),
'type' => 'integer',
),
),
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_item' ),
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
'args' => array(
'force' => array(
'type' => 'boolean',
'default' => false,
'description' => __( 'Required to be true, as terms do not support trashing.', 'default' ),
),
),
),
'allow_batch' => array( 'v1' => true ),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
}


/**
* Checks if a request has access to read terms in the specified taxonomy.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import {
SelectControl,
} from '@wordpress/components';
import { decodeEntities } from '@wordpress/html-entities';
import apiFetch from '@wordpress/api-fetch';
import { useDispatch } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';

/**
* Internal dependencies
Expand All @@ -31,6 +34,62 @@ export default function ManageLocations( {
const [ isModalOpen, setIsModalOpen ] = useState( false );
const openModal = () => setIsModalOpen( true );
const closeModal = () => setIsModalOpen( false );
const { createSuccessNotice, createErrorNotice } = useDispatch(
noticesStore
);

const validateBatchResponse = ( batchResponse ) => {
if ( batchResponse.failed ) {
return false;
}

const errorResponses = batchResponse.responses.filter( ( response ) => {
return 200 > response.status || 300 <= response.status;
} );

return 1 > errorResponses.length;
};

const handleUpdateMenuLocations = async () => {
const method = 'POST';
const batchRequests = menus.map( ( { id } ) => {
const locations = menuLocations
.filter( ( menuLocation ) => menuLocation.menu === id )
.map( ( menuLocation ) => menuLocation.name );

return {
path: `/__experimental/menus/${ id }`,
body: {
locations,
},
method,
};
} );

const batchResponse = await apiFetch( {
path: 'batch/v1',
data: {
validation: 'require-all-validate',
requests: batchRequests,
},
method,
} );

const isSuccess = validateBatchResponse( batchResponse );

if ( isSuccess ) {
createSuccessNotice( __( 'Menu locations have been updated.' ), {
type: 'snackbar',
} );
closeModal();
return;
}

createErrorNotice(
__( 'An error occurred while trying to update menu locations.' ),
{ type: 'snackbar' }
);
};

if ( ! menuLocations || ! menus?.length ) {
return <Spinner />;
Expand Down Expand Up @@ -156,6 +215,13 @@ export default function ManageLocations( {
{ themeLocationCountTextModal }
</div>
{ menuLocationCard }
<Button
className="edit-navigation-manage-locations__save-button"
variant="primary"
onClick={ handleUpdateMenuLocations }
>
{ __( 'Update' ) }
</Button>
</Modal>
) }
</PanelBody>
Expand Down
4 changes: 4 additions & 0 deletions packages/edit-navigation/src/components/sidebar/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,7 @@
.edit-navigation-manage-locations__theme-location-text-modal {
margin-bottom: $grid-unit-30;
}

.edit-navigation-manage-locations__save-button {
float: right;
}
10 changes: 10 additions & 0 deletions phpunit/class-rest-nav-menus-controller-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,16 @@ public function test_get_item_wrong_permission() {
$this->assertErrorResponse( 'rest_cannot_view', $response, 403 );
}

public function test_it_allows_batch_requests_when_updating_menus() {
$rest_server = rest_get_server();
// This call is needed to initialize route_options.
$rest_server->get_routes();
$route_options = $rest_server->get_route_options( '/__experimental/menus/(?P<id>[\d]+)' );

$this->assertArrayHasKey( 'allow_batch', $route_options );
$this->assertSame( array( 'v1' => true ), $route_options['allow_batch'] );
}

/**
* @param WP_REST_Response $response Response Class.
*/
Expand Down

0 comments on commit b686c45

Please sign in to comment.