Skip to content

Commit 64c15f3

Browse files
authored
Add editor post slug target resolution
1 parent b91c172 commit 64c15f3

2 files changed

Lines changed: 63 additions & 11 deletions

File tree

packages/runtime-playground/src/editor-actions.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ export type RunPlaygroundCommand = (
1616

1717
export interface EditorOpenTarget {
1818
url: string
19-
kind: "post" | "post-new" | "site" | "url" | "front-page"
19+
kind: "post" | "post-new" | "site" | "url" | "front-page" | "post-slug"
2020
postId?: number
21+
postSlug?: string
2122
postType?: string
2223
waitSelector: string
2324
}
@@ -68,8 +69,16 @@ export function editorOpenTargetFromArgs(args: string[]): EditorOpenTarget {
6869
return { url: `/wp-admin/post.php?post=${postId}&action=edit`, kind: "post", postId, postType, waitSelector }
6970
}
7071

72+
const postSlug = argValue(args, "post-slug")?.trim()
73+
if (postSlug) {
74+
if (!/^[a-zA-Z0-9_\-/]+$/.test(postSlug)) {
75+
throw new Error(`wordpress.editor-open post-slug must be a WordPress post slug or path: ${postSlug}`)
76+
}
77+
return { url: "", kind: "post-slug", postSlug, postType, waitSelector }
78+
}
79+
7180
if (target !== "post-new") {
72-
throw new Error(`wordpress.editor-open target supports post-new, site, front-page, or url=<path-or-url>: ${target}`)
81+
throw new Error(`wordpress.editor-open target supports post-new, site, front-page, post-slug=<slug>, or url=<path-or-url>: ${target}`)
7382
}
7483

7584
return { url: `/wp-admin/post-new.php?post_type=${encodeURIComponent(postType)}`, kind: "post-new", postType, waitSelector }
@@ -93,25 +102,28 @@ export async function resolveEditorOpenTarget(
93102
server: PlaygroundCliServer
94103
},
95104
): Promise<EditorOpenTarget> {
96-
if (target.kind !== "front-page") {
105+
if (target.kind !== "front-page" && target.kind !== "post-slug") {
97106
return target
98107
}
99108
const { command, runPlaygroundCommand, runtimeSpec, server } = context
100109
if (!runPlaygroundCommand) {
101-
throw new Error(`${command} target=front-page requires Playground PHP command support`)
110+
throw new Error(`${command} ${target.kind} target requires Playground PHP command support`)
102111
}
103112
if (!runtimeSpec) {
104-
throw new Error(`${command} target=front-page requires a runtime spec`)
113+
throw new Error(`${command} ${target.kind} target requires a runtime spec`)
105114
}
106115

107-
const resolveCommand = `${command}.resolve-front-page`
116+
const resolveCommand = target.kind === "front-page" ? `${command}.resolve-front-page` : `${command}.resolve-post-slug`
108117
const response = await runPlaygroundCommand(resolveCommand, server, {
109-
code: bootstrapPhpCode(runtimeSpec, frontPagePostIdPhpCode(), []),
118+
code: bootstrapPhpCode(runtimeSpec, target.kind === "front-page" ? frontPagePostIdPhpCode() : postSlugPostIdPhpCode(target.postSlug ?? "", target.postType ?? "post"), []),
110119
})
111120
assertPlaygroundResponseOk(resolveCommand, response)
112121

113-
const frontPageId = Number.parseInt(cleanWpCliOutput(response.text).trim(), 10)
114-
if (!Number.isInteger(frontPageId) || frontPageId <= 0) {
122+
const postId = Number.parseInt(cleanWpCliOutput(response.text).trim(), 10)
123+
if (!Number.isInteger(postId) || postId <= 0) {
124+
if (target.kind === "post-slug") {
125+
throw new Error(`${command} post-slug=${target.postSlug ?? ""} post-type=${target.postType ?? "post"} resolved no editable post.`)
126+
}
115127
throw new Error(
116128
`${command} target=front-page found no static front page: WordPress has show_on_front != "page" or page_on_front is unset. Configure a static front page (e.g. an importer that sets page_on_front) before validating the front page.`,
117129
)
@@ -120,8 +132,8 @@ export async function resolveEditorOpenTarget(
120132
return {
121133
...target,
122134
kind: "post",
123-
postId: frontPageId,
124-
url: `/wp-admin/post.php?post=${frontPageId}&action=edit`,
135+
postId,
136+
url: `/wp-admin/post.php?post=${postId}&action=edit`,
125137
}
126138
}
127139

@@ -137,6 +149,13 @@ echo $front_page_id;
137149
`
138150
}
139151

152+
function postSlugPostIdPhpCode(postSlug: string, postType: string): string {
153+
return `
154+
$post = get_page_by_path(${JSON.stringify(postSlug)}, OBJECT, ${JSON.stringify(postType)});
155+
echo $post instanceof WP_Post ? (int) $post->ID : 0;
156+
`
157+
}
158+
140159
export const EDITOR_VALIDATE_BLOCKS_DEFAULT_PROVIDER = "wordpress-block-editor"
141160

142161
export async function editorValidateContentFromArgs(args: string[]): Promise<string | undefined> {

tests/editor-actions.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,39 @@ assert.equal(resolved.postId, 57)
6363
assert.equal(resolved.url, "/wp-admin/post.php?post=57&action=edit")
6464
assert.deepEqual(resolveCalls, ["wordpress.editor-validate-blocks.resolve-front-page"])
6565

66+
// post-slug targets are also runtime-resolved, allowing recipe authors to target
67+
// imported pages by stable WordPress slug when the post id is created in an
68+
// earlier recipe step.
69+
const postSlugTarget = editorOpenTargetFromArgs(["post-type=page", "post-slug=contact"])
70+
assert.equal(postSlugTarget.kind, "post-slug")
71+
assert.equal(postSlugTarget.postType, "page")
72+
assert.equal(postSlugTarget.postSlug, "contact")
73+
assert.equal(postSlugTarget.url, "")
74+
const postSlugCalls: string[] = []
75+
const resolvedPostSlug = await resolveEditorOpenTarget(postSlugTarget, {
76+
command: "wordpress.editor-open",
77+
runPlaygroundCommand: async (command) => {
78+
postSlugCalls.push(command)
79+
return { ok: true, text: "91\n" } as never
80+
},
81+
runtimeSpec: { wp: "latest" } as never,
82+
server: { serverUrl: "http://localhost" } as never,
83+
})
84+
assert.equal(resolvedPostSlug.kind, "post")
85+
assert.equal(resolvedPostSlug.postId, 91)
86+
assert.equal(resolvedPostSlug.url, "/wp-admin/post.php?post=91&action=edit")
87+
assert.deepEqual(postSlugCalls, ["wordpress.editor-open.resolve-post-slug"])
88+
89+
await assert.rejects(
90+
resolveEditorOpenTarget(postSlugTarget, {
91+
command: "wordpress.editor-open",
92+
runPlaygroundCommand: async () => ({ ok: true, text: "0" } as never),
93+
runtimeSpec: { wp: "latest" } as never,
94+
server: { serverUrl: "http://localhost" } as never,
95+
}),
96+
/resolved no editable post/,
97+
)
98+
6699
// No static front page configured (page_on_front resolves to 0) is a real
67100
// misconfiguration, not a silent empty-editor open.
68101
await assert.rejects(

0 commit comments

Comments
 (0)