eddev 2.3.12 → 2.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/entry/MetaTags.d.ts.map +1 -1
- package/dist/app/entry/MetaTags.js +2 -0
- package/dist/app/lib/blocks/block-utils.d.ts +2 -2
- package/dist/app/lib/blocks/block-utils.d.ts.map +1 -1
- package/dist/app/lib/blocks/block-utils.js +10 -3
- package/dist/app/lib/blocks/editor/root-blocks.d.ts.map +1 -1
- package/dist/app/lib/blocks/editor/root-blocks.js +2 -2
- package/dist/app/lib/devtools/hooks/useTailwind.d.ts +45 -45
- package/dist/app/lib/hooks/query-hooks.d.ts +8 -8
- package/dist/app/lib/hooks/query-hooks.d.ts.map +1 -1
- package/dist/app/lib/hooks/query-hooks.js +2 -1
- package/dist/app/lib/runtime/apiConfig.d.ts +15 -0
- package/dist/app/lib/runtime/apiConfig.d.ts.map +1 -1
- package/dist/app/server/proxy-wp-admin.d.ts.map +1 -1
- package/dist/app/server/proxy-wp-admin.js +1 -0
- package/dist/app/server/server-context.d.ts +2 -2
- package/dist/app/server/server-context.d.ts.map +1 -1
- package/dist/app/utils/trpc-client.d.ts.map +1 -1
- package/dist/app/utils/trpc-client.js +19 -3
- package/dist/node/cli/version.d.ts +1 -1
- package/dist/node/cli/version.js +1 -1
- package/dist/node/compiler/dev-server.js +1 -1
- package/dist/node/compiler/get-vite-config.d.ts.map +1 -1
- package/dist/node/compiler/get-vite-config.js +1 -0
- package/dist/node/compiler/vinxi-app.d.ts +1 -1
- package/dist/node/compiler/vinxi-app.d.ts.map +1 -1
- package/dist/node/utils/fetch-wp.d.ts.map +1 -1
- package/dist/node/utils/fetch-wp.js +2 -1
- package/dist/node/utils/fs.d.ts +22 -19
- package/dist/node/utils/fs.d.ts.map +1 -1
- package/package.json +2 -2
- package/skills/eddev/SKILL.md +156 -0
- package/skills/eddev/docs/acf/admin-panel-widgets.mdx +99 -0
- package/skills/eddev/docs/acf/custom-enums.mdx +75 -0
- package/skills/eddev/docs/acf/custom-fields.mdx +131 -0
- package/skills/eddev/docs/acf.mdx +31 -0
- package/skills/eddev/docs/blocks/block-definition.mdx +189 -0
- package/skills/eddev/docs/blocks/core-blocks.mdx +86 -0
- package/skills/eddev/docs/blocks/data-and-editing.mdx +219 -0
- package/skills/eddev/docs/blocks/editor-config.mdx +157 -0
- package/skills/eddev/docs/blocks/nested-blocks.mdx +129 -0
- package/skills/eddev/docs/blocks/overview.mdx +58 -0
- package/skills/eddev/docs/blocks/template-parts.mdx +131 -0
- package/skills/eddev/docs/config.mdx +200 -0
- package/skills/eddev/docs/design/color.mdx +185 -0
- package/skills/eddev/docs/design/favicons.mdx +103 -0
- package/skills/eddev/docs/design/grid.mdx +120 -0
- package/skills/eddev/docs/design/icons.mdx +197 -0
- package/skills/eddev/docs/design/responsive-scaling.mdx +312 -0
- package/skills/eddev/docs/design/type.mdx +125 -0
- package/skills/eddev/docs/devtool/cli.mdx +201 -0
- package/skills/eddev/docs/devtool/overlay.mdx +5 -0
- package/skills/eddev/docs/getting-started.mdx +53 -0
- package/skills/eddev/docs/graphql/extending.mdx +186 -0
- package/skills/eddev/docs/graphql/fragments.mdx +107 -0
- package/skills/eddev/docs/graphql/global-data.mdx +47 -0
- package/skills/eddev/docs/graphql/infinite-queries.mdx +95 -0
- package/skills/eddev/docs/graphql/mutation-hooks.mdx +111 -0
- package/skills/eddev/docs/graphql/query-hooks.mdx +122 -0
- package/skills/eddev/docs/graphql/tooling.mdx +50 -0
- package/skills/eddev/docs/graphql.mdx +97 -0
- package/skills/eddev/docs/guides/color-schemes.mdx +204 -0
- package/skills/eddev/docs/guides/integrations.mdx +3 -0
- package/skills/eddev/docs/guides/page-transitions.mdx +5 -0
- package/skills/eddev/docs/guides/seo.mdx +5 -0
- package/skills/eddev/docs/guides/state-management.mdx +5 -0
- package/skills/eddev/docs/infra/caching.mdx +9 -0
- package/skills/eddev/docs/infra/deployment.mdx +13 -0
- package/skills/eddev/docs/infra/local.mdx +5 -0
- package/skills/eddev/docs/infra/security.mdx +11 -0
- package/skills/eddev/docs/routing/api.mdx +731 -0
- package/skills/eddev/docs/routing/custom.mdx +123 -0
- package/skills/eddev/docs/routing/full-details.mdx +37 -0
- package/skills/eddev/docs/routing/wordpress.mdx +70 -0
- package/skills/eddev/docs/routing.mdx +18 -0
- package/skills/eddev/docs/serverless/functions.mdx +436 -0
- package/skills/eddev/docs/serverless.mdx +202 -0
- package/skills/eddev/docs/snippets/automated-block-layouts.mdx +97 -0
- package/skills/eddev/docs/snippets/custom-routes-and-urls.mdx +91 -0
- package/skills/eddev/docs/snippets/multiple-editable-zones.mdx +87 -0
- package/skills/eddev/docs/snippets/querying-specific-blocks.mdx +164 -0
- package/skills/eddev/docs/snippets/submitting-forms-to-rpc.mdx +91 -0
- package/skills/eddev/docs/snippets/svgs.mdx +38 -0
- package/skills/eddev/docs/snippets/type-safe-acf-dropdowns.mdx +72 -0
- package/skills/eddev/docs/snippets.mdx +19 -0
- package/skills/eddev/docs/software.mdx +19 -0
- package/skills/eddev/docs/stack/how-it-works.mdx +50 -0
- package/skills/eddev/docs/stack/overview.mdx +56 -0
- package/skills/eddev/docs/stack/spa-vs-ssr.mdx +52 -0
- package/skills/eddev/docs/views/app-view.mdx +97 -0
- package/skills/eddev/docs/views/page-templates.mdx +82 -0
- package/skills/eddev/docs/views/queries.mdx +116 -0
- package/skills/eddev/docs/views.mdx +63 -0
- package/skills/eddev/index.mdx +79 -0
- package/tsconfig.app.json +2 -2
package/dist/node/utils/fs.d.ts
CHANGED
|
@@ -28,18 +28,23 @@ export declare const fs: {
|
|
|
28
28
|
encoding: "buffer";
|
|
29
29
|
withFileTypes?: false | undefined;
|
|
30
30
|
recursive?: boolean | undefined;
|
|
31
|
-
} | "buffer"): Promise<
|
|
31
|
+
} | "buffer"): Promise<NonSharedBuffer[]>;
|
|
32
32
|
readdir(path: import("fs").PathLike, options?: (import("fs").ObjectEncodingOptions & {
|
|
33
33
|
withFileTypes?: false | undefined;
|
|
34
34
|
recursive?: boolean | undefined;
|
|
35
|
-
}) | BufferEncoding | null): Promise<string[] |
|
|
35
|
+
}) | BufferEncoding | null): Promise<string[] | NonSharedBuffer[]>;
|
|
36
36
|
readdir(path: import("fs").PathLike, options: import("fs").ObjectEncodingOptions & {
|
|
37
37
|
withFileTypes: true;
|
|
38
38
|
recursive?: boolean | undefined;
|
|
39
39
|
}): Promise<import("fs").Dirent[]>;
|
|
40
|
+
readdir(path: import("fs").PathLike, options: {
|
|
41
|
+
encoding: "buffer";
|
|
42
|
+
withFileTypes: true;
|
|
43
|
+
recursive?: boolean | undefined;
|
|
44
|
+
}): Promise<import("fs").Dirent<NonSharedBuffer>[]>;
|
|
40
45
|
readlink(path: import("fs").PathLike, options?: import("fs").ObjectEncodingOptions | BufferEncoding | null): Promise<string>;
|
|
41
|
-
readlink(path: import("fs").PathLike, options: import("fs").BufferEncodingOption): Promise<
|
|
42
|
-
readlink(path: import("fs").PathLike, options?: import("fs").ObjectEncodingOptions | string | null): Promise<string |
|
|
46
|
+
readlink(path: import("fs").PathLike, options: import("fs").BufferEncodingOption): Promise<NonSharedBuffer>;
|
|
47
|
+
readlink(path: import("fs").PathLike, options?: import("fs").ObjectEncodingOptions | string | null): Promise<string | NonSharedBuffer>;
|
|
43
48
|
symlink(target: import("fs").PathLike, path: import("fs").PathLike, type?: string | null): Promise<void>;
|
|
44
49
|
lstat(path: import("fs").PathLike, opts?: import("fs").StatOptions & {
|
|
45
50
|
bigint?: false | undefined;
|
|
@@ -71,11 +76,11 @@ export declare const fs: {
|
|
|
71
76
|
chown(path: import("fs").PathLike, uid: number, gid: number): Promise<void>;
|
|
72
77
|
utimes(path: import("fs").PathLike, atime: import("fs").TimeLike, mtime: import("fs").TimeLike): Promise<void>;
|
|
73
78
|
realpath(path: import("fs").PathLike, options?: import("fs").ObjectEncodingOptions | BufferEncoding | null): Promise<string>;
|
|
74
|
-
realpath(path: import("fs").PathLike, options: import("fs").BufferEncodingOption): Promise<
|
|
75
|
-
realpath(path: import("fs").PathLike, options?: import("fs").ObjectEncodingOptions | BufferEncoding | null): Promise<string |
|
|
79
|
+
realpath(path: import("fs").PathLike, options: import("fs").BufferEncodingOption): Promise<NonSharedBuffer>;
|
|
80
|
+
realpath(path: import("fs").PathLike, options?: import("fs").ObjectEncodingOptions | BufferEncoding | null): Promise<string | NonSharedBuffer>;
|
|
76
81
|
mkdtemp(prefix: string, options?: import("fs").ObjectEncodingOptions | BufferEncoding | null): Promise<string>;
|
|
77
|
-
mkdtemp(prefix: string, options: import("fs").BufferEncodingOption): Promise<
|
|
78
|
-
mkdtemp(prefix: string, options?: import("fs").ObjectEncodingOptions | BufferEncoding | null): Promise<string |
|
|
82
|
+
mkdtemp(prefix: string, options: import("fs").BufferEncodingOption): Promise<NonSharedBuffer>;
|
|
83
|
+
mkdtemp(prefix: string, options?: import("fs").ObjectEncodingOptions | BufferEncoding | null): Promise<string | NonSharedBuffer>;
|
|
79
84
|
writeFile(file: import("fs").PathLike | nodeFs.FileHandle, data: string | NodeJS.ArrayBufferView | Iterable<string | NodeJS.ArrayBufferView> | AsyncIterable<string | NodeJS.ArrayBufferView> | import("stream"), options?: (import("fs").ObjectEncodingOptions & {
|
|
80
85
|
mode?: import("fs").Mode | undefined;
|
|
81
86
|
flag?: import("fs").OpenMode | undefined;
|
|
@@ -87,25 +92,23 @@ export declare const fs: {
|
|
|
87
92
|
readFile(path: import("fs").PathLike | nodeFs.FileHandle, options?: ({
|
|
88
93
|
encoding?: null | undefined;
|
|
89
94
|
flag?: import("fs").OpenMode | undefined;
|
|
90
|
-
} & import("events").Abortable) | null): Promise<
|
|
95
|
+
} & import("events").Abortable) | null): Promise<NonSharedBuffer>;
|
|
91
96
|
readFile(path: import("fs").PathLike | nodeFs.FileHandle, options: ({
|
|
92
97
|
encoding: BufferEncoding;
|
|
93
98
|
flag?: import("fs").OpenMode | undefined;
|
|
94
99
|
} & import("events").Abortable) | BufferEncoding): Promise<string>;
|
|
95
100
|
readFile(path: import("fs").PathLike | nodeFs.FileHandle, options?: (import("fs").ObjectEncodingOptions & import("events").Abortable & {
|
|
96
101
|
flag?: import("fs").OpenMode | undefined;
|
|
97
|
-
}) | BufferEncoding | null): Promise<string |
|
|
102
|
+
}) | BufferEncoding | null): Promise<string | NonSharedBuffer>;
|
|
98
103
|
opendir(path: import("fs").PathLike, options?: import("fs").OpenDirOptions): Promise<import("fs").Dir>;
|
|
99
|
-
watch(filename: import("fs").PathLike, options
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
watch(filename: import("fs").PathLike, options?: import("fs").WatchOptions | BufferEncoding): AsyncIterable<nodeFs.FileChangeInfo<string>>;
|
|
103
|
-
watch(filename: import("fs").PathLike, options: import("fs").WatchOptions | string): AsyncIterable<nodeFs.FileChangeInfo<string>> | AsyncIterable<nodeFs.FileChangeInfo<Buffer>>;
|
|
104
|
+
watch(filename: import("fs").PathLike, options?: nodeFs.WatchOptionsWithStringEncoding | BufferEncoding): NodeJS.AsyncIterator<nodeFs.FileChangeInfo<string>>;
|
|
105
|
+
watch(filename: import("fs").PathLike, options: nodeFs.WatchOptionsWithBufferEncoding | "buffer"): NodeJS.AsyncIterator<nodeFs.FileChangeInfo<NonSharedBuffer>>;
|
|
106
|
+
watch(filename: import("fs").PathLike, options: nodeFs.WatchOptions | BufferEncoding | "buffer"): NodeJS.AsyncIterator<nodeFs.FileChangeInfo<string | NonSharedBuffer>>;
|
|
104
107
|
cp(source: string | URL, destination: string | URL, opts?: import("fs").CopyOptions): Promise<void>;
|
|
105
|
-
glob(pattern: string | string[]): NodeJS.AsyncIterator<string>;
|
|
106
|
-
glob(pattern: string | string[],
|
|
107
|
-
glob(pattern: string | string[],
|
|
108
|
-
glob(pattern: string | string[],
|
|
108
|
+
glob(pattern: string | readonly string[]): NodeJS.AsyncIterator<string>;
|
|
109
|
+
glob(pattern: string | readonly string[], options: import("fs").GlobOptionsWithFileTypes): NodeJS.AsyncIterator<import("fs").Dirent>;
|
|
110
|
+
glob(pattern: string | readonly string[], options: import("fs").GlobOptionsWithoutFileTypes): NodeJS.AsyncIterator<string>;
|
|
111
|
+
glob(pattern: string | readonly string[], options: import("fs").GlobOptions): NodeJS.AsyncIterator<import("fs").Dirent | string>;
|
|
109
112
|
constants: typeof import("fs").constants;
|
|
110
113
|
};
|
|
111
114
|
//# sourceMappingURL=fs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../src/node/utils/fs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAGrC,eAAO,MAAM,EAAE;6BAEkB,MAAM,WAAW,MAAM;iCAWnB,MAAM,WAAW,GAAG;sBAW/B,MAAM,WAAW,GAAG;qBAGrB,MAAM;mBAIR,MAAM;mBAQN,MAAM;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../src/node/utils/fs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAGrC,eAAO,MAAM,EAAE;6BAEkB,MAAM,WAAW,MAAM;iCAWnB,MAAM,WAAW,GAAG;sBAW/B,MAAM,WAAW,GAAG;qBAGrB,MAAM;mBAIR,MAAM;mBAQN,MAAM;;;;;;;;;;;;iBAQs+0B,CAAC;;;;qBAAqkD,CAAC;iBAA8C,CAAC;;;;qBAAmjB,CAAC;iBAA8C,CAAC;;;qBAAwhB,CAAC;iBAA8C,CAAC;;;;iBAA2hB,CAAC;;;;;iBAA2c,CAAC;;;;;;;cAAu9F,CAAC;;;;;;;cAAoe,CAAC;;;;;;;cAAif,CAAC;;;;;;;;;;;;;;;;;;;;;YAA6rT,CAAC;YAAwC,CAAC;aAAoR,CAAC;;;aAAi2B,CAAC;;;gBAAosE,CAAC;YAAwC,CAAC;;;;YAAqoB,CAAC;;;YAAwrB,CAAC;;;;;;;;;;;;CADrkhD,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eddev",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.13",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"undent": "^0.1.0",
|
|
134
134
|
"undici": "6.21.0",
|
|
135
135
|
"valtio": "^2.3.1",
|
|
136
|
-
"vinxi": "
|
|
136
|
+
"vinxi": "0.5.11",
|
|
137
137
|
"vite-plugin-glsl": "^1.5.5",
|
|
138
138
|
"vite-tsconfig-paths": "4.3.2",
|
|
139
139
|
"zod": "^4.1.12"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: eddev
|
|
3
|
+
description: Work on ED.'s eddev WordPress + React/TypeScript stack. Use when you need to build, maintain, modify, debug, explain, or document eddev themes, including WordPress route resolution, React views and blocks, GraphQL data files, generated query hooks, ACF, serverless/RPC routes, SPA mode, SSR mode, the eddev CLI, and project conventions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# eddev
|
|
7
|
+
|
|
8
|
+
eddev is ED.'s stack for building WordPress-backed websites with React, TypeScript, GraphQL, and serverless rendering. Treat WordPress as the CMS and routing authority: WordPress resolves the requested URL, builds the route payload, and decides which React view should render. The React app renders that payload in either WordPress-hosted SPA mode or serverless SSR mode.
|
|
9
|
+
|
|
10
|
+
Use this skill to keep eddev work aligned with the real stack rather than generic WordPress, generic React, or generic Next.js assumptions.
|
|
11
|
+
|
|
12
|
+
## Best Practice
|
|
13
|
+
|
|
14
|
+
- Preserve WordPress as the source of truth for routes, content editing, admin state, custom post types, ACF fields, and route payloads.
|
|
15
|
+
- Keep React responsible for rendering views, blocks, app shell UI, interactive components, and project-specific frontend behavior.
|
|
16
|
+
- Use GraphQL files to select data. Do not imply ACF fields or WordPress objects are passed directly to components without a query layer.
|
|
17
|
+
- Prefer existing eddev APIs and project conventions before inventing abstractions.
|
|
18
|
+
- Keep examples type-safe and source-backed. Use generated types and generated query hooks when docs or project code expose them.
|
|
19
|
+
- Separate route/render data from runtime browser data. View, block, and app GraphQL files support route rendering; `queries/*.graphql` files support generated runtime hooks.
|
|
20
|
+
- Route runtime GraphQL through named REST endpoints and generated hooks. Do not describe eddev as exposing arbitrary public GraphQL text posts from the browser.
|
|
21
|
+
- Use serverless/RPC routes for backend TypeScript procedures that belong in `server/routes/**/*.{ts,tsx}`.
|
|
22
|
+
- Keep docs and explanations practical for ED developers. Prefer direct file paths, workflow steps, and small representative examples.
|
|
23
|
+
|
|
24
|
+
## Stack Basics
|
|
25
|
+
|
|
26
|
+
The normal eddev project combines:
|
|
27
|
+
|
|
28
|
+
- WordPress and PHP for routing, admin, content editing, custom post types, ACF, REST endpoints, and route payload generation.
|
|
29
|
+
- React and TypeScript for views, blocks, app layout, interactive UI, and server routes.
|
|
30
|
+
- GraphQL and WPGraphQL for view data, block props, app shell data, fragments, runtime queries, and runtime mutations.
|
|
31
|
+
- The eddev CLI for discovering files, generating TypeScript outputs, running development servers, and building SPA or serverless output.
|
|
32
|
+
- Local for local WordPress development, WP Engine for the WordPress origin, and Vercel or another serverless target for public SSR traffic.
|
|
33
|
+
|
|
34
|
+
The key request flow is:
|
|
35
|
+
|
|
36
|
+
1. WordPress resolves the URL through the normal template hierarchy.
|
|
37
|
+
2. eddev maps the resolved template to a React view in `views/`.
|
|
38
|
+
3. eddev runs the paired view GraphQL file when one exists.
|
|
39
|
+
4. WordPress returns a route payload containing the matched view, `viewData`, app data, metadata, admin context, and debug data when available.
|
|
40
|
+
5. In SSR mode, the JavaScript server renders the matching React view to HTML and hydrates in the browser.
|
|
41
|
+
6. In SPA mode, WordPress serves the app shell and payload, then the browser renders the view client-side.
|
|
42
|
+
|
|
43
|
+
Blocks follow the same split: WordPress and ACF own editor data, `blocks/**/*.graphql` selects the public props, and React block components render the frontend output.
|
|
44
|
+
|
|
45
|
+
## Common File Conventions
|
|
46
|
+
|
|
47
|
+
- `views/*.tsx` defines React views, usually with `defineView("name", component)`.
|
|
48
|
+
- `views/*.graphql` selects data for the paired view.
|
|
49
|
+
- `views/_app.tsx` defines the shared app shell.
|
|
50
|
+
- `views/_app.graphql` selects global app data.
|
|
51
|
+
- `blocks/**/*.tsx` defines React blocks, usually with `export const meta: BlockMeta` and `defineBlock("folder/name", component)`.
|
|
52
|
+
- `blocks/**/*.graphql` selects public block props from WordPress and ACF data.
|
|
53
|
+
- `queries/fragments/*.graphql` contains reusable GraphQL fragments.
|
|
54
|
+
- `queries/*.graphql` creates generated runtime query or mutation hooks.
|
|
55
|
+
- `server/routes/**/*.{ts,tsx}` defines TypeScript RPC/serverless procedures through `eddev/server`.
|
|
56
|
+
- `ed.config.json` configures project-level eddev behavior.
|
|
57
|
+
|
|
58
|
+
## Referring To The Docs
|
|
59
|
+
|
|
60
|
+
Use the synced docs in this skill before answering detailed eddev questions. Start with the table of contents below, then read only the relevant `.mdx` files needed for the user's task.
|
|
61
|
+
|
|
62
|
+
- For the high-level model, read `docs/stack/overview.mdx`, `docs/stack/how-it-works.mdx`, and `docs/stack/spa-vs-ssr.mdx`.
|
|
63
|
+
- For project setup and commands, read `docs/getting-started.mdx`, `docs/software.mdx`, and `docs/devtool/cli.mdx`.
|
|
64
|
+
- For routing, read `docs/routing.mdx` and the nested routing pages.
|
|
65
|
+
- For data work, read `docs/graphql.mdx` and the matching nested page for fragments, query hooks, mutation hooks, infinite queries, global data, tooling, or schema extensions.
|
|
66
|
+
- For page templates, read `docs/views.mdx` and the nested views pages.
|
|
67
|
+
- For Gutenberg blocks, read `docs/blocks/overview.mdx` and the nested blocks pages.
|
|
68
|
+
- For ACF, read `docs/acf.mdx` and the nested ACF pages.
|
|
69
|
+
- For serverless behavior, read `docs/serverless.mdx` and `docs/serverless/functions.mdx`.
|
|
70
|
+
- For quick implementation patterns, read the relevant page under `docs/snippets/`.
|
|
71
|
+
|
|
72
|
+
When writing docs or code comments, cite the public docs path in prose, such as `/docs/graphql/query-hooks`, rather than exposing this skill folder path to readers.
|
|
73
|
+
|
|
74
|
+
Do not hand-edit the generated contents block below. `scripts/update-skill.js` keeps it synced from `skills/eddev/index.mdx`.
|
|
75
|
+
|
|
76
|
+
<!-- START TOC -->
|
|
77
|
+
|
|
78
|
+
- Stack
|
|
79
|
+
- [Overview](docs/stack/overview.mdx): Understand the main technologies and hosting shape behind eddev sites.
|
|
80
|
+
- [How It Works](docs/stack/how-it-works.mdx): Follow the end-to-end request flow for an eddev page.
|
|
81
|
+
- [SPA vs SSR](docs/stack/spa-vs-ssr.mdx): Compare WordPress-hosted SPA mode with serverless SSR mode.
|
|
82
|
+
- [Software and Tooling](docs/software.mdx): Tools we use to build, edit, and run eddev projects.
|
|
83
|
+
|
|
84
|
+
- **Guides**
|
|
85
|
+
- [Getting Started](docs/getting-started.mdx): Set up a new eddev project from the starter theme.
|
|
86
|
+
- Dev Tools
|
|
87
|
+
- [eddev CLI](docs/devtool/cli.mdx): Run development, builds, codegen, and diagnostics through the eddev CLI.
|
|
88
|
+
- [Dev Overlay](docs/devtool/overlay.mdx): Use the in-browser development overlay while working on eddev sites.
|
|
89
|
+
- Infrastructure
|
|
90
|
+
- [Deployment](docs/infra/deployment.mdx): A placeholder for deployment workflows across GitHub, Vercel, and Cloudflare.
|
|
91
|
+
- [Local](docs/infra/local.mdx): A placeholder for Local setup and push-pull workflow guidance.
|
|
92
|
+
- [Security](docs/infra/security.mdx): A placeholder for origin protection and secret management guidance.
|
|
93
|
+
- [Caching](docs/infra/caching.mdx): A placeholder for eddev cache configuration and deployment layers.
|
|
94
|
+
- Design System
|
|
95
|
+
- [Colours](docs/design/color.mdx): Configure colour tokens and Figma handoff output for Tailwind.
|
|
96
|
+
- [Typography](docs/design/type.mdx): Configure typography tokens through Tailwind helper classes.
|
|
97
|
+
- [Using Icons](docs/design/icons.mdx): Export and use Figma icons as React-friendly SVG components.
|
|
98
|
+
- [Grid System](docs/design/grid.mdx): Configure grid tokens, gutters, and layout utilities.
|
|
99
|
+
- [Responsive Scaling](docs/design/responsive-scaling.mdx): Configure responsive Tailwind tokens with the local helper.
|
|
100
|
+
- [Favicons](docs/design/favicons.mdx): Configure how eddev generates or delegates favicon assets.
|
|
101
|
+
- More Guides
|
|
102
|
+
- [Colour Schemes](docs/guides/color-schemes.mdx): Define named visual schemes with Tailwind semantic tokens.
|
|
103
|
+
- [Integrations](docs/guides/integrations.mdx): A placeholder for third-party integration guidance.
|
|
104
|
+
- [Page Transitions](docs/guides/page-transitions.mdx): A placeholder for page transition patterns in eddev sites.
|
|
105
|
+
- [SEO](docs/guides/seo.mdx): A placeholder for SEO patterns in eddev sites.
|
|
106
|
+
- [State Management](docs/guides/state-management.mdx): A placeholder for state management guidance in eddev sites.
|
|
107
|
+
- Snippets
|
|
108
|
+
- [Overview](docs/snippets.mdx): Situation-based recipes from real eddev themes
|
|
109
|
+
- [Querying Specific Blocks](docs/snippets/querying-specific-blocks.mdx): Select, split, and render only the block content you need
|
|
110
|
+
- [Type-Safe ACF Dropdowns](docs/snippets/type-safe-acf-dropdowns.mdx): Register one enum field and use its generated TypeScript type
|
|
111
|
+
- [Multiple Editable Zones](docs/snippets/multiple-editable-zones.mdx): Use SlotBlocks when one block needs more than one child area
|
|
112
|
+
- [Automated Block Layouts](docs/snippets/automated-block-layouts.mdx): Use block flags and wrapBlock to keep layout rules out of every block
|
|
113
|
+
- [Submitting Forms To RPC](docs/snippets/submitting-forms-to-rpc.mdx): Create a serverless mutation and call it from React
|
|
114
|
+
- [Custom Routes And URLs](docs/snippets/custom-routes-and-urls.mdx): Map fixed URLs to views and keep generated WordPress links aligned
|
|
115
|
+
- [SVGs](docs/snippets/svgs.mdx): Copy/paste SVG upload and GraphQL snippets
|
|
116
|
+
|
|
117
|
+
- **Components**
|
|
118
|
+
- [Configuration](docs/config.mdx): Configure eddev projects with theme-level JSON settings.
|
|
119
|
+
- Routing
|
|
120
|
+
- [Routing Overview](docs/routing.mdx): Understand the WordPress and frontend sides of eddev routing.
|
|
121
|
+
- [Custom Routes](docs/routing/custom.mdx): Register fixed WordPress-backed routes for app-like screens.
|
|
122
|
+
- [WordPress Routing](docs/routing/wordpress.mdx): Let WordPress resolve URLs while React renders the matched view.
|
|
123
|
+
- [Frontend Routing APIs](docs/routing/api.mdx): Use eddev routing APIs for links, preloading, and client navigation.
|
|
124
|
+
- [How it Works](docs/routing/full-details.mdx): Trace how eddev loads route data for SPA and serverless navigation.
|
|
125
|
+
- GraphQL
|
|
126
|
+
- [Overview](docs/graphql.mdx): Working with GraphQL in eddev
|
|
127
|
+
- [Global Data](docs/graphql/global-data.mdx): Fetch shared site shell data through views/_app.graphql.
|
|
128
|
+
- [GraphQL Fragments](docs/graphql/fragments.mdx): Share GraphQL selections and generated fragment types across queries.
|
|
129
|
+
- [Query Hooks](docs/graphql/query-hooks.mdx): Generate browser runtime query hooks from files in queries.
|
|
130
|
+
- [Mutation Hooks](docs/graphql/mutation-hooks.mdx): Generate mutation hooks for runtime GraphQL operations with side effects.
|
|
131
|
+
- [Infinite Queries](docs/graphql/infinite-queries.mdx): Build load-more interfaces with generated infinite query hooks.
|
|
132
|
+
- [Extending the GraphQL Schema](docs/graphql/extending.mdx): Extend WPGraphQL when frontend data needs custom schema fields.
|
|
133
|
+
- [GraphQL Tooling](docs/graphql/tooling.mdx): Use generated schema files with editor tooling and GraphiQL.
|
|
134
|
+
- Views
|
|
135
|
+
- [Views](docs/views.mdx): Page and post-type templates
|
|
136
|
+
- [_app.tsx Layout](docs/views/app-view.mdx): Common site layout
|
|
137
|
+
- [Page Templates](docs/views/page-templates.mdx): Selectable templates for pages and post types
|
|
138
|
+
- [View Data](docs/views/queries.mdx): Pipe WordPress data into your templates
|
|
139
|
+
- Blocks
|
|
140
|
+
- [Overview](docs/blocks/overview.mdx): The basics of creating Gutenberg blocks
|
|
141
|
+
- [Defining a block](docs/blocks/block-definition.mdx): How to create a new block type
|
|
142
|
+
- [Data and Editing](docs/blocks/data-and-editing.mdx): GraphQL props, inline content, and core block rendering
|
|
143
|
+
- [Configuring the Editor](docs/blocks/editor-config.mdx): Control which blocks authors can use
|
|
144
|
+
- [Nested Blocks](docs/blocks/nested-blocks.mdx): Blocks within blocks
|
|
145
|
+
- [Template Parts](docs/blocks/template-parts.mdx): Reusable site sections powered by blocks
|
|
146
|
+
- [Core Blocks](docs/blocks/core-blocks.mdx): Working with WordPress core blocks in eddev
|
|
147
|
+
- ACF
|
|
148
|
+
- [ACF](docs/acf.mdx): Custom ACF fields, enum field shortcuts, and React widgets for WordPress admin screens.
|
|
149
|
+
- [Custom Fields](docs/acf/custom-fields.mdx): Build a custom ACF field type with PHP storage and React editing UI.
|
|
150
|
+
- [Custom Enums](docs/acf/custom-enums.mdx): Register reusable typed ACF choice fields without writing a full custom field UI.
|
|
151
|
+
- [Admin Panel Widgets](docs/acf/admin-panel-widgets.mdx): Mount React widgets inside custom WordPress admin pages.
|
|
152
|
+
- Serverless
|
|
153
|
+
- [Serverless](docs/serverless.mdx): Run the public eddev frontend on Vercel while WordPress owns content and routing.
|
|
154
|
+
- [RPC Functions](docs/serverless/functions.mdx): Define TypeScript RPC routes for serverless eddev projects.
|
|
155
|
+
|
|
156
|
+
<!-- END TOC -->
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Admin Panel Widgets (/docs/acf/admin-panel-widgets)
|
|
2
|
+
|
|
3
|
+
**Mount React widgets inside custom WordPress admin pages.**
|
|
4
|
+
|
|
5
|
+
Admin panel widgets are not ACF fields. They are React components mounted into WordPress admin screens, useful for project tools such as sync panels, importers, reports, or asset managers.
|
|
6
|
+
|
|
7
|
+
The SFF site uses this pattern for festival sync tooling and film asset management. The reusable shape is simpler than those production tools: create a widget TSX file, print a matching `data-widget` element from PHP, and enable the eddev admin assets on that screen.
|
|
8
|
+
|
|
9
|
+
## Create The Widget [#create-the-widget]
|
|
10
|
+
|
|
11
|
+
Widget files live in `backend/widgets/*.tsx`. The file slug is what PHP uses in `data-widget`.
|
|
12
|
+
|
|
13
|
+
```tsx filename="backend/widgets/content-sync.tsx"
|
|
14
|
+
import { defineWidget } from "eddev/admin"
|
|
15
|
+
import { useState } from "react"
|
|
16
|
+
|
|
17
|
+
export default defineWidget("content-sync", () => {
|
|
18
|
+
const [message, setMessage] = useState<string | null>(null)
|
|
19
|
+
const [busy, setBusy] = useState(false)
|
|
20
|
+
|
|
21
|
+
async function runSync() {
|
|
22
|
+
setBusy(true)
|
|
23
|
+
setMessage(null)
|
|
24
|
+
|
|
25
|
+
const response = await fetch("/wp-json/site/v1/sync-content", {
|
|
26
|
+
method: "POST",
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
setBusy(false)
|
|
30
|
+
setMessage(response.ok ? "Sync complete." : "Sync failed.")
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className="postbox p-4">
|
|
35
|
+
<p>Run the latest content sync.</p>
|
|
36
|
+
<button className="button button-primary" disabled={busy} onClick={runSync}>
|
|
37
|
+
{busy ? "Syncing..." : "Run sync"}
|
|
38
|
+
</button>
|
|
39
|
+
{message && <p>{message}</p>}
|
|
40
|
+
</div>
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Keep the `defineWidget` name and the filename slug the same. eddev discovers the file from `backend/widgets/content-sync.tsx`, and the admin page mounts it with `data-widget="content-sync"`.
|
|
46
|
+
|
|
47
|
+
## Add A WordPress Admin Page [#add-a-wordpress-admin-page]
|
|
48
|
+
|
|
49
|
+
The PHP side can live wherever your backend include file loads project systems. Large sites often keep this near the system it controls, for example under `backend/systems/*/*.php`.
|
|
50
|
+
|
|
51
|
+
```php filename="backend/systems/content-sync/content-sync-admin.php"
|
|
52
|
+
<?php
|
|
53
|
+
|
|
54
|
+
use ED\AdminAssets;
|
|
55
|
+
|
|
56
|
+
add_action("admin_menu", function () {
|
|
57
|
+
add_menu_page(
|
|
58
|
+
"Content Sync",
|
|
59
|
+
"Content Sync",
|
|
60
|
+
"edit_theme_options",
|
|
61
|
+
"content-sync",
|
|
62
|
+
"showContentSyncAdminPage",
|
|
63
|
+
"dashicons-update",
|
|
64
|
+
31
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
add_filter("ed_should_enqueue_admin_scripts", function ($enabled, $screen) {
|
|
68
|
+
if ($screen->id === "toplevel_page_content-sync") {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return $enabled;
|
|
73
|
+
}, 10, 2);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
function showContentSyncAdminPage() {
|
|
77
|
+
AdminAssets::$enabled = true;
|
|
78
|
+
?>
|
|
79
|
+
<div class="wrap">
|
|
80
|
+
<h1 class="wp-heading-inline">Content Sync</h1>
|
|
81
|
+
<div data-widget="content-sync"></div>
|
|
82
|
+
</div>
|
|
83
|
+
<?php
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`AdminAssets` loads the eddev admin bundle. The widget runner scans the page for `[data-widget]` elements and mounts the matching React widget.
|
|
88
|
+
|
|
89
|
+
## Data Access [#data-access]
|
|
90
|
+
|
|
91
|
+
Widgets can call normal WordPress REST endpoints with `fetch`. They can also use generated query hooks when the data is exposed through committed `queries/**/*.graphql` files.
|
|
92
|
+
|
|
93
|
+
Use a widget when the screen is an operational tool rather than page content. For example:
|
|
94
|
+
|
|
95
|
+
* a sync panel that starts a background import and reports progress
|
|
96
|
+
* an asset manager that lets editors inspect and update media for a post type
|
|
97
|
+
* a small admin dashboard that combines project-specific status checks
|
|
98
|
+
|
|
99
|
+
If the UI is meant to edit a single ACF value inside a field group, build a [custom field](/docs/acf/custom-fields) instead.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Custom Enums (/docs/acf/custom-enums)
|
|
2
|
+
|
|
3
|
+
**Register reusable typed ACF choice fields without writing a full custom field UI.**
|
|
4
|
+
|
|
5
|
+
Custom enums are shorthand for semi-custom ACF fields. They create a named ACF field type backed by a normal ACF choice control, then expose that value to GraphQL as a generated TypeScript-friendly scalar.
|
|
6
|
+
|
|
7
|
+
Use them for repeated dropdowns like colour schemes, content tones, states, categories, or display modes.
|
|
8
|
+
|
|
9
|
+
## Register An Enum Field [#register-an-enum-field]
|
|
10
|
+
|
|
11
|
+
Put enum registrations in `backend/fields/*.php`.
|
|
12
|
+
|
|
13
|
+
```php filename="backend/fields/content-tone.php"
|
|
14
|
+
<?php
|
|
15
|
+
|
|
16
|
+
ED()->registerEnumFieldType("content-tone", [
|
|
17
|
+
"label" => "Content Tone",
|
|
18
|
+
"type" => "select",
|
|
19
|
+
"options" => [
|
|
20
|
+
"neutral" => "Neutral",
|
|
21
|
+
"festival" => "Festival",
|
|
22
|
+
"urgent" => "Urgent",
|
|
23
|
+
],
|
|
24
|
+
]);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The enum field type slug is `content-tone`. Add that field type to any ACF field group where authors should choose one of those values.
|
|
28
|
+
|
|
29
|
+
`type` controls the underlying ACF editing control:
|
|
30
|
+
|
|
31
|
+
| Type | Use It For |
|
|
32
|
+
| -------------- | ------------------------------------------------------------ |
|
|
33
|
+
| `select` | The default choice for most dropdowns. |
|
|
34
|
+
| `button_group` | Short visual choices with only a few options. |
|
|
35
|
+
| `radio` | Choices that should stay visible without opening a dropdown. |
|
|
36
|
+
| `checkbox` | Multiple selected values. |
|
|
37
|
+
|
|
38
|
+
`checkbox` returns a list of enum values in GraphQL. The other types return one value or `null`.
|
|
39
|
+
|
|
40
|
+
## Query The Field [#query-the-field]
|
|
41
|
+
|
|
42
|
+
Once the field has been added to ACF, select it from the relevant view or block query.
|
|
43
|
+
|
|
44
|
+
```graphql filename="blocks/content/callout.graphql"
|
|
45
|
+
query {
|
|
46
|
+
block {
|
|
47
|
+
content_callout {
|
|
48
|
+
tone
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
eddev derives the generated type name from the field slug. `content-tone` becomes `ContentToneOption`.
|
|
55
|
+
|
|
56
|
+
```tsx filename="blocks/content/callout.tsx"
|
|
57
|
+
import { defineBlock } from "eddev/blocks"
|
|
58
|
+
import type { ContentToneOption } from "@generated-types"
|
|
59
|
+
|
|
60
|
+
const toneClasses: Record<ContentToneOption, string> = {
|
|
61
|
+
neutral: "theme-neutral",
|
|
62
|
+
festival: "theme-festival",
|
|
63
|
+
urgent: "theme-urgent",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default defineBlock("content/callout", (props) => {
|
|
67
|
+
const tone = props.tone ?? "neutral"
|
|
68
|
+
|
|
69
|
+
return <section className={toneClasses[tone]}>...</section>
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Keep the PHP options and React mapping together during review. If a new enum option is added, TypeScript should force the component to decide how that option renders.
|
|
74
|
+
|
|
75
|
+
For a more recipe-style dropdown example, see [Type-Safe ACF Dropdowns](/docs/snippets/type-safe-acf-dropdowns).
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Custom Fields (/docs/acf/custom-fields)
|
|
2
|
+
|
|
3
|
+
**Build a custom ACF field type with PHP storage and React editing UI.**
|
|
4
|
+
|
|
5
|
+
Custom fields are for reusable editor controls that need more than a built-in ACF input. A field has two sides:
|
|
6
|
+
|
|
7
|
+
* a PHP file that registers the ACF field type and its GraphQL shape
|
|
8
|
+
* a React file that renders the editing control in WordPress admin
|
|
9
|
+
|
|
10
|
+
Put both files in `backend/fields` and keep the slug consistent across the PHP registration, the TSX filename, and the ACF field type.
|
|
11
|
+
|
|
12
|
+
## Register The PHP Field [#register-the-php-field]
|
|
13
|
+
|
|
14
|
+
The PHP file is loaded by the backend include path. Starter themes include `backend/fields/*.php` from `backend/includes.php`.
|
|
15
|
+
|
|
16
|
+
```php filename="backend/fields/event-link.php"
|
|
17
|
+
<?php
|
|
18
|
+
|
|
19
|
+
ED()->registerFieldType("event-link", [
|
|
20
|
+
"label" => "Event Link",
|
|
21
|
+
"type" => "EventLink",
|
|
22
|
+
"objectType" => [
|
|
23
|
+
"fields" => [
|
|
24
|
+
"label" => ["type" => "String"],
|
|
25
|
+
"url" => ["type" => "String"],
|
|
26
|
+
"opensInNewTab" => ["type" => "Boolean"],
|
|
27
|
+
],
|
|
28
|
+
],
|
|
29
|
+
"resolve" => function ($root, $args, $context, $info, $value) {
|
|
30
|
+
return is_array($value) ? $value : null;
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`registerFieldType` makes `event-link` available as an ACF field type. The `type` value is the GraphQL type returned when a GraphQL file selects this field.
|
|
36
|
+
|
|
37
|
+
Use `objectType` for small structured values. For richer project data, register GraphQL types and resolvers explicitly, then set `type` to the GraphQL type name.
|
|
38
|
+
|
|
39
|
+
## Add The React Editor [#add-the-react-editor]
|
|
40
|
+
|
|
41
|
+
The React file is discovered by eddev's admin manifest from `backend/fields/*.tsx`. Its filename must match the ACF field type slug.
|
|
42
|
+
|
|
43
|
+
```tsx filename="backend/fields/event-link.tsx"
|
|
44
|
+
import { defineField } from "eddev/admin"
|
|
45
|
+
|
|
46
|
+
type EventLinkValue = {
|
|
47
|
+
label?: string
|
|
48
|
+
url?: string
|
|
49
|
+
opensInNewTab?: boolean
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default defineField<EventLinkValue>({
|
|
53
|
+
defaultValue: {},
|
|
54
|
+
render({ value, onChange }) {
|
|
55
|
+
return (
|
|
56
|
+
<div className="stack-y-2">
|
|
57
|
+
<label>
|
|
58
|
+
<span>Label</span>
|
|
59
|
+
<input
|
|
60
|
+
className="regular-text"
|
|
61
|
+
value={value.label ?? ""}
|
|
62
|
+
onChange={(event) => {
|
|
63
|
+
onChange({ ...value, label: event.target.value })
|
|
64
|
+
}}
|
|
65
|
+
/>
|
|
66
|
+
</label>
|
|
67
|
+
|
|
68
|
+
<label>
|
|
69
|
+
<span>URL</span>
|
|
70
|
+
<input
|
|
71
|
+
className="regular-text"
|
|
72
|
+
value={value.url ?? ""}
|
|
73
|
+
onChange={(event) => {
|
|
74
|
+
onChange({ ...value, url: event.target.value })
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
77
|
+
</label>
|
|
78
|
+
|
|
79
|
+
<label>
|
|
80
|
+
<input
|
|
81
|
+
type="checkbox"
|
|
82
|
+
checked={!!value.opensInNewTab}
|
|
83
|
+
onChange={(event) => {
|
|
84
|
+
onChange({ ...value, opensInNewTab: event.target.checked })
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
Open in a new tab
|
|
88
|
+
</label>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`defineField` receives the current value and an `onChange` callback. eddev stores the React value in ACF through a hidden JSON input, then the PHP side can normalize or resolve it for GraphQL.
|
|
96
|
+
|
|
97
|
+
## Use The Field In ACF [#use-the-field-in-acf]
|
|
98
|
+
|
|
99
|
+
After the PHP field type is registered, add it to a field group in ACF like any other field type. The field can live on a block, post type, options page, taxonomy, or other ACF location.
|
|
100
|
+
|
|
101
|
+
When a block or view selects that field, GraphQL receives the resolved value:
|
|
102
|
+
|
|
103
|
+
```graphql filename="blocks/content/event-card.graphql"
|
|
104
|
+
query {
|
|
105
|
+
block {
|
|
106
|
+
content_event_card {
|
|
107
|
+
cta {
|
|
108
|
+
label
|
|
109
|
+
url
|
|
110
|
+
opensInNewTab
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```tsx filename="blocks/content/event-card.tsx"
|
|
118
|
+
import { defineBlock } from "eddev/blocks"
|
|
119
|
+
|
|
120
|
+
export default defineBlock("content/event-card", (props) => {
|
|
121
|
+
if (!props.cta?.url) return null
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<a href={props.cta.url} target={props.cta.opensInNewTab ? "_blank" : undefined}>
|
|
125
|
+
{props.cta.label ?? "Read more"}
|
|
126
|
+
</a>
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Keep custom fields focused. If the editor only needs a fixed list of choices, use a [custom enum field](/docs/acf/custom-enums) instead.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# ACF (/docs/acf)
|
|
2
|
+
|
|
3
|
+
**Custom ACF fields, enum field shortcuts, and React widgets for WordPress admin screens.**
|
|
4
|
+
|
|
5
|
+
Use this section when normal ACF fields are not enough for a site-specific editing workflow.
|
|
6
|
+
|
|
7
|
+
Most day-to-day block and view data should still use ordinary ACF fields selected through GraphQL. Reach for these tools when the editor needs a reusable control, a typed dropdown used across field groups, or a custom admin screen that runs React.
|
|
8
|
+
|
|
9
|
+
<Cards>
|
|
10
|
+
<Card title="Custom Fields" href="/docs/acf/custom-fields">
|
|
11
|
+
Pair a PHP field registration with a React editor control in `backend/fields`.
|
|
12
|
+
</Card>
|
|
13
|
+
|
|
14
|
+
<Card title="Custom Enums" href="/docs/acf/custom-enums">
|
|
15
|
+
Register a typed select, radio, button group, or checkbox field without writing React.
|
|
16
|
+
</Card>
|
|
17
|
+
|
|
18
|
+
<Card title="Admin Panel Widgets" href="/docs/acf/admin-panel-widgets">
|
|
19
|
+
Mount React widgets inside custom WordPress admin pages.
|
|
20
|
+
</Card>
|
|
21
|
+
</Cards>
|
|
22
|
+
|
|
23
|
+
## Which Tool To Use [#which-tool-to-use]
|
|
24
|
+
|
|
25
|
+
| Need | Use |
|
|
26
|
+
| -------------------------------------------------------------- | ---------------------------------------------------- |
|
|
27
|
+
| A field with custom React editing UI and custom GraphQL output | [Custom Fields](/docs/acf/custom-fields) |
|
|
28
|
+
| A reusable typed dropdown or button group | [Custom Enums](/docs/acf/custom-enums) |
|
|
29
|
+
| A custom admin screen, importer, sync tool, or asset manager | [Admin Panel Widgets](/docs/acf/admin-panel-widgets) |
|
|
30
|
+
|
|
31
|
+
Custom fields and enums are still ACF field types. Admin panel widgets are separate from ACF, but they use the same eddev admin bundle and are useful for adjacent WordPress editing tools.
|