├── .eslintrc.yml
├── .github
└── workflows
│ ├── publish-latest-plugin-zip.yml
│ └── release.yml
├── .gitignore
├── .prettierrc.js
├── LICENSE.md
├── README.md
├── blueprint.json
├── create-content-model.php
├── dev.json
├── get-started.md
├── includes
├── exporter
│ ├── 0-load.php
│ ├── class-content-model-exporter.php
│ └── template
│ │ ├── README.md
│ │ └── includes
│ │ └── json-initializer
│ │ ├── 0-load.php
│ │ └── class-content-model-json-initializer.php
├── manager
│ ├── 0-load.php
│ ├── class-content-model-loader.php
│ ├── manager.js
│ └── src
│ │ ├── components
│ │ ├── attribute-binder-panel.js
│ │ ├── cpt-settings-panel.js
│ │ ├── edit-block.js
│ │ ├── edit-field.js
│ │ ├── fields-ui.js
│ │ └── manage-bindings.js
│ │ ├── constants.js
│ │ ├── hooks
│ │ ├── use-content-model-name-validation.js
│ │ └── use-default-value-placeholder-changer.js
│ │ ├── register-attribute-binder.js
│ │ ├── register-content-model-name-validation.js
│ │ ├── register-cpt-settings-panel.js
│ │ ├── register-default-value-placeholder-changer.js
│ │ └── register-fields-ui.js
└── runtime
│ ├── 0-load.php
│ ├── class-content-model-block.php
│ ├── class-content-model-data-hydrator.php
│ ├── class-content-model-html-manipulator.php
│ ├── class-content-model-manager.php
│ ├── class-content-model.php
│ ├── data-entry.js
│ ├── helpers.php
│ ├── src
│ ├── components
│ │ ├── block-variation-updater.js
│ │ └── fields-ui.js
│ ├── constants.js
│ ├── hooks
│ │ ├── use-bound-group-extractor.js
│ │ ├── use-content-locking.js
│ │ └── use-fallback-value-clearer.js
│ ├── register-block-variation-updater.js
│ ├── register-bound-group-extractor.js
│ ├── register-content-locking.js
│ ├── register-fallback-value-clearer.js
│ └── register-fields-ui.js
│ └── templating.js
├── package-lock.json
├── package.json
├── phpcs.xml
└── webpack.config.js
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | root: true
2 | env:
3 | es6: true
4 | browser: true
5 | jest: true
6 | extends:
7 | - plugin:@wordpress/eslint-plugin/recommended
8 | rules:
9 | '@wordpress/no-unsafe-wp-apis': off
10 | 'import/no-extraneous-dependencies': off
11 |
--------------------------------------------------------------------------------
/.github/workflows/publish-latest-plugin-zip.yml:
--------------------------------------------------------------------------------
1 | name: Publish plugin to Automattic/create-content-model-releases latest on trunk merge
2 |
3 | on:
4 | push:
5 | branches:
6 | - trunk
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Checkout code
14 | uses: actions/checkout@v4
15 | with:
16 | fetch-depth: 0
17 |
18 | - name: Get most recent tag
19 | id: get_tag
20 | uses: WyriHaximus/github-action-get-previous-tag@v1
21 | with:
22 | fallback: 1.0.0
23 |
24 | - name: Update version to latest trunk commit
25 | run: "find . -type f -exec sed -i 's/0.0.0-placeholder/${{ steps.get_tag.outputs.tag }}-dev-${{ github.sha }}/g' {} +"
26 |
27 | - name: Setup Node.js
28 | uses: actions/setup-node@v4
29 | with:
30 | node-version: "20"
31 |
32 | - name: Install dependencies
33 | run: npm ci
34 |
35 | - name: Build and create plugin zip
36 | run: npm run plugin-zip
37 |
38 | - name: Create output directory
39 | run: mkdir -p output
40 |
41 | - name: Move plugin zip to output/
42 | run: mv create-content-model.zip output/
43 |
44 | - name: Get user email
45 | id: get_email
46 | run: |
47 | EMAIL=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
48 | https://api.github.com/users/${{ github.actor }} \
49 | | jq -r '.email // empty')
50 | if [ -z "$EMAIL" ]; then
51 | EMAIL="${{ github.actor }}@users.noreply.github.com"
52 | fi
53 | echo "email=$EMAIL" >> $GITHUB_OUTPUT
54 |
55 | - name: Push zip to another repository
56 | uses: cpina/github-action-push-to-another-repository@main
57 | env:
58 | SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
59 | with:
60 | source-directory: "output"
61 | destination-github-username: "automattic"
62 | destination-repository-name: "create-content-model-releases"
63 | user-name: ${{ github.actor }}
64 | user-email: ${{ steps.get_email.outputs.email }}
65 | target-branch: latest
66 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: "tagged-release"
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | tagged-release:
10 | name: "Tagged Release"
11 | runs-on: "ubuntu-latest"
12 | outputs:
13 | tag_name: ${{ steps.get_tag.outputs.tag_name }}
14 |
15 | steps:
16 | - uses: actions/checkout@master
17 | - name: Get tag name
18 | id: get_tag
19 | run: echo "tag_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
20 | - name: Fetch Tags
21 | run: git fetch --tags --force
22 | - id: tag-message
23 | run: git tag -l --sort=-taggerdate --format='%(contents)' $(git describe --tags $(git branch --show-current))
24 | - uses: actions/setup-node@v4
25 | with:
26 | node-version: 20
27 | cache: "npm"
28 | - run: npm install
29 | - run: "find . -type f -exec sed -i 's/0.0.0-placeholder/${{ steps.get_tag.outputs.tag_name }}/g' {} +"
30 | - run: npm run plugin-zip
31 | - uses: softprops/action-gh-release@v2
32 | with:
33 | body: ${{ steps.tag-message.outputs.stdout }}
34 | files: create-content-model.zip
35 | make_latest: true
36 |
37 | - name: Upload plugin zip
38 | uses: actions/upload-artifact@v4
39 | with:
40 | name: plugin-zip
41 | path: create-content-model.zip
42 |
43 | publish-to-releases-repo:
44 | name: "Publish to Releases Repository"
45 | needs: tagged-release
46 | runs-on: "ubuntu-latest"
47 |
48 | steps:
49 | # Download the artifact from the previous job
50 | - name: Download plugin zip
51 | uses: actions/download-artifact@v4
52 | with:
53 | name: plugin-zip
54 |
55 | - name: Create output directory
56 | run: mkdir -p output
57 |
58 | - name: Move plugin zip to output/
59 | run: mv create-content-model.zip output/
60 |
61 | - name: Get user email
62 | id: get_email
63 | run: |
64 | EMAIL=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
65 | https://api.github.com/users/${{ github.actor }} \
66 | | jq -r '.email // empty')
67 | if [ -z "$EMAIL" ]; then
68 | EMAIL="${{ github.actor }}@users.noreply.github.com"
69 | fi
70 | echo "email=$EMAIL" >> $GITHUB_OUTPUT
71 |
72 | - name: Push zip to create-content-model-releases repository
73 | uses: cpina/github-action-push-to-another-repository@main
74 | env:
75 | SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
76 | with:
77 | source-directory: "output"
78 | destination-github-username: "automattic"
79 | destination-repository-name: "create-content-model-releases"
80 | user-name: ${{ github.actor }}
81 | user-email: ${{ steps.get_email.outputs.email }}
82 | target-branch: releases
83 | commit-message: "${{ needs.tagged-release.outputs.tag_name }} from ORIGIN_COMMIT"
84 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | debug.log
3 | includes/*/dist
4 | create-content-model.zip
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require( '@wordpress/prettier-config' );
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The GNU General Public License, Version 2, June 1991 (GPLv2)
2 |
3 | > Copyright (C) 1989, 1991 Free Software Foundation, Inc.
4 | > 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
5 |
6 | Everyone is permitted to copy and distribute verbatim copies of this license
7 | document, but changing it is not allowed.
8 |
9 | ## Preamble
10 |
11 | The licenses for most software are designed to take away your freedom to share
12 | and change it. By contrast, the GNU General Public License is intended to
13 | guarantee your freedom to share and change free software--to make sure the
14 | software is free for all its users. This General Public License applies to most
15 | of the Free Software Foundation's software and to any other program whose
16 | authors commit to using it. (Some other Free Software Foundation software is
17 | covered by the GNU Library General Public License instead.) You can apply it to
18 | your programs, too.
19 |
20 | When we speak of free software, we are referring to freedom, not price. Our
21 | General Public Licenses are designed to make sure that you have the freedom to
22 | distribute copies of free software (and charge for this service if you wish),
23 | that you receive source code or can get it if you want it, that you can change
24 | the software or use pieces of it in new free programs; and that you know you can
25 | do these things.
26 |
27 | To protect your rights, we need to make restrictions that forbid anyone to deny
28 | you these rights or to ask you to surrender the rights. These restrictions
29 | translate to certain responsibilities for you if you distribute copies of the
30 | software, or if you modify it.
31 |
32 | For example, if you distribute copies of such a program, whether gratis or for a
33 | fee, you must give the recipients all the rights that you have. You must make
34 | sure that they, too, receive or can get the source code. And you must show them
35 | these terms so they know their rights.
36 |
37 | We protect your rights with two steps: (1) copyright the software, and (2) offer
38 | you this license which gives you legal permission to copy, distribute and/or
39 | modify the software.
40 |
41 | Also, for each author's protection and ours, we want to make certain that
42 | everyone understands that there is no warranty for this free software. If the
43 | software is modified by someone else and passed on, we want its recipients to
44 | know that what they have is not the original, so that any problems introduced by
45 | others will not reflect on the original authors' reputations.
46 |
47 | Finally, any free program is threatened constantly by software patents. We wish
48 | to avoid the danger that redistributors of a free program will individually
49 | obtain patent licenses, in effect making the program proprietary. To prevent
50 | this, we have made it clear that any patent must be licensed for everyone's free
51 | use or not licensed at all.
52 |
53 | The precise terms and conditions for copying, distribution and modification
54 | follow.
55 |
56 | ## Terms And Conditions For Copying, Distribution And Modification
57 |
58 | **0.** This License applies to any program or other work which contains a notice
59 | placed by the copyright holder saying it may be distributed under the terms of
60 | this General Public License. The "Program", below, refers to any such program or
61 | work, and a "work based on the Program" means either the Program or any
62 | derivative work under copyright law: that is to say, a work containing the
63 | Program or a portion of it, either verbatim or with modifications and/or
64 | translated into another language. (Hereinafter, translation is included without
65 | limitation in the term "modification".) Each licensee is addressed as "you".
66 |
67 | Activities other than copying, distribution and modification are not covered by
68 | this License; they are outside its scope. The act of running the Program is not
69 | restricted, and the output from the Program is covered only if its contents
70 | constitute a work based on the Program (independent of having been made by
71 | running the Program). Whether that is true depends on what the Program does.
72 |
73 | **1.** You may copy and distribute verbatim copies of the Program's source code
74 | as you receive it, in any medium, provided that you conspicuously and
75 | appropriately publish on each copy an appropriate copyright notice and
76 | disclaimer of warranty; keep intact all the notices that refer to this License
77 | and to the absence of any warranty; and give any other recipients of the Program
78 | a copy of this License along with the Program.
79 |
80 | You may charge a fee for the physical act of transferring a copy, and you may at
81 | your option offer warranty protection in exchange for a fee.
82 |
83 | **2.** You may modify your copy or copies of the Program or any portion of it,
84 | thus forming a work based on the Program, and copy and distribute such
85 | modifications or work under the terms of Section 1 above, provided that you also
86 | meet all of these conditions:
87 |
88 | - **a)** You must cause the modified files to carry prominent notices stating
89 | that you changed the files and the date of any change.
90 |
91 | - **b)** You must cause any work that you distribute or publish, that in whole
92 | or in part contains or is derived from the Program or any part thereof, to
93 | be licensed as a whole at no charge to all third parties under the terms of
94 | this License.
95 |
96 | - **c)** If the modified program normally reads commands interactively when
97 | run, you must cause it, when started running for such interactive use in the
98 | most ordinary way, to print or display an announcement including an
99 | appropriate copyright notice and a notice that there is no warranty (or
100 | else, saying that you provide a warranty) and that users may redistribute
101 | the program under these conditions, and telling the user how to view a copy
102 | of this License. (Exception: if the Program itself is interactive but does
103 | not normally print such an announcement, your work based on the Program is
104 | not required to print an announcement.)
105 |
106 | These requirements apply to the modified work as a whole. If identifiable
107 | sections of that work are not derived from the Program, and can be reasonably
108 | considered independent and separate works in themselves, then this License, and
109 | its terms, do not apply to those sections when you distribute them as separate
110 | works. But when you distribute the same sections as part of a whole which is a
111 | work based on the Program, the distribution of the whole must be on the terms of
112 | this License, whose permissions for other licensees extend to the entire whole,
113 | and thus to each and every part regardless of who wrote it.
114 |
115 | Thus, it is not the intent of this section to claim rights or contest your
116 | rights to work written entirely by you; rather, the intent is to exercise the
117 | right to control the distribution of derivative or collective works based on the
118 | Program.
119 |
120 | In addition, mere aggregation of another work not based on the Program with the
121 | Program (or with a work based on the Program) on a volume of a storage or
122 | distribution medium does not bring the other work under the scope of this
123 | License.
124 |
125 | **3.** You may copy and distribute the Program (or a work based on it, under
126 | Section 2) in object code or executable form under the terms of Sections 1 and 2
127 | above provided that you also do one of the following:
128 |
129 | - **a)** Accompany it with the complete corresponding machine-readable source
130 | code, which must be distributed under the terms of Sections 1 and 2 above on
131 | a medium customarily used for software interchange; or,
132 |
133 | - **b)** Accompany it with a written offer, valid for at least three years, to
134 | give any third party, for a charge no more than your cost of physically
135 | performing source distribution, a complete machine-readable copy of the
136 | corresponding source code, to be distributed under the terms of Sections 1
137 | and 2 above on a medium customarily used for software interchange; or,
138 |
139 | - **c)** Accompany it with the information you received as to the offer to
140 | distribute corresponding source code. (This alternative is allowed only for
141 | noncommercial distribution and only if you received the program in object
142 | code or executable form with such an offer, in accord with Subsection b
143 | above.)
144 |
145 | The source code for a work means the preferred form of the work for making
146 | modifications to it. For an executable work, complete source code means all the
147 | source code for all modules it contains, plus any associated interface
148 | definition files, plus the scripts used to control compilation and installation
149 | of the executable. However, as a special exception, the source code distributed
150 | need not include anything that is normally distributed (in either source or
151 | binary form) with the major components (compiler, kernel, and so on) of the
152 | operating system on which the executable runs, unless that component itself
153 | accompanies the executable.
154 |
155 | If distribution of executable or object code is made by offering access to copy
156 | from a designated place, then offering equivalent access to copy the source code
157 | from the same place counts as distribution of the source code, even though third
158 | parties are not compelled to copy the source along with the object code.
159 |
160 | **4.** You may not copy, modify, sublicense, or distribute the Program except as
161 | expressly provided under this License. Any attempt otherwise to copy, modify,
162 | sublicense or distribute the Program is void, and will automatically terminate
163 | your rights under this License. However, parties who have received copies, or
164 | rights, from you under this License will not have their licenses terminated so
165 | long as such parties remain in full compliance.
166 |
167 | **5.** You are not required to accept this License, since you have not signed
168 | it. However, nothing else grants you permission to modify or distribute the
169 | Program or its derivative works. These actions are prohibited by law if you do
170 | not accept this License. Therefore, by modifying or distributing the Program (or
171 | any work based on the Program), you indicate your acceptance of this License to
172 | do so, and all its terms and conditions for copying, distributing or modifying
173 | the Program or works based on it.
174 |
175 | **6.** Each time you redistribute the Program (or any work based on the
176 | Program), the recipient automatically receives a license from the original
177 | licensor to copy, distribute or modify the Program subject to these terms and
178 | conditions. You may not impose any further restrictions on the recipients'
179 | exercise of the rights granted herein. You are not responsible for enforcing
180 | compliance by third parties to this License.
181 |
182 | **7.** If, as a consequence of a court judgment or allegation of patent
183 | infringement or for any other reason (not limited to patent issues), conditions
184 | are imposed on you (whether by court order, agreement or otherwise) that
185 | contradict the conditions of this License, they do not excuse you from the
186 | conditions of this License. If you cannot distribute so as to satisfy
187 | simultaneously your obligations under this License and any other pertinent
188 | obligations, then as a consequence you may not distribute the Program at all.
189 | For example, if a patent license would not permit royalty-free redistribution of
190 | the Program by all those who receive copies directly or indirectly through you,
191 | then the only way you could satisfy both it and this License would be to refrain
192 | entirely from distribution of the Program.
193 |
194 | If any portion of this section is held invalid or unenforceable under any
195 | particular circumstance, the balance of the section is intended to apply and the
196 | section as a whole is intended to apply in other circumstances.
197 |
198 | It is not the purpose of this section to induce you to infringe any patents or
199 | other property right claims or to contest validity of any such claims; this
200 | section has the sole purpose of protecting the integrity of the free software
201 | distribution system, which is implemented by public license practices. Many
202 | people have made generous contributions to the wide range of software
203 | distributed through that system in reliance on consistent application of that
204 | system; it is up to the author/donor to decide if he or she is willing to
205 | distribute software through any other system and a licensee cannot impose that
206 | choice.
207 |
208 | This section is intended to make thoroughly clear what is believed to be a
209 | consequence of the rest of this License.
210 |
211 | **8.** If the distribution and/or use of the Program is restricted in certain
212 | countries either by patents or by copyrighted interfaces, the original copyright
213 | holder who places the Program under this License may add an explicit
214 | geographical distribution limitation excluding those countries, so that
215 | distribution is permitted only in or among countries not thus excluded. In such
216 | case, this License incorporates the limitation as if written in the body of this
217 | License.
218 |
219 | **9.** The Free Software Foundation may publish revised and/or new versions of
220 | the General Public License from time to time. Such new versions will be similar
221 | in spirit to the present version, but may differ in detail to address new
222 | problems or concerns.
223 |
224 | Each version is given a distinguishing version number. If the Program specifies
225 | a version number of this License which applies to it and "any later version",
226 | you have the option of following the terms and conditions either of that version
227 | or of any later version published by the Free Software Foundation. If the
228 | Program does not specify a version number of this License, you may choose any
229 | version ever published by the Free Software Foundation.
230 |
231 | **10.** If you wish to incorporate parts of the Program into other free programs
232 | whose distribution conditions are different, write to the author to ask for
233 | permission. For software which is copyrighted by the Free Software Foundation,
234 | write to the Free Software Foundation; we sometimes make exceptions for this.
235 | Our decision will be guided by the two goals of preserving the free status of
236 | all derivatives of our free software and of promoting the sharing and reuse of
237 | software generally.
238 |
239 | ## No Warranty
240 |
241 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
242 | THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
243 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
244 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
245 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
246 | PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
247 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
248 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
249 |
250 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
251 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
252 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
253 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
254 | INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
255 | BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
256 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
257 | OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Create Content Model
2 |
3 | _Define custom post types & fields in the Block Editor._
4 |
5 | WordPress.com’s experimental Create Content Model plugin transforms the way custom post types and custom fields are created and managed in WordPress by making use of the latest core features to bring content modeling into the Block Editor. Additionally, the created data model and data entry UI can be exported as a standalone, maintenance-free plugin.
6 |
7 | [](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/Automattic/create-content-model/trunk/blueprint.json)
8 |
9 | You can also test out the plugin locally with [Studio](https://developer.wordpress.com/studio/?utm_source=github&utm_medium=readme&utm_campaign=create-content-model)! Check out the [Get Started](/get-started.md#test-locally-with-studio) guide for details.
10 |
11 | https://github.com/user-attachments/assets/723a973a-eb92-4b71-9f64-ac269d0f9861
12 |
13 | For a more thorough introduction:
14 |
15 | - Check out Brian Coord's [Custom fields and post types inside the block editor livestream](https://www.youtube.com/watch?v=VLB3OkgNOTs).
16 | - [Watch our talk at WordCamp Asia 2025](https://www.youtube.com/live/nKntUgxnZuY?feature=shared&t=3409), and this is the [demo video](https://youtu.be/67CHMveu38Y) shown at the end of the talk.
17 |
18 | ## Getting Started
19 |
20 | Find detailed instructions on creating your content model using this plugin in the [Get Started](/get-started.md) guide.
21 |
22 | [](https://github.com/Automattic/create-content-model/releases/latest/download/create-content-model.zip)
23 |
24 | ## About
25 |
26 | Our team at WordPress.com is excited to share our recent prototyping efforts on game changing approaches to custom content creation.
27 |
28 | The Create Content Model plugin builds upon our custom post types project at the [CloudFest Hackathon in 2024](https://wordpress.com/blog/2024/04/15/custom-post-types-wordpress-admin/?utm_source=github&utm_medium=readme&utm_campaign=create-content-model). We’ve leveraged core functionality, like [block bindings](https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/) and [block variations](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/), to create a new paradigm for creating and managing custom post types and custom fields in WordPress.
29 |
30 | Unlike existing custom post type and custom field plugins, our plugin takes a native approach by putting the creation and management of these elements directly in the WordPress Block Editor. Using the Block Bindings API, `post_meta` fields are bound to block attributes. Block variations are created from each bound block for use in front-end template layouts. The result is an extremely intuitive workflow for both the setup of custom post types and fields and their usage in front-end templating.
31 |
32 | A key feature of the Create Content Model plugin is the export of a locked custom data model and a data entry UI. Developers can generate and reuse the same content models on multiple sites without ongoing plugin maintenance or costs. They can hand off fully functional sites with locked custom post types and fields, ready for clients to populate the content.
33 |
34 | ## Development
35 |
36 | * Run `npm install` to install the dependencies
37 | * Run `npm run dev-server` to start the local WordPress server
38 | * In a new terminal window, run `npm start` to start the JavaScript bundler watcher
39 |
40 | ### Bundling
41 |
42 | Run `npm run plugin-zip` to create a zip file of the plugin. This will automatically bundle the JavaScript files.
43 |
44 | ### Creating a new release
45 |
46 | Create a new release by filling the form on [this page](https://github.com/Automattic/create-content-model/releases/new).
47 |
48 | The release title and tag ("Choose a tag" selectbox, above the title) should be in the Semver format (`major.minor.patch`).
49 |
50 | The release description should be a list of bullet points of the most meaningful changes. You can copy the commit title from the merged PRs.
51 |
52 | After clicking "Publish release," a [GitHub workflow](https://github.com/Automattic/create-content-model/blob/trunk/.github/workflows/release.yml) will bundle the plugin and export the release artifact.
53 |
54 | ## Contribute & Contact
55 |
56 | Want to help us move this concept forward?
57 |
58 | Feel free to open an issue in the repo to discuss your proposed improvement. Pull requests are welcome for bug fixes and enhancements.
59 |
60 | We built this as a prototype and may invest into it further based on level of interest. Our near term vision is outlined in this [roadmap issue](https://github.com/Automattic/create-content-model/issues/77).
61 |
62 | ## Licensing
63 | [GNU General Public License](/LICENSE.md)
64 |
65 | ## Credits & Acknowledgements
66 | We’d like to thank the team at WordPress.com who made this project possible: [Luis Felipe Zaguini](https://github.com/zaguiini), [Candy Tsai](https://github.com/candy02058912), [Autumn Fjeld](https://github.com/autumnfjeld), [Brian Coords](https://github.com/bacoords), [Daniel Bachhuber](https://github.com/danielbachhuber).
67 |
68 | ## Stay in the Loop with WordPress.com
69 | Follow us:
70 |
71 | [](https://www.linkedin.com/showcase/wordpress.com)
72 |
73 | [](https://x.com/wordpressdotcom)
74 |
75 | [](https://www.instagram.com/wordpressdotcom)
76 |
77 |
78 |
79 | And while you’re at it, check out our [WordPress hosting solution for developers](https://wordpress.com/hosting?utm_source=github&utm_medium=readme&utm_campaign=create-content-model) and [our agency program](https://wordpress.com/for-agencies/?utm_source=github&utm_medium=readme&utm_campaign=create-content-model).
80 |
--------------------------------------------------------------------------------
/blueprint.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://playground.wordpress.net/blueprint-schema.json",
3 | "meta": {
4 | "title": "Create Content Model latest",
5 | "description": "Installs the latest version of create-content-model plugin to WordPress Playground",
6 | "author": "Automattic",
7 | "categories": [ "Content", "CPT" ]
8 | },
9 | "landingPage": "/wp-admin/",
10 | "steps": [
11 | {
12 | "step": "login"
13 | },
14 | {
15 | "step": "installPlugin",
16 | "pluginZipFile": {
17 | "resource": "url",
18 | "url": "https://raw.githubusercontent.com/Automattic/create-content-model-releases/releases/create-content-model.zip"
19 | }
20 | },
21 | {
22 | "step": "activatePlugin",
23 | "pluginPath": "create-content-model/create-content-model.php"
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/create-content-model.php:
--------------------------------------------------------------------------------
1 | esc_html__( 'Return to Plugins Page' ),
18 | 'link_url' => esc_url( admin_url( 'plugins.php' ) ),
19 | )
20 | );
21 | }
22 |
23 | define( 'CONTENT_MODEL_PLUGIN_FILE', __FILE__ );
24 | define( 'CONTENT_MODEL_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
25 | define( 'CONTENT_MODEL_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
26 |
27 | if ( ! function_exists( 'content_model_require_if_exists' ) ) {
28 | /**
29 | * Requires a file if it exists.
30 | *
31 | * @param string $file The file to require.
32 | */
33 | function content_model_require_if_exists( string $file ) {
34 | if ( file_exists( $file ) ) {
35 | require_once $file;
36 | }
37 | }
38 | }
39 |
40 | content_model_require_if_exists( __DIR__ . '/includes/json-initializer/0-load.php' );
41 | content_model_require_if_exists( __DIR__ . '/includes/runtime/0-load.php' );
42 | content_model_require_if_exists( __DIR__ . '/includes/manager/0-load.php' );
43 | content_model_require_if_exists( __DIR__ . '/includes/exporter/0-load.php' );
44 |
--------------------------------------------------------------------------------
/dev.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://playground.wordpress.net/blueprint-schema.json",
3 | "steps": [
4 | {
5 | "step": "defineWpConfigConsts",
6 | "consts": {
7 | "WP_DEBUG": true,
8 | "WP_DEBUG_LOG": "/var/www/html/wp-content/plugins/create-content-model/debug.log"
9 | }
10 | }
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/get-started.md:
--------------------------------------------------------------------------------
1 |
2 | # Get Started
3 | Start leveraging the latest WordPress core features with WordPress.com’s experimental Create Content Model plugin.
4 |
5 | Create custom post types and custom fields directly in the Block Editor, and then export your data model and data entry UI as a standalone, maintenance-free plugin. Everything you build is using core WordPress functionality, so you can run the future-proof plugin or you can use filters and hooks to extend and adapt your data model.
6 |
7 | To get started with the Create Content Model plugin, [download the latest release](https://github.com/Automattic/create-content-model/releases/latest/download/create-content-model.zip), [launch our WordPress Playground Blueprint](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/Automattic/create-content-model/trunk/blueprint.json), or [test locally with Studio](#test-locally-with-studio).
8 |
9 | https://github.com/user-attachments/assets/09b449f0-4398-4037-ba07-820c76407d7d
10 |
11 | ## Creating a content model
12 |
13 | A content model is a custom post type that you can register and build directly in WordPress core. As you design it, you select which blocks are editable and can add custom fields.
14 |
15 | Creating a new content model includes:
16 |
17 | 1. Registering a new post type.
18 | 2. Designing the frontend template for your new post type and selecting which blocks in the template are editable by adding new “Bindings.”
19 | 3. Adding custom fields to your post to collect additional data.
20 |
21 | *Note that custom taxonomy support is on the [roadmap](https://github.com/Automattic/create-content-model/issues/77).*
22 |
23 | ### Register the post type
24 |
25 | From the Content Models page:
26 |
27 | 1. Click **Add New Model**.
28 | 2. Name your content model.
29 | 3. Manage the post type settings using the sidebar panel: Singular Label, Plural Label, Icon Name
30 |
31 | 
32 |
33 | ### Design the frontend template for your new post type
34 | Once you’ve created the post type, you can start designing the template.
35 |
36 | As you add blocks to the template, they will not be editable by default. You’ll need to select which blocks include dynamic (aka editable) data by selecting **Add Binding** in the block sidebar controls.
37 |
38 | Once a block is “bound,” it will be editable in the future, and any data entered will be automatically stored as postmeta, meaning you can use that data in different templates or query loops, view it in the REST API, bulk manage it via the database, and much more.
39 |
40 | 
41 |
42 | If you have the [Gutenberg plugin](https://wordpress.org/plugins/gutenberg/) and enable the "Block Binding UI" experiment enabled, you can view and use your custom fields registered as postmeta when you manually bind an attribute.
43 |
44 | Since we’re using core WordPress’ [Block Bindings API](https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/), the only blocks that are currently supported are the [Paragraph](https://wordpress.org/documentation/article/paragraph-block/), [Heading](https://wordpress.org/documentation/article/heading-block/), [Image](https://wordpress.org/documentation/article/image-block/), and [Buttons](https://wordpress.org/documentation/article/buttons-block/) blocks.
45 |
46 | ### Rich content areas: the Group block
47 | This tool also allows you to bind the [Group](https://wordpress.org/documentation/article/group-block/) block to a post meta field, which creates a “rich text” or WYSIWYG area in your template where multiple blocks can be used. A bound group block will store its contents in a post meta field, or you can map it directly to the `post_content` attribute.
48 |
49 | 
50 |
51 | ## Your data model and custom fields
52 | All of your bound blocks will save their content to post meta fields, so you can redesign, remix, and filter your content model in the future and without losing the integrity of your data. Open the Post Meta sidebar panel to view.
53 |
54 | 
55 |
56 | Click the Manage Post Meta button to browse all of your block bindings and create your own custom fields that are available in the post editing screen.
57 |
58 | 
59 |
60 | Click **Publish** to see your new content model on your website.
61 |
62 | ## Adding and managing content
63 | Once your data model is published, it will show up as an additional post type beneath Posts and Pages in your WordPress dashboard.
64 |
65 | Add new content just like you would add any other post content. You’ll notice that only the blocks you bound are editable, and the rest of the data model’s template is safe from being changed or edited.
66 |
67 | 
68 |
69 | Any custom fields that you’ve added will also be available in the post sidebar:
70 |
71 | 
72 |
73 | Click the **Publish** button to publish your post and view it on the front end.
74 |
75 | ## Updating the front-end layout
76 | Create Content Model is designed to work with the block editor and block-based themes. If you’d like to make changes to the design of the single or archive templates for your custom post type, you can do that inside of the Site Editor, just like you would for any other post type.
77 |
78 | ### Single post template
79 | You can set up the single post layout in your custom post type template. Alternatively, you can create a new `single-CPTNAME.html` template and add block variations from the block inserter.
80 |
81 | ### Archives and the Query Loop block
82 | Create a custom [Query Loop](https://wordpress.org/documentation/article/query-loop-block/) on a page, `archive-CPTNAME.html` template, or any other template (e.g. the theme’s home template). Pull in the posts from your data model, sort and filter them, and use the new block variations in the block inserter to pull individual pieces of data into your template.
83 |
84 | 
85 |
86 | ## Plugin export workflow
87 | Create Content Model is a development tool, but it’s not required to run on your site. If you’re done building your content model, you can “export” it as a standalone plugin:
88 |
89 | 1. Click Content Models → **Export**.
90 | 2. Export the data model plugin by clicking the **Download ZIP file** button.
91 | 3. Install your data model plugin on a new site (or deactivate the main plugin on the current site and import the new plugin). Remember to upload it as the .zip file.
92 | 4. Optionally, add version control for your own content model plugin to track changes and deploy your plugin across multiple sites.
93 |
94 | ## Test locally with Studio
95 | Studio is WordPress.com's free, open-source local development environment.
96 |
97 | 1. Download [Studio](https://developer.wordpress.com/studio/?utm_source=github&utm_medium=get-started&utm_campaign=create-content-model).
98 | 2. Add a site.
99 | 3. Open WP Admin.
100 | 4. Download the [latest plugin release](https://github.com/Automattic/create-content-model/releases/latest/download/create-content-model.zip).
101 | 5. Install and activate the plugin.
102 |
--------------------------------------------------------------------------------
/includes/exporter/0-load.php:
--------------------------------------------------------------------------------
1 | generate_all_models_json();
69 | $has_models = ! empty( $all_models_json );
70 | $show_error = ! $has_models;
71 | if ( isset( $_GET['error'] ) && 'no_models' === $_GET['error'] && check_admin_referer( 'export_error_nonce', 'export_error_nonce' ) ) {
72 | $show_error = true;
73 | }
74 | ?>
75 |