fix(admin): join REST URLs correctly under plain permalinks
When permalink_structure is empty, rest_url() is index.php?rest_route=/aksrt/v1. Naive base+endpoint produced rest_route=/aksrt/v1/banners?kind=banner (query inside route value), so WP returned rest_no_route and Banner/Hero managers 404'd. Fold path into rest_route and append extra params as siblings.
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* AKSRT Admin API Client
|
* AKSRT Admin API Client
|
||||||
*
|
*
|
||||||
* Communicates with the WordPress REST API at /wp-json/aksrt/v1.
|
* Communicates with the WordPress REST API at /wp-json/aksrt/v1
|
||||||
|
* (or index.php?rest_route=/aksrt/v1 when pretty permalinks are off).
|
||||||
* Methods are organized into domain modules while the client keeps the shared
|
* Methods are organized into domain modules while the client keeps the shared
|
||||||
* request pipeline and schema-domain normalization contract.
|
* request pipeline and schema-domain normalization contract.
|
||||||
*/
|
*/
|
||||||
@@ -15,6 +16,73 @@ function normalizeDomainKey(domain) {
|
|||||||
return String(domain || 'global').trim().replace(/-/g, '_')
|
return String(domain || 'global').trim().replace(/-/g, '_')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join REST base + endpoint correctly for both pretty and plain permalinks.
|
||||||
|
*
|
||||||
|
* Pretty: https://site/wp-json/aksrt/v1 + /banners?kind=x
|
||||||
|
* → https://site/wp-json/aksrt/v1/banners?kind=x
|
||||||
|
*
|
||||||
|
* Plain: https://site/index.php?rest_route=/aksrt/v1 + /banners?kind=x
|
||||||
|
* → https://site/index.php?rest_route=/aksrt/v1/banners&kind=x
|
||||||
|
* (must NOT produce rest_route=/aksrt/v1/banners?kind=x)
|
||||||
|
*
|
||||||
|
* @param {string} baseUrl
|
||||||
|
* @param {string} endpoint path starting with /, may include ?query
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function joinRestUrl(baseUrl, endpoint) {
|
||||||
|
let path = endpoint == null || endpoint === '' ? '/' : String(endpoint)
|
||||||
|
let extraQuery = ''
|
||||||
|
const qIdx = path.indexOf('?')
|
||||||
|
if (qIdx !== -1) {
|
||||||
|
extraQuery = path.slice(qIdx + 1)
|
||||||
|
path = path.slice(0, qIdx)
|
||||||
|
}
|
||||||
|
if (!path.startsWith('/')) {
|
||||||
|
path = '/' + path
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = String(baseUrl || '').trim() || '/wp-json/aksrt/v1'
|
||||||
|
|
||||||
|
// Plain permalinks: rest_route query mode
|
||||||
|
if (base.includes('rest_route=')) {
|
||||||
|
let u
|
||||||
|
try {
|
||||||
|
u = new URL(base, typeof window !== 'undefined' ? window.location.origin : 'https://localhost')
|
||||||
|
} catch {
|
||||||
|
// Fallback: naive append (should not hit with valid rest_url)
|
||||||
|
return base.replace(/\/?$/, '') + path + (extraQuery ? (base.includes('?') ? '&' : '?') + extraQuery : '')
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseRoute = (u.searchParams.get('rest_route') || '/aksrt/v1').replace(/\/$/, '') || '/aksrt/v1'
|
||||||
|
let fullRoute
|
||||||
|
if (path === '/') {
|
||||||
|
fullRoute = baseRoute
|
||||||
|
} else if (path.startsWith('/aksrt/')) {
|
||||||
|
fullRoute = path
|
||||||
|
} else {
|
||||||
|
fullRoute = baseRoute + path
|
||||||
|
}
|
||||||
|
u.searchParams.set('rest_route', fullRoute)
|
||||||
|
|
||||||
|
if (extraQuery) {
|
||||||
|
const extra = new URLSearchParams(extraQuery)
|
||||||
|
extra.forEach((v, k) => {
|
||||||
|
u.searchParams.set(k, v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return u.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pretty /wp-json mode
|
||||||
|
const root = base.replace(/\/$/, '')
|
||||||
|
let url = root + (path === '/' ? '' : path)
|
||||||
|
if (extraQuery) {
|
||||||
|
url += (url.includes('?') ? '&' : '?') + extraQuery
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.baseUrl = API_ROOT
|
this.baseUrl = API_ROOT
|
||||||
@@ -58,11 +126,13 @@ class ApiClient {
|
|||||||
endpoint = endpoint.replace('/aksrt/v1', '') || '/'
|
endpoint = endpoint.replace('/aksrt/v1', '') || '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = `${this.baseUrl}${endpoint}`
|
let url = joinRestUrl(this.baseUrl, endpoint)
|
||||||
|
|
||||||
if (params && typeof params === 'object') {
|
if (params && typeof params === 'object') {
|
||||||
const qs = new URLSearchParams(params).toString()
|
const qs = new URLSearchParams(params).toString()
|
||||||
if (qs) url += (url.includes('?') ? '&' : '?') + qs
|
if (qs) {
|
||||||
|
url += (url.includes('?') ? '&' : '?') + qs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let finalBody = body
|
let finalBody = body
|
||||||
@@ -116,5 +186,5 @@ class ApiClient {
|
|||||||
|
|
||||||
Object.assign(ApiClient.prototype, apiMethods)
|
Object.assign(ApiClient.prototype, apiMethods)
|
||||||
|
|
||||||
export { normalizeDomainKey }
|
export { normalizeDomainKey, joinRestUrl }
|
||||||
export default new ApiClient()
|
export default new ApiClient()
|
||||||
|
|||||||
Reference in New Issue
Block a user