| 1 |
/** |
| 2 |
* Route api-fetch PUT/PATCH/DELETE through POST + `?_method=<VERB>`. |
| 3 |
* |
| 4 |
* `@wordpress/api-fetch` rewrites PUT/PATCH/DELETE into a POST that carries an |
| 5 |
* `X-HTTP-Method-Override` header (its httpV1 middleware). CRS-default WAFs and |
| 6 |
* some managed hosts 403 both the bare verbs and that header before WordPress |
| 7 |
* sees the request, so every wp-admin mutation in a WCPOS bundle would die on |
| 8 |
* such a host. WordPress core reads the `_method` query parameter BEFORE the |
| 9 |
* override header (WP_REST_Server::serve_request), so a plain POST with |
| 10 |
* `?_method=DELETE` reaches the same route handler on every host. |
| 11 |
* |
| 12 |
* The POS client already made this exact switch (mono#1397); this shim brings |
| 13 |
* the wp-admin bundles in line. `apiFetch.use()` unshifts, so this runs before |
| 14 |
* the httpV1 middleware, which then sees a POST and adds nothing. |
| 15 |
* |
| 16 |
* Loaded once per admin page via the `wcpos-api-fetch-method-param` script |
| 17 |
* handle; the shared `wp.apiFetch` instance is patched, so every bundle that |
| 18 |
* lists the handle as a dependency is covered. |
| 19 |
*/ |
| 20 |
( function ( wp ) { |
| 21 |
if ( ! wp || ! wp.apiFetch || wp.apiFetch.wcposMethodParam ) { |
| 22 |
return; |
| 23 |
} |
| 24 |
|
| 25 |
var REWRITTEN_METHODS = { PUT: true, PATCH: true, DELETE: true }; |
| 26 |
|
| 27 |
// Only WCPOS routes are rewritten. The shared instance also serves core |
| 28 |
// calls on these screens, and core's own middlewares (media uploads, for |
| 29 |
// one) key off the verb — a rewritten `DELETE /wp/v2/media/{id}` would be |
| 30 |
// mistaken for an upload. |
| 31 |
var WCPOS_ROUTE = /(^|\/)wcpos\/v\d+\//; |
| 32 |
|
| 33 |
wp.apiFetch.use( function ( options, next ) { |
| 34 |
var method = String( options.method || 'GET' ).toUpperCase(); |
| 35 |
|
| 36 |
if ( ! REWRITTEN_METHODS[ method ] ) { |
| 37 |
return next( options ); |
| 38 |
} |
| 39 |
|
| 40 |
// api-fetch accepts either a REST `path` or an absolute `url`. A |
| 41 |
// `namespace` + `endpoint` caller is left alone: core assembles its |
| 42 |
// `path` AFTER this middleware and would drop the `_method` param. |
| 43 |
var key = typeof options.url === 'string' ? 'url' : 'path'; |
| 44 |
var target = options[ key ]; |
| 45 |
|
| 46 |
if ( typeof target !== 'string' || ! WCPOS_ROUTE.test( target ) ) { |
| 47 |
return next( options ); |
| 48 |
} |
| 49 |
|
| 50 |
var separator = target.indexOf( '?' ) === -1 ? '?' : '&'; |
| 51 |
var rewritten = Object.assign( {}, options, { method: 'POST' } ); |
| 52 |
|
| 53 |
rewritten[ key ] = target + separator + '_method=' + method; |
| 54 |
|
| 55 |
return next( rewritten ); |
| 56 |
} ); |
| 57 |
|
| 58 |
wp.apiFetch.wcposMethodParam = true; |
| 59 |
} )( window.wp ); |
| 60 |
|