diff --git a/includes/manager/class-content-model-loader.php b/includes/manager/class-content-model-loader.php
index 0ef6268..14e133a 100644
--- a/includes/manager/class-content-model-loader.php
+++ b/includes/manager/class-content-model-loader.php
@@ -38,7 +38,7 @@ public static function get_instance() {
* Initializes the Content_Model_Loader class.
*
* Checks if the current user has the capability to manage options.
- * If they do, it registers the post type and enqueues the attribute binder.
+ * If they do, it registers the post type and enqueues the manager scripts.
*
* @return void
*/
@@ -48,11 +48,8 @@ private function __construct() {
}
$this->register_post_type();
- $this->maybe_enqueue_the_attribute_binder();
- $this->maybe_enqueue_the_cpt_settings_panel();
- $this->maybe_enqueue_the_fields_ui();
- $this->maybe_enqueue_content_model_length_restrictor();
- $this->maybe_enqueue_the_defaut_value_placeholder();
+
+ add_action( 'enqueue_block_editor_assets', array( $this, 'maybe_enqueue_scripts' ) );
add_action( 'save_post', array( $this, 'map_template_to_bindings_api_signature' ), 99, 2 );
@@ -149,178 +146,35 @@ private function register_post_type() {
}
/**
- * Conditionally enqueues the attribute binder script for the block editor.
- *
- * Checks if the current post is of the correct type before enqueueing the script.
+ * Enqueue the helper scripts if opening the content model manager.
*
* @return void
*/
- private function maybe_enqueue_the_attribute_binder() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || Content_Model_Manager::POST_TYPE_NAME !== $post->post_type ) {
- return;
- }
-
- $register_attribute_binder_js = include CONTENT_MODEL_PLUGIN_PATH . '/includes/manager/dist/register-attribute-binder.asset.php';
-
- wp_enqueue_script(
- 'content-model/attribute-binder',
- CONTENT_MODEL_PLUGIN_URL . '/includes/manager/dist/register-attribute-binder.js',
- $register_attribute_binder_js['dependencies'],
- $register_attribute_binder_js['version'],
- true
- );
-
- wp_add_inline_script(
- 'content-model/attribute-binder',
- 'window.BINDINGS_KEY = "' . Content_Model_Loader::BINDINGS_KEY . '";',
- 'before'
- );
-
- wp_add_inline_script(
- 'content-model/attribute-binder',
- 'window.BLOCK_VARIATION_NAME_ATTR = "' . Content_Model_Block::BLOCK_VARIATION_NAME_ATTR . '";',
- 'before'
- );
- }
- );
- }
+ public function maybe_enqueue_scripts() {
+ global $post;
- /**
- * Conditionally enqueues the CPT settings script for the content model editor.
- *
- * Checks if the current post is of the correct type before enqueueing the script.
- *
- * @return void
- */
- private function maybe_enqueue_the_cpt_settings_panel() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || Content_Model_Manager::POST_TYPE_NAME !== $post->post_type ) {
- return;
- }
-
- $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/manager/dist/cpt-settings-panel.asset.php';
-
- wp_register_script(
- 'data-types/cpt-settings-panel',
- CONTENT_MODEL_PLUGIN_URL . '/includes/manager/dist/cpt-settings-panel.js',
- $asset_file['dependencies'],
- $asset_file['version'],
- true
- );
-
- wp_localize_script(
- 'data-types/cpt-settings-panel',
- 'contentModelFields',
- array(
- 'postType' => Content_Model_Manager::POST_TYPE_NAME,
- )
- );
-
- wp_enqueue_script( 'data-types/cpt-settings-panel' );
- }
- );
- }
+ if ( ! $post || Content_Model_Manager::POST_TYPE_NAME !== $post->post_type ) {
+ return;
+ }
+ $asset_file = include CONTENT_MODEL_PLUGIN_PATH . '/includes/manager/dist/manager.asset.php';
- /**
- * Conditionally enqueues the fields UI script for the block editor.
- *
- * Checks if the current post is of the correct type before enqueueing the script.
- *
- * @return void
- */
- private function maybe_enqueue_the_fields_ui() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || Content_Model_Manager::POST_TYPE_NAME !== $post->post_type ) {
- return;
- }
-
- $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/manager/dist/fields-ui.asset.php';
-
- wp_register_script(
- 'data-types/fields-ui',
- CONTENT_MODEL_PLUGIN_URL . '/includes/manager/dist/fields-ui.js',
- $asset_file['dependencies'],
- $asset_file['version'],
- true
- );
-
- wp_localize_script(
- 'data-types/fields-ui',
- 'contentModelFields',
- array(
- 'postType' => Content_Model_Manager::POST_TYPE_NAME,
- )
- );
-
- wp_enqueue_script( 'data-types/fields-ui' );
- }
- );
- }
-
- /**
- * Conditionally enqueues the content model length restrictor script for the block editor.
- *
- * Checks if the current post is of the correct type before enqueueing the script.
- *
- * @return void
- */
- private function maybe_enqueue_content_model_length_restrictor() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || Content_Model_Manager::POST_TYPE_NAME !== $post->post_type ) {
- return;
- }
-
- $content_model_length_restrictor_js = include CONTENT_MODEL_PLUGIN_PATH . '/includes/manager/dist/content-model-title-length-restrictor.asset.php';
-
- wp_enqueue_script(
- 'content-model/length-restrictor',
- CONTENT_MODEL_PLUGIN_URL . '/includes/manager/dist/content-model-title-length-restrictor.js',
- $content_model_length_restrictor_js['dependencies'],
- $content_model_length_restrictor_js['version'],
- true
- );
- }
+ wp_enqueue_script(
+ 'content-model/manager',
+ CONTENT_MODEL_PLUGIN_URL . '/includes/manager/dist/manager.js',
+ $asset_file['dependencies'],
+ $asset_file['version'],
+ true
);
- }
- private function maybe_enqueue_the_defaut_value_placeholder() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || Content_Model_Manager::POST_TYPE_NAME !== $post->post_type ) {
- return;
- }
-
- $content_model_length_restrictor_js = include CONTENT_MODEL_PLUGIN_PATH . '/includes/manager/dist/default-value-placeholder-changer.asset.php';
-
- wp_enqueue_script(
- 'content-model/default-value-placeholder-changer',
- CONTENT_MODEL_PLUGIN_URL . '/includes/manager/dist/default-value-placeholder-changer.js',
- $content_model_length_restrictor_js['dependencies'],
- $content_model_length_restrictor_js['version'],
- true
- );
- }
+ wp_localize_script(
+ 'content-model/manager',
+ 'contentModelData',
+ array(
+ 'BINDINGS_KEY' => self::BINDINGS_KEY,
+ 'BLOCK_VARIATION_NAME_ATTR' => Content_Model_Block::BLOCK_VARIATION_NAME_ATTR,
+ 'POST_TYPE_NAME' => Content_Model_Manager::POST_TYPE_NAME,
+ )
);
}
diff --git a/includes/manager/manager.js b/includes/manager/manager.js
new file mode 100644
index 0000000..417ed68
--- /dev/null
+++ b/includes/manager/manager.js
@@ -0,0 +1,11 @@
+import { registerAttributeBinder } from './src/register-attribute-binder';
+import { registerContentModelLengthRestrictor } from './src/register-content-model-title-length-restrictor';
+import { registerCPTSettingsPanel } from './src/register-cpt-settings-panel';
+import { registerDefaultValuePlaceholderChanger } from './src/register-default-value-placeholder-changer';
+import { registerFieldsUI } from './src/register-fields-ui';
+
+registerAttributeBinder();
+registerCPTSettingsPanel();
+registerFieldsUI();
+registerContentModelLengthRestrictor();
+registerDefaultValuePlaceholderChanger();
diff --git a/includes/manager/register-attribute-binder.js b/includes/manager/register-attribute-binder.js
deleted file mode 100644
index 4bef79c..0000000
--- a/includes/manager/register-attribute-binder.js
+++ /dev/null
@@ -1,222 +0,0 @@
-import { addFilter } from '@wordpress/hooks';
-import { useCallback, useMemo, useState } from '@wordpress/element';
-import { __ } from '@wordpress/i18n';
-import { createHigherOrderComponent } from '@wordpress/compose';
-import { InspectorControls } from '@wordpress/block-editor';
-import {
- PanelBody,
- PanelRow,
- Button,
- ButtonGroup,
- __experimentalItemGroup as ItemGroup,
- __experimentalItem as Item,
- Flex,
- FlexBlock,
- FlexItem,
-} from '@wordpress/components';
-import { useSelect } from '@wordpress/data';
-import { store as blocksStore } from '@wordpress/blocks';
-import { useEntityProp } from '@wordpress/core-data';
-
-import ManageBindings from './_manage-bindings';
-
-import SUPPORTED_BLOCK_ATTRIBUTES from './_supported-attributes';
-
-const withAttributeBinder = createHigherOrderComponent( ( BlockEdit ) => {
- return ( props ) => {
- const { getBlockType } = useSelect( blocksStore );
- const { getBlockParentsByBlockName, getBlocksByClientId } =
- useSelect( 'core/block-editor' );
- const [ editingBoundAttribute, setEditingBoundAttribute ] =
- useState( null );
-
- const [ meta, setMeta ] = useEntityProp(
- 'postType',
- window.contentModelFields.postType,
- 'meta'
- );
-
- const fields = useMemo( () => {
- // Saving the fields as serialized JSON because I was tired of fighting the REST API.
- return meta?.fields ? JSON.parse( meta.fields ) : [];
- }, [ meta.fields ] );
-
- const { attributes, setAttributes, name } = props;
-
- const boundField = fields.find(
- ( field ) => field.slug === attributes.metadata?.slug
- );
-
- const removeBindings = useCallback( () => {
- const newAttributes = {
- metadata: {
- ...( attributes.metadata ?? {} ),
- },
- };
-
- delete newAttributes.metadata[ window.BINDINGS_KEY ];
- delete newAttributes.metadata[ window.BLOCK_VARIATION_NAME_ATTR ];
- delete newAttributes.metadata.slug;
-
- const newFields = fields.filter(
- ( field ) => field.slug !== attributes.metadata.slug
- );
-
- setMeta( {
- fields: JSON.stringify( newFields ),
- } );
-
- setAttributes( newAttributes );
- }, [ attributes.metadata, setAttributes, fields, setMeta ] );
-
- const selectedBlockType = getBlockType( name );
-
- const blockParentsByBlockName = getBlockParentsByBlockName(
- props.clientId,
- [ 'core/group' ]
- );
-
- // Check if any parent blocks have bindings.
- const parentHasBindings = useMemo( () => {
- return (
- getBlocksByClientId( blockParentsByBlockName ).filter(
- ( block ) =>
- Object.keys(
- block?.attributes?.metadata?.[
- window.BINDINGS_KEY
- ] || {}
- ).length > 0
- ).length > 0
- );
- }, [ blockParentsByBlockName, getBlocksByClientId ] );
-
- const supportedAttributes =
- SUPPORTED_BLOCK_ATTRIBUTES[ selectedBlockType?.name ];
-
- const setBinding = useCallback(
- ( field ) => {
- const bindings = supportedAttributes.reduce(
- ( acc, attribute ) => {
- acc[ attribute ] =
- 'post_content' === field.slug
- ? field.slug
- : `${ field.slug }__${ attribute }`;
-
- return acc;
- },
- {}
- );
-
- const newAttributes = {
- metadata: {
- ...( attributes.metadata ?? {} ),
- [ window.BLOCK_VARIATION_NAME_ATTR ]: field.label,
- slug: field.slug,
- [ window.BINDINGS_KEY ]: bindings,
- },
- };
-
- setAttributes( newAttributes );
- },
- [ attributes.metadata, setAttributes, supportedAttributes ]
- );
-
- if ( ! supportedAttributes || parentHasBindings ) {
- return ;
- }
-
- const bindings = attributes?.metadata?.[ window.BINDINGS_KEY ];
-
- return (
- <>
-
-
- { ! editingBoundAttribute && bindings && (
-
- { supportedAttributes.map( ( attribute ) => {
- return (
- -
-
-
- { attribute }
-
- { bindings[ attribute ] && (
-
-
-
- {
- bindings[
- attribute
- ]
- }
-
-
-
- ) }
-
-
- );
- } ) }
-
- ) }
- { ! editingBoundAttribute && (
-
-
-
- { bindings && (
-
- ) }
-
-
- ) }
- { editingBoundAttribute && (
-
- {
- setBinding( formData );
- setEditingBoundAttribute( null );
- } }
- defaultFormData={ {
- label:
- attributes?.metadata?.[
- window.BLOCK_VARIATION_NAME_ATTR
- ] ?? '',
- slug: attributes?.metadata?.slug ?? '',
- uuid:
- boundField?.uuid ??
- window.crypto.randomUUID(),
- description: '',
- type: selectedBlockType?.name,
- visible: false,
- } }
- typeIsDisabled={ true }
- />
-
- ) }
-
-
-
- >
- );
- };
-}, 'withAttributeBinder' );
-
-addFilter(
- 'editor.BlockEdit',
- 'content-model/attribute-binder',
- withAttributeBinder
-);
diff --git a/includes/manager/src/components/attribute-binder-panel.js b/includes/manager/src/components/attribute-binder-panel.js
new file mode 100644
index 0000000..f52203d
--- /dev/null
+++ b/includes/manager/src/components/attribute-binder-panel.js
@@ -0,0 +1,175 @@
+import { useCallback, useMemo, useState } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { InspectorControls } from '@wordpress/block-editor';
+import {
+ PanelBody,
+ PanelRow,
+ Button,
+ ButtonGroup,
+ __experimentalItemGroup as ItemGroup,
+ __experimentalItem as Item,
+ Flex,
+ FlexBlock,
+ FlexItem,
+} from '@wordpress/components';
+import { useEntityProp } from '@wordpress/core-data';
+
+import ManageBindings from './manage-bindings';
+import {
+ SUPPORTED_BLOCK_ATTRIBUTES,
+ BINDINGS_KEY,
+ POST_TYPE_NAME,
+ BLOCK_VARIATION_NAME_ATTR,
+} from '../constants';
+
+export const AttributeBinderPanel = ( { attributes, setAttributes, name } ) => {
+ const supportedAttributes = SUPPORTED_BLOCK_ATTRIBUTES[ name ];
+ const bindings = attributes?.metadata?.[ BINDINGS_KEY ];
+
+ const [ editingBoundAttribute, setEditingBoundAttribute ] =
+ useState( null );
+
+ const [ meta, setMeta ] = useEntityProp(
+ 'postType',
+ POST_TYPE_NAME,
+ 'meta'
+ );
+
+ const fields = useMemo( () => {
+ // Saving the fields as serialized JSON because I was tired of fighting the REST API.
+ return meta?.fields ? JSON.parse( meta.fields ) : [];
+ }, [ meta.fields ] );
+
+ const boundField = fields.find(
+ ( field ) => field.slug === attributes.metadata?.slug
+ );
+
+ const removeBindings = useCallback( () => {
+ const newAttributes = {
+ metadata: {
+ ...( attributes.metadata ?? {} ),
+ },
+ };
+
+ delete newAttributes.metadata[ BINDINGS_KEY ];
+ delete newAttributes.metadata[ BLOCK_VARIATION_NAME_ATTR ];
+ delete newAttributes.metadata.slug;
+
+ const newFields = fields.filter(
+ ( field ) => field.slug !== attributes.metadata.slug
+ );
+
+ setMeta( {
+ fields: JSON.stringify( newFields ),
+ } );
+
+ setAttributes( newAttributes );
+ }, [ attributes.metadata, setAttributes, fields, setMeta ] );
+
+ const setBinding = useCallback(
+ ( field ) => {
+ const newBindings = supportedAttributes.reduce(
+ ( acc, attribute ) => {
+ acc[ attribute ] =
+ 'post_content' === field.slug
+ ? field.slug
+ : `${ field.slug }__${ attribute }`;
+
+ return acc;
+ },
+ {}
+ );
+
+ const newAttributes = {
+ metadata: {
+ ...( attributes.metadata ?? {} ),
+ [ BLOCK_VARIATION_NAME_ATTR ]: field.label,
+ slug: field.slug,
+ [ BINDINGS_KEY ]: newBindings,
+ },
+ };
+
+ setAttributes( newAttributes );
+ },
+ [ attributes.metadata, setAttributes, supportedAttributes ]
+ );
+
+ return (
+
+
+ { ! editingBoundAttribute && bindings && (
+
+ { supportedAttributes.map( ( attribute ) => {
+ return (
+ -
+
+ { attribute }
+ { bindings[ attribute ] && (
+
+
+
+ {
+ bindings[
+ attribute
+ ]
+ }
+
+
+
+ ) }
+
+
+ );
+ } ) }
+
+ ) }
+ { ! editingBoundAttribute && (
+
+
+
+ { bindings && (
+
+ ) }
+
+
+ ) }
+ { editingBoundAttribute && (
+
+ {
+ setBinding( formData );
+ setEditingBoundAttribute( null );
+ } }
+ defaultFormData={ {
+ label:
+ attributes?.metadata?.[
+ BLOCK_VARIATION_NAME_ATTR
+ ] ?? '',
+ slug: attributes?.metadata?.slug ?? '',
+ uuid: boundField?.uuid ?? crypto.randomUUID(),
+ description: '',
+ type: name,
+ visible: false,
+ } }
+ typeIsDisabled={ true }
+ />
+
+ ) }
+
+
+ );
+};
diff --git a/includes/manager/cpt-settings-panel.js b/includes/manager/src/components/cpt-settings-panel.js
similarity index 87%
rename from includes/manager/cpt-settings-panel.js
rename to includes/manager/src/components/cpt-settings-panel.js
index 3eeea38..3841deb 100644
--- a/includes/manager/cpt-settings-panel.js
+++ b/includes/manager/src/components/cpt-settings-panel.js
@@ -1,4 +1,3 @@
-import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import { TextControl, Dashicon } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
@@ -8,17 +7,18 @@ import {
createInterpolateElement,
} from '@wordpress/element';
import { useEntityProp } from '@wordpress/core-data';
+import { POST_TYPE_NAME } from '../constants';
-const CreateContentModelCptSettings = function () {
+export const CPTSettingsPanel = function () {
const [ meta, setMeta ] = useEntityProp(
'postType',
- window.contentModelFields.postType,
+ POST_TYPE_NAME,
'meta'
);
const [ title, setTitle ] = useEntityProp(
'postType',
- window.contentModelFields.postType,
+ POST_TYPE_NAME,
'title'
);
@@ -94,8 +94,3 @@ const CreateContentModelCptSettings = function () {
>
);
};
-
-// Register the plugin.
-registerPlugin( 'create-content-model-cpt-settings', {
- render: CreateContentModelCptSettings,
-} );
diff --git a/includes/manager/_edit-field.js b/includes/manager/src/components/edit-field.js
similarity index 91%
rename from includes/manager/_edit-field.js
rename to includes/manager/src/components/edit-field.js
index b1c2fe2..7e8b5fa 100644
--- a/includes/manager/_edit-field.js
+++ b/includes/manager/src/components/edit-field.js
@@ -14,7 +14,7 @@ import {
FlexItem,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
-import { useState } from '@wordpress/element';
+import { useState, useEffect } from '@wordpress/element';
import {
trash,
chevronUp,
@@ -22,17 +22,9 @@ import {
blockDefault,
post,
} from '@wordpress/icons';
-import { useEffect } from '@wordpress/element';
-import SUPPORTED_BLOCK_ATTRIBUTES from './_supported-attributes';
+import { SUPPORTED_BLOCK_ATTRIBUTES } from '../constants';
-/**
- * Display a form to edit a field.
- * @param {Object} props
- * @param {Function} props.onSave
- * @param {Object} props.defaultFormData (to be updated with the field data for editing)
- * @returns EditFieldForm
- */
const EditFieldForm = ( {
field = {
label: '',
@@ -98,11 +90,16 @@ const EditFieldForm = ( {
icon={ trash }
title={ __( 'Delete Field' ) }
onClick={ () => {
- confirm(
+ // eslint-disable-next-line no-alert
+ const userWantsToDelete = confirm(
__(
'Are you sure you want to delete this field?'
)
- ) && onDelete( formData );
+ );
+
+ if ( userWantsToDelete ) {
+ onDelete( formData );
+ }
} }
/>
) }
diff --git a/includes/manager/fields-ui.js b/includes/manager/src/components/fields-ui.js
similarity index 89%
rename from includes/manager/fields-ui.js
rename to includes/manager/src/components/fields-ui.js
index c2c6c50..406de5b 100644
--- a/includes/manager/fields-ui.js
+++ b/includes/manager/src/components/fields-ui.js
@@ -1,4 +1,3 @@
-import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import {
Button,
@@ -17,16 +16,13 @@ import { useEntityProp } from '@wordpress/core-data';
import { useState } from '@wordpress/element';
import { seen, unseen, blockDefault } from '@wordpress/icons';
-import EditFieldForm from './_edit-field';
+import EditFieldForm from './edit-field';
+import { POST_TYPE_NAME } from '../constants';
-const CreateContentModelPageSettings = function () {
+export const FieldsUI = function () {
const [ isFieldsOpen, setFieldsOpen ] = useState( false );
- const [ meta ] = useEntityProp(
- 'postType',
- window.contentModelFields.postType,
- 'meta'
- );
+ const [ meta ] = useEntityProp( 'postType', POST_TYPE_NAME, 'meta' );
// Saving the fields as serialized JSON because I was tired of fighting the REST API.
const fields = meta?.fields ? JSON.parse( meta.fields ) : [];
@@ -34,7 +30,7 @@ const CreateContentModelPageSettings = function () {
// Add UUID to fields
fields.forEach( ( field ) => {
if ( ! field.uuid ) {
- field.uuid = window.crypto.randomUUID();
+ field.uuid = crypto.randomUUID();
}
} );
@@ -104,7 +100,7 @@ const CreateContentModelPageSettings = function () {
const FieldsList = () => {
const [ meta, setMeta ] = useEntityProp(
'postType',
- window.contentModelFields.postType,
+ POST_TYPE_NAME,
'meta'
);
@@ -168,7 +164,7 @@ const FieldsList = () => {
setFields( [
...fields,
{
- uuid: window.crypto.randomUUID(),
+ uuid: crypto.randomUUID(),
label: '',
slug: '',
description: '',
@@ -184,8 +180,3 @@ const FieldsList = () => {
>
);
};
-
-// Register the plugin.
-registerPlugin( 'create-content-model-page-settings', {
- render: CreateContentModelPageSettings,
-} );
diff --git a/includes/manager/_manage-bindings.js b/includes/manager/src/components/manage-bindings.js
similarity index 86%
rename from includes/manager/_manage-bindings.js
rename to includes/manager/src/components/manage-bindings.js
index 66ea56b..d24900f 100644
--- a/includes/manager/_manage-bindings.js
+++ b/includes/manager/src/components/manage-bindings.js
@@ -2,14 +2,8 @@ import { Button, TextControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useEntityProp } from '@wordpress/core-data';
import { useState, useEffect } from '@wordpress/element';
+import { POST_TYPE_NAME } from '../constants';
-/**
- * Display a form to edit a field.
- * @param {Object} props
- * @param {Function} props.onSave
- * @param {Object} props.defaultFormData (to be updated with the field data for editing)
- * @returns EditFieldForm
- */
const ManageBindings = ( {
defaultFormData = {
label: '',
@@ -17,7 +11,7 @@ const ManageBindings = ( {
description: '',
type: 'text',
visible: true,
- uuid: window.crypto.randomUUID(),
+ uuid: crypto.randomUUID(),
},
onSave = () => {},
} ) => {
@@ -26,7 +20,7 @@ const ManageBindings = ( {
const [ meta, setMeta ] = useEntityProp(
'postType',
- contentModelFields.postType,
+ POST_TYPE_NAME,
'meta'
);
diff --git a/includes/manager/src/constants.js b/includes/manager/src/constants.js
new file mode 100644
index 0000000..655c793
--- /dev/null
+++ b/includes/manager/src/constants.js
@@ -0,0 +1,11 @@
+// https://github.com/WordPress/WordPress/blob/master/wp-includes/class-wp-block.php#L246-L251
+export const SUPPORTED_BLOCK_ATTRIBUTES = {
+ 'core/group': [ 'content' ],
+ 'core/paragraph': [ 'content' ],
+ 'core/heading': [ 'content' ],
+ 'core/image': [ 'id', 'url', 'title', 'alt' ],
+ 'core/button': [ 'url', 'text', 'linkTarget', 'rel' ],
+};
+
+export const { BINDINGS_KEY, BLOCK_VARIATION_NAME_ATTR, POST_TYPE_NAME } =
+ window.contentModelData;
diff --git a/includes/manager/content-model-title-length-restrictor.js b/includes/manager/src/hooks/use-content-model-name-length-restrictor.js
similarity index 79%
rename from includes/manager/content-model-title-length-restrictor.js
rename to includes/manager/src/hooks/use-content-model-name-length-restrictor.js
index a9b8b0a..940db3b 100644
--- a/includes/manager/content-model-title-length-restrictor.js
+++ b/includes/manager/src/hooks/use-content-model-name-length-restrictor.js
@@ -3,9 +3,8 @@ import { useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
import { store as noticesStore } from '@wordpress/notices';
-import { registerPlugin } from '@wordpress/plugins';
-const ContentModelLengthRestrictor = () => {
+export const useContentModelNameLengthRestrictor = () => {
const { editPost } = useDispatch( editorStore );
const { createNotice } = useDispatch( noticesStore );
@@ -27,7 +26,3 @@ const ContentModelLengthRestrictor = () => {
}
}, [ title, editPost, createNotice ] );
};
-
-registerPlugin( 'content-model-title-length-restrictor', {
- render: ContentModelLengthRestrictor,
-} );
diff --git a/includes/manager/default-value-placeholder-changer.js b/includes/manager/src/hooks/use-default-value-placeholder-changer.js
similarity index 83%
rename from includes/manager/default-value-placeholder-changer.js
rename to includes/manager/src/hooks/use-default-value-placeholder-changer.js
index 018b2b1..d775509 100644
--- a/includes/manager/default-value-placeholder-changer.js
+++ b/includes/manager/src/hooks/use-default-value-placeholder-changer.js
@@ -2,9 +2,8 @@ import { __, sprintf } from '@wordpress/i18n';
import { useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';
-import { registerPlugin } from '@wordpress/plugins';
-const ContentModelDefaultValuePlaceholderChanger = () => {
+export const useDefaultValuePlaceholderChanger = () => {
const boundBlocks = useSelect( ( select ) => {
const blocks = select( blockEditorStore ).getBlocks();
const map = {};
@@ -41,7 +40,3 @@ const ContentModelDefaultValuePlaceholderChanger = () => {
} );
}, [ boundBlocks, updateBlockAttributes ] );
};
-
-registerPlugin( 'content-model-default-value-placeholder-changer', {
- render: ContentModelDefaultValuePlaceholderChanger,
-} );
diff --git a/includes/manager/src/register-attribute-binder.js b/includes/manager/src/register-attribute-binder.js
new file mode 100644
index 0000000..6146040
--- /dev/null
+++ b/includes/manager/src/register-attribute-binder.js
@@ -0,0 +1,51 @@
+import { addFilter } from '@wordpress/hooks';
+import { useMemo } from '@wordpress/element';
+import { createHigherOrderComponent } from '@wordpress/compose';
+import { useSelect } from '@wordpress/data';
+import { store as blockEditorStore } from '@wordpress/block-editor';
+
+import { SUPPORTED_BLOCK_ATTRIBUTES, BINDINGS_KEY } from './constants';
+import { AttributeBinderPanel } from './components/attribute-binder-panel';
+
+const withAttributeBinder = createHigherOrderComponent( ( BlockEdit ) => {
+ return ( props ) => {
+ const { getBlockParentsByBlockName, getBlocksByClientId } =
+ useSelect( blockEditorStore );
+
+ const blockParentsByBlockName = getBlockParentsByBlockName(
+ props.clientId,
+ [ 'core/group' ]
+ );
+
+ const parentHasBindings = useMemo( () => {
+ return (
+ getBlocksByClientId( blockParentsByBlockName ).filter(
+ ( block ) =>
+ Object.keys(
+ block?.attributes?.metadata?.[ BINDINGS_KEY ] || {}
+ ).length > 0
+ ).length > 0
+ );
+ }, [ blockParentsByBlockName, getBlocksByClientId ] );
+
+ const shouldDisplayAttributeBinderPanel =
+ SUPPORTED_BLOCK_ATTRIBUTES[ props.name ] && ! parentHasBindings;
+
+ return (
+ <>
+
+ { shouldDisplayAttributeBinderPanel && (
+
+ ) }
+ >
+ );
+ };
+}, 'withAttributeBinder' );
+
+export const registerAttributeBinder = () => {
+ addFilter(
+ 'editor.BlockEdit',
+ 'content-model/attribute-binder',
+ withAttributeBinder
+ );
+};
diff --git a/includes/manager/src/register-content-model-title-length-restrictor.js b/includes/manager/src/register-content-model-title-length-restrictor.js
new file mode 100644
index 0000000..95ccda4
--- /dev/null
+++ b/includes/manager/src/register-content-model-title-length-restrictor.js
@@ -0,0 +1,11 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { useContentModelNameLengthRestrictor } from './hooks/use-content-model-name-length-restrictor';
+
+export const registerContentModelLengthRestrictor = () => {
+ registerPlugin( 'content-model-title-length-restrictor', {
+ render: () => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useContentModelNameLengthRestrictor();
+ },
+ } );
+};
diff --git a/includes/manager/src/register-cpt-settings-panel.js b/includes/manager/src/register-cpt-settings-panel.js
new file mode 100644
index 0000000..b3033b5
--- /dev/null
+++ b/includes/manager/src/register-cpt-settings-panel.js
@@ -0,0 +1,8 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { CPTSettingsPanel } from './components/cpt-settings-panel';
+
+export const registerCPTSettingsPanel = () => {
+ registerPlugin( 'create-content-model-cpt-settings-pannel', {
+ render: CPTSettingsPanel,
+ } );
+};
diff --git a/includes/manager/src/register-default-value-placeholder-changer.js b/includes/manager/src/register-default-value-placeholder-changer.js
new file mode 100644
index 0000000..16ebd14
--- /dev/null
+++ b/includes/manager/src/register-default-value-placeholder-changer.js
@@ -0,0 +1,11 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { useDefaultValuePlaceholderChanger } from './hooks/use-default-value-placeholder-changer';
+
+export const registerDefaultValuePlaceholderChanger = () => {
+ registerPlugin( 'content-model-default-value-placeholder-changer', {
+ render: () => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useDefaultValuePlaceholderChanger();
+ },
+ } );
+};
diff --git a/includes/manager/src/register-fields-ui.js b/includes/manager/src/register-fields-ui.js
new file mode 100644
index 0000000..dc5cf89
--- /dev/null
+++ b/includes/manager/src/register-fields-ui.js
@@ -0,0 +1,8 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { FieldsUI } from './components/fields-ui';
+
+export const registerFieldsUI = () => {
+ registerPlugin( 'create-content-model-fields-ui', {
+ render: FieldsUI,
+ } );
+};
diff --git a/includes/runtime/class-content-model.php b/includes/runtime/class-content-model.php
index 97b2669..f9e6fc6 100644
--- a/includes/runtime/class-content-model.php
+++ b/includes/runtime/class-content-model.php
@@ -81,10 +81,8 @@ public function __construct( WP_Post $content_model_post ) {
$this->blocks = $this->inflate_template_blocks( $this->template );
$this->fields = json_decode( get_post_meta( $content_model_post->ID, 'fields', true ), true );
$this->register_meta_fields();
- $this->maybe_enqueue_the_fields_ui();
- $this->maybe_enqueue_bound_group_extractor();
- $this->maybe_enqueue_content_locking();
- $this->maybe_enqueue_fallback_value_clearer();
+
+ add_action( 'enqueue_block_editor_assets', array( $this, 'maybe_enqueue_scripts' ) );
add_filter( 'block_categories_all', array( $this, 'register_block_category' ) );
@@ -462,167 +460,35 @@ public function swap_post_content_with_hydrated_template( $post_content ) {
}
/**
- * When you use the Bindings API, the Editor automatically extracts bound attributes as post meta.
- * But because we're binding to the inner blocks of Groups (and not an attribute),
- * we need to manually extract it.
- *
- * @return void
- */
- private function maybe_enqueue_bound_group_extractor() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || $this->slug !== $post->post_type ) {
- return;
- }
-
- $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/runtime/dist/bound-group-extractor.asset.php';
-
- wp_register_script(
- 'data-types/bound-group-extractor',
- CONTENT_MODEL_PLUGIN_URL . '/includes/runtime/dist/bound-group-extractor.js',
- $asset_file['dependencies'],
- $asset_file['version'],
- true
- );
-
- wp_localize_script(
- 'data-types/bound-group-extractor',
- 'contentModelFields',
- array(
- 'postType' => $this->slug,
- 'fields' => $this->fields,
- )
- );
-
- wp_enqueue_script( 'data-types/bound-group-extractor' );
- }
- );
- }
-
- /**
- * Conditionally enqueues the fields UI script for the block editor.
- *
- * Checks if the current post is of the correct type before enqueueing the script.
- *
- * @return void
- */
- private function maybe_enqueue_the_fields_ui() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || $this->slug !== $post->post_type ) {
- return;
- }
-
- $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/runtime/dist/fields-ui.asset.php';
-
- wp_register_script(
- 'data-types/fields-ui',
- CONTENT_MODEL_PLUGIN_URL . '/includes/runtime/dist/fields-ui.js',
- $asset_file['dependencies'],
- $asset_file['version'],
- true
- );
-
- wp_localize_script(
- 'data-types/fields-ui',
- 'contentModelFields',
- array(
- 'postType' => $this->slug,
- 'fields' => $this->fields,
- )
- );
-
- wp_enqueue_script( 'data-types/fields-ui' );
- }
- );
- }
-
-
- /**
- * Conditionally enqueues the fields UI script for the block editor.
- *
- * Checks if the current post is of the correct type before enqueueing the script.
+ * Enqueue the helper scripts if entering data to a content model.
*
* @return void
*/
- private function maybe_enqueue_content_locking() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || $this->slug !== $post->post_type ) {
- return;
- }
-
- $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/runtime/dist/content-locking.asset.php';
+ public function maybe_enqueue_scripts() {
+ global $post;
- wp_register_script(
- 'data-types/content-locking',
- CONTENT_MODEL_PLUGIN_URL . '/includes/runtime/dist/content-locking.js',
- $asset_file['dependencies'],
- $asset_file['version'],
- true
- );
+ if ( ! $post || $this->slug !== $post->post_type ) {
+ return;
+ }
- wp_localize_script(
- 'data-types/content-locking',
- 'contentModelFields',
- array(
- 'postType' => $this->slug,
- 'fields' => $this->fields,
- )
- );
+ $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/runtime/dist/runtime.asset.php';
- wp_enqueue_script( 'data-types/content-locking' );
- }
+ wp_enqueue_script(
+ 'content-model/runtime',
+ CONTENT_MODEL_PLUGIN_URL . '/includes/runtime/dist/runtime.js',
+ $asset_file['dependencies'],
+ $asset_file['version'],
+ true
);
- }
- /**
- * Conditionally enqueues the fallback value clearer, allowing the block to become editable.
- *
- * Checks if the current post is of the correct type before enqueueing the script.
- *
- * @return void
- */
- private function maybe_enqueue_fallback_value_clearer() {
- add_action(
- 'enqueue_block_editor_assets',
- function () {
- global $post;
-
- if ( ! $post || $this->slug !== $post->post_type ) {
- return;
- }
-
- $asset_file = include CONTENT_MODEL_PLUGIN_PATH . 'includes/runtime/dist/fallback-value-clearer.asset.php';
-
- wp_register_script(
- 'data-types/fallback-value-clearer',
- CONTENT_MODEL_PLUGIN_URL . '/includes/runtime/dist/fallback-value-clearer.js',
- $asset_file['dependencies'],
- $asset_file['version'],
- true
- );
-
- wp_localize_script(
- 'data-types/fallback-value-clearer',
- 'contentModelFields',
- array(
- 'postType' => $this->slug,
- 'FALLBACK_VALUE_PLACEHOLDER' => self::FALLBACK_VALUE_PLACEHOLDER,
- )
- );
-
- wp_enqueue_script( 'data-types/fallback-value-clearer' );
- }
+ wp_localize_script(
+ 'content-model/runtime',
+ 'contentModelData',
+ array(
+ 'POST_TYPE' => $this->slug,
+ 'FIELDS' => $this->fields,
+ 'FALLBACK_VALUE_PLACEHOLDER' => self::FALLBACK_VALUE_PLACEHOLDER,
+ )
);
}
}
diff --git a/includes/runtime/fields-ui.js b/includes/runtime/fields-ui.js
deleted file mode 100644
index 989692f..0000000
--- a/includes/runtime/fields-ui.js
+++ /dev/null
@@ -1,201 +0,0 @@
-import { registerPlugin } from '@wordpress/plugins';
-import { PluginDocumentSettingPanel } from '@wordpress/editor';
-import {
- Button,
- Modal,
- TextControl,
- TextareaControl,
- __experimentalVStack as VStack,
- Card,
- CardBody,
- CardFooter,
-} from '@wordpress/components';
-import { MediaPlaceholder } from '@wordpress/block-editor';
-import { __ } from '@wordpress/i18n';
-import { useEntityProp } from '@wordpress/core-data';
-import { useState } from '@wordpress/element';
-
-/**
- * Our base plugin component.
- * @returns CreateContentModelFieldsUI
- */
-const CreateContentModelFieldsUI = function () {
- const [ isFieldsOpen, setFieldsOpen ] = useState( false );
-
- const fields = contentModelFields.fields;
-
- if (
- ! fields ||
- fields.filter( ( field ) => field.visible ).length === 0
- ) {
- return null;
- }
-
- return (
-
-
-
-
-
-
- { isFieldsOpen && (
- setFieldsOpen( false ) }
- >
-
-
- ) }
-
- );
-};
-
-/**
- * Display the list of fields inside the modal.
- * @returns FieldsList
- */
-const FieldsList = () => {
- const fields = contentModelFields.fields;
-
- return (
- <>
-
- { fields
- .filter( ( field ) => field.visible )
- .map( ( field ) => (
-
- ) ) }
-
- >
- );
-};
-
-/**
- * Display a row for a field.
- * @param {Object} field
- * @returns FieldRow
- */
-const FieldRow = ( { field } ) => {
- const [ meta, setMeta ] = useEntityProp(
- 'postType',
- contentModelFields.postType,
- 'meta'
- );
-
- const value = meta[ field.slug ] ?? '';
-
- return (
- <>
-
- {
- setMeta( {
- [ slug ]: value,
- } );
- } }
- />
-
- { field.description }
-
-
- >
- );
-};
-
-/**
- * Display the input for a field.
- * @param {Object} field
- * @param {boolean} isDisabled
- * @returns FieldInput
- */
-const FieldInput = ( { field, isDisabled = false, value, saveChanges } ) => {
- switch ( field.type ) {
- case 'image':
- return (
- <>
-
- { value && (
-
-
-
-
-
-
-
-
- ) }
- { ! value && (
-
- saveChanges( field.slug, value.url )
- }
- />
- ) }
- >
- );
- break;
-
- case 'textarea':
- return (
- saveChanges( field.slug, value ) }
- />
- );
- break;
-
- default:
- return (
- saveChanges( field.slug, value ) }
- />
- );
- break;
- }
-};
-
-// Register the plugin.
-registerPlugin( 'create-content-model-fields-ui', {
- render: CreateContentModelFieldsUI,
-} );
diff --git a/includes/runtime/runtime.js b/includes/runtime/runtime.js
new file mode 100644
index 0000000..6767b6b
--- /dev/null
+++ b/includes/runtime/runtime.js
@@ -0,0 +1,9 @@
+import { registerBoundGroupExtractor } from './src/register-bound-group-extractor';
+import { registerContentLocking } from './src/register-content-locking';
+import { registerFallbackValueClearer } from './src/register-fallback-value-clearer';
+import { registerFieldsUI } from './src/register-fields-ui';
+
+registerBoundGroupExtractor();
+registerFieldsUI();
+registerContentLocking();
+registerFallbackValueClearer();
diff --git a/includes/runtime/src/components/fields-ui.js b/includes/runtime/src/components/fields-ui.js
new file mode 100644
index 0000000..ae5d073
--- /dev/null
+++ b/includes/runtime/src/components/fields-ui.js
@@ -0,0 +1,156 @@
+import { PluginDocumentSettingPanel } from '@wordpress/editor';
+import {
+ Button,
+ Modal,
+ TextControl,
+ TextareaControl,
+ __experimentalVStack as VStack,
+ Card,
+ CardBody,
+ CardFooter,
+} from '@wordpress/components';
+import { MediaPlaceholder } from '@wordpress/block-editor';
+import { __ } from '@wordpress/i18n';
+import { useEntityProp } from '@wordpress/core-data';
+import { useState } from '@wordpress/element';
+import { FIELDS, POST_TYPE } from '../constants';
+
+export const FieldsUI = function () {
+ const [ isFieldsOpen, setFieldsOpen ] = useState( false );
+
+ if ( FIELDS.filter( ( field ) => field.visible ).length === 0 ) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+ { isFieldsOpen && (
+ setFieldsOpen( false ) }
+ >
+
+
+ ) }
+
+ );
+};
+
+const FieldsList = ( { fields } ) => {
+ return (
+
+ { fields
+ .filter( ( field ) => field.visible )
+ .map( ( field ) => (
+
+ ) ) }
+
+ );
+};
+
+const FieldRow = ( { field } ) => {
+ const [ meta, setMeta ] = useEntityProp( 'postType', POST_TYPE, 'meta' );
+
+ const value = meta[ field.slug ] ?? '';
+
+ return (
+
+ {
+ setMeta( {
+ [ slug ]: newValue,
+ } );
+ } }
+ />
+
+ { field.description }
+
+
+ );
+};
+
+const FieldInput = ( { field, isDisabled = false, value, saveChanges } ) => {
+ if ( 'image' === field.type ) {
+ return (
+ <>
+
+ { field.label }
+
+ { ! value && (
+
+ saveChanges( field.slug, newValue.url )
+ }
+ />
+ ) }
+ { value && (
+
+
+
+
+
+
+
+
+ ) }
+ >
+ );
+ }
+
+ if ( 'textarea' === field.type ) {
+ return (
+ saveChanges( field.slug, newValue ) }
+ />
+ );
+ }
+
+ return (
+ saveChanges( field.slug, newValue ) }
+ />
+ );
+};
diff --git a/includes/manager/_supported-attributes.js b/includes/runtime/src/constants.js
similarity index 68%
rename from includes/manager/_supported-attributes.js
rename to includes/runtime/src/constants.js
index 370fae7..934af4f 100644
--- a/includes/manager/_supported-attributes.js
+++ b/includes/runtime/src/constants.js
@@ -1,5 +1,5 @@
// https://github.com/WordPress/WordPress/blob/master/wp-includes/class-wp-block.php#L246-L251
-const SUPPORTED_BLOCK_ATTRIBUTES = {
+export const SUPPORTED_BLOCK_ATTRIBUTES = {
'core/group': [ 'content' ],
'core/paragraph': [ 'content' ],
'core/heading': [ 'content' ],
@@ -7,4 +7,5 @@ const SUPPORTED_BLOCK_ATTRIBUTES = {
'core/button': [ 'url', 'text', 'linkTarget', 'rel' ],
};
-export default SUPPORTED_BLOCK_ATTRIBUTES;
+export const { POST_TYPE, FIELDS, FALLBACK_VALUE_PLACEHOLDER } =
+ window.contentModelData;
diff --git a/includes/runtime/bound-group-extractor.js b/includes/runtime/src/hooks/use-bound-group-extractor.js
similarity index 73%
rename from includes/runtime/bound-group-extractor.js
rename to includes/runtime/src/hooks/use-bound-group-extractor.js
index 182ca7f..0b31842 100644
--- a/includes/runtime/bound-group-extractor.js
+++ b/includes/runtime/src/hooks/use-bound-group-extractor.js
@@ -1,9 +1,23 @@
import { useEffect } from '@wordpress/element';
-import { registerPlugin } from '@wordpress/plugins';
import { useEntityProp } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/block-editor';
import { serialize } from '@wordpress/blocks';
+import { POST_TYPE } from '../constants';
+
+export const useBoundGroupExtractor = () => {
+ const blocks = useSelect( ( select ) => select( editorStore ).getBlocks() );
+
+ const [ , setMeta ] = useEntityProp( 'postType', POST_TYPE, 'meta' );
+
+ useEffect( () => {
+ const boundBlocks = findBoundBlocks( blocks );
+
+ setMeta( boundBlocks );
+ }, [ blocks, setMeta ] );
+
+ return null;
+};
const findBoundBlocks = ( blocks, acc = {} ) => {
for ( const block of blocks ) {
@@ -24,25 +38,3 @@ const findBoundBlocks = ( blocks, acc = {} ) => {
return acc;
};
-
-const CreateContentModelBoundGroupExtractor = () => {
- const blocks = useSelect( ( select ) => select( editorStore ).getBlocks() );
-
- const [ , setMeta ] = useEntityProp(
- 'postType',
- window.contentModelFields.postType,
- 'meta'
- );
-
- useEffect( () => {
- const boundBlocks = findBoundBlocks( blocks );
-
- setMeta( boundBlocks );
- }, [ blocks, setMeta ] );
-
- return null;
-};
-
-registerPlugin( 'create-content-model-bound-group-extractor', {
- render: CreateContentModelBoundGroupExtractor,
-} );
diff --git a/includes/runtime/content-locking.js b/includes/runtime/src/hooks/use-content-locking.js
similarity index 77%
rename from includes/runtime/content-locking.js
rename to includes/runtime/src/hooks/use-content-locking.js
index 67d1689..80a229f 100644
--- a/includes/runtime/content-locking.js
+++ b/includes/runtime/src/hooks/use-content-locking.js
@@ -1,16 +1,11 @@
-import { registerPlugin } from '@wordpress/plugins';
import { useEffect } from '@wordpress/element';
-import { dispatch } from '@wordpress/data';
-import { useDispatch } from '@wordpress/data';
+import { dispatch, useDispatch } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';
+import { SUPPORTED_BLOCK_ATTRIBUTES } from '../constants';
-/**
- * Our base plugin component.
- * @returns CreateContentModelPageSettings
- */
-const CreateContentModelContentLocking = function () {
- const fields = contentModelFields.fields;
+const SUPPORTED_BLOCKS = Object.keys( SUPPORTED_BLOCK_ATTRIBUTES );
+export const useContentLocking = function () {
const blocks = wp.data.select( 'core/block-editor' ).getBlocks();
const currentBlock = wp.data
@@ -19,25 +14,12 @@ const CreateContentModelContentLocking = function () {
const { setBlockEditingMode } = useDispatch( blockEditorStore );
- if ( ! fields ) {
- return null;
- }
-
useEffect( () => {
if ( blocks.length > 0 ) {
parseBlocks( blocks, setBlockEditingMode );
}
}, [ blocks, setBlockEditingMode, currentBlock ] );
-
- return;
};
-const SUPPORTED_BLOCKS = [
- 'core/group',
- 'core/paragraph',
- 'core/heading',
- 'core/image',
- 'core/button',
-];
const parseBlocks = ( blocks, setEditMode, forceEnabled = false ) => {
blocks.forEach( ( block ) => {
@@ -100,8 +82,3 @@ const findBoundGroup = ( blocks ) => {
}
return null;
};
-
-// Register the plugin.
-registerPlugin( 'create-content-model-content-locking', {
- render: CreateContentModelContentLocking,
-} );
diff --git a/includes/runtime/fallback-value-clearer.js b/includes/runtime/src/hooks/use-fallback-value-clearer.js
similarity index 81%
rename from includes/runtime/fallback-value-clearer.js
rename to includes/runtime/src/hooks/use-fallback-value-clearer.js
index 0529350..54e2e48 100644
--- a/includes/runtime/fallback-value-clearer.js
+++ b/includes/runtime/src/hooks/use-fallback-value-clearer.js
@@ -1,8 +1,8 @@
import { useLayoutEffect } from '@wordpress/element';
-import { registerPlugin } from '@wordpress/plugins';
import { useEntityProp } from '@wordpress/core-data';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { useSelect, useDispatch } from '@wordpress/data';
+import { FALLBACK_VALUE_PLACEHOLDER, POST_TYPE } from '../constants';
/**
* This allows the user to edit values that are bound to an attribute.
@@ -13,12 +13,8 @@ import { useSelect, useDispatch } from '@wordpress/data';
*
* See https://github.com/Automattic/create-content-model/issues/63 for the problem.
*/
-const CreateContentModelFallbackValueClearer = () => {
- const [ meta, setMeta ] = useEntityProp(
- 'postType',
- window.contentModelFields.postType,
- 'meta'
- );
+export const useFallbackValueClearer = () => {
+ const [ meta, setMeta ] = useEntityProp( 'postType', POST_TYPE, 'meta' );
const { updateBlockAttributes } = useDispatch( blockEditorStore );
@@ -56,10 +52,8 @@ const CreateContentModelFallbackValueClearer = () => {
( [ blockId, metaInfos ] ) => {
metaInfos.forEach( ( { metaKey, blockName } ) => {
const value = meta[ metaKey ];
- if (
- value ===
- window.contentModelFields.FALLBACK_VALUE_PLACEHOLDER
- ) {
+
+ if ( value === FALLBACK_VALUE_PLACEHOLDER ) {
setMeta( { [ metaKey ]: '' } );
updateBlockAttributes( blockId, {
@@ -73,7 +67,3 @@ const CreateContentModelFallbackValueClearer = () => {
return null;
};
-
-registerPlugin( 'create-content-model-fallback-value-clearer', {
- render: CreateContentModelFallbackValueClearer,
-} );
diff --git a/includes/runtime/src/register-bound-group-extractor.js b/includes/runtime/src/register-bound-group-extractor.js
new file mode 100644
index 0000000..5b6f816
--- /dev/null
+++ b/includes/runtime/src/register-bound-group-extractor.js
@@ -0,0 +1,11 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { useBoundGroupExtractor } from './hooks/use-bound-group-extractor';
+
+export const registerBoundGroupExtractor = () => {
+ registerPlugin( 'create-content-model-bound-group-extractor', {
+ render: () => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useBoundGroupExtractor();
+ },
+ } );
+};
diff --git a/includes/runtime/src/register-content-locking.js b/includes/runtime/src/register-content-locking.js
new file mode 100644
index 0000000..8c8baf5
--- /dev/null
+++ b/includes/runtime/src/register-content-locking.js
@@ -0,0 +1,11 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { useContentLocking } from './hooks/use-content-locking';
+
+export const registerContentLocking = () => {
+ registerPlugin( 'create-content-model-content-locking', {
+ render: () => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useContentLocking();
+ },
+ } );
+};
diff --git a/includes/runtime/src/register-fallback-value-clearer.js b/includes/runtime/src/register-fallback-value-clearer.js
new file mode 100644
index 0000000..305e0c1
--- /dev/null
+++ b/includes/runtime/src/register-fallback-value-clearer.js
@@ -0,0 +1,11 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { useFallbackValueClearer } from './hooks/use-fallback-value-clearer';
+
+export const registerFallbackValueClearer = () => {
+ registerPlugin( 'create-content-model-fallback-value-clearer', {
+ render: () => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useFallbackValueClearer();
+ },
+ } );
+};
diff --git a/includes/runtime/src/register-fields-ui.js b/includes/runtime/src/register-fields-ui.js
new file mode 100644
index 0000000..220bb32
--- /dev/null
+++ b/includes/runtime/src/register-fields-ui.js
@@ -0,0 +1,9 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { FieldsUI } from './components/fields-ui';
+
+export const registerFieldsUI = () => {
+ // Register the plugin.
+ registerPlugin( 'create-content-model-fields-ui', {
+ render: FieldsUI,
+ } );
+};
diff --git a/webpack.config.js b/webpack.config.js
index 851b3f4..fcaa68a 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -8,9 +8,6 @@ const includesDir = path.resolve( process.cwd(), 'includes' );
const entries = glob
.sync( '*/*.js', { cwd: includesDir } )
- .filter( ( entry ) => {
- return ! entry.split( '/' )[ 1 ].startsWith( '_' );
- } )
.reduce( ( acc, entry ) => {
const [ folder, name ] = entry.split( '/' );