diff --git a/includes/class-newspack-newsletters-layouts.php b/includes/class-newspack-newsletters-layouts.php
index b76190ad8..16485b8da 100644
--- a/includes/class-newspack-newsletters-layouts.php
+++ b/includes/class-newspack-newsletters-layouts.php
@@ -42,6 +42,7 @@ public static function instance() {
*/
public function __construct() {
add_action( 'init', [ __CLASS__, 'register_layout_cpt' ] );
+ add_action( 'init', [ __CLASS__, 'register_meta' ] );
}
/**
@@ -55,12 +56,51 @@ public static function register_layout_cpt() {
$cpt_args = [
'public' => false,
'show_in_rest' => true,
- 'supports' => [ 'editor', 'title' ],
+ 'supports' => [ 'editor', 'title', 'custom-fields' ],
'taxonomies' => [],
];
\register_post_type( self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT, $cpt_args );
}
+ /**
+ * Register custom fields.
+ */
+ public static function register_meta() {
+ \register_meta(
+ 'post',
+ 'font_header',
+ [
+ 'object_subtype' => self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT,
+ 'show_in_rest' => true,
+ 'type' => 'string',
+ 'single' => true,
+ 'auth_callback' => '__return_true',
+ ]
+ );
+ \register_meta(
+ 'post',
+ 'font_body',
+ [
+ 'object_subtype' => self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT,
+ 'show_in_rest' => true,
+ 'type' => 'string',
+ 'single' => true,
+ 'auth_callback' => '__return_true',
+ ]
+ );
+ \register_meta(
+ 'post',
+ 'background_color',
+ [
+ 'object_subtype' => self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT,
+ 'show_in_rest' => true,
+ 'type' => 'string',
+ 'single' => true,
+ 'auth_callback' => '__return_true',
+ ]
+ );
+ }
+
/**
* Token replacement for newsletter layouts.
*
diff --git a/includes/class-newspack-newsletters.php b/includes/class-newspack-newsletters.php
index cbffa9cbe..6039fe917 100644
--- a/includes/class-newspack-newsletters.php
+++ b/includes/class-newspack-newsletters.php
@@ -429,8 +429,19 @@ public static function api_get_layouts() {
'posts_per_page' => -1,
)
);
+ $user_layouts = array_map(
+ function ( $post ) {
+ $post->meta = [
+ 'background_color' => get_post_meta( $post->ID, 'background_color', true ),
+ 'font_body' => get_post_meta( $post->ID, 'font_body', true ),
+ 'font_header' => get_post_meta( $post->ID, 'font_header', true ),
+ ];
+ return $post;
+ },
+ $layouts_query->get_posts()
+ );
$layouts = array_merge(
- $layouts_query->get_posts(),
+ $user_layouts,
Newspack_Newsletters_Layouts::get_default_layouts(),
apply_filters( 'newspack_newsletters_templates', [] )
);
diff --git a/src/components/init-modal/screens/layout-picker/SingleLayoutPreview.js b/src/components/init-modal/screens/layout-picker/SingleLayoutPreview.js
index efa53f106..f6126ab86 100644
--- a/src/components/init-modal/screens/layout-picker/SingleLayoutPreview.js
+++ b/src/components/init-modal/screens/layout-picker/SingleLayoutPreview.js
@@ -11,7 +11,6 @@ import { parse } from '@wordpress/blocks';
import { useState, useMemo } from '@wordpress/element';
import { Button, TextControl } from '@wordpress/components';
import { ENTER, SPACE } from '@wordpress/keycodes';
-import { BlockPreview } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
/**
@@ -19,6 +18,7 @@ import { __ } from '@wordpress/i18n';
*/
import { LAYOUT_CPT_SLUG } from '../../../../utils/consts';
import { setPreventDeduplicationForPostsInserter } from '../../../../editor/blocks/posts-inserter/utils';
+import NewsletterPreview from '../../../newsletter-preview';
const SingleLayoutPreview = ( {
isEditable,
@@ -29,6 +29,7 @@ const SingleLayoutPreview = ( {
ID,
post_title: title,
post_content: content,
+ meta,
} ) => {
const handleDelete = () => {
// eslint-disable-next-line no-alert
@@ -75,7 +76,7 @@ const SingleLayoutPreview = ( {
aria-label={ title }
>
{ '' === content ? null : (
-
+
) }
{ isEditable ? (
diff --git a/src/components/init-modal/screens/layout-picker/index.js b/src/components/init-modal/screens/layout-picker/index.js
index 2a8e06cad..f547e69b6 100644
--- a/src/components/init-modal/screens/layout-picker/index.js
+++ b/src/components/init-modal/screens/layout-picker/index.js
@@ -13,7 +13,6 @@ import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
import { Button, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
-import { BlockPreview } from '@wordpress/block-editor';
/**
* Internal dependencies
@@ -22,6 +21,7 @@ import { BLANK_LAYOUT_ID } from '../../../../utils/consts';
import { isUserDefinedLayout } from '../../../../utils';
import { useLayoutsState } from '../../../../utils/hooks';
import SingleLayoutPreview from './SingleLayoutPreview';
+import NewsletterPreview from '../../../newsletter-preview';
const LAYOUTS_TABS = [
{
@@ -35,11 +35,17 @@ const LAYOUTS_TABS = [
},
];
-const LayoutPicker = ( { getBlocks, insertBlocks, replaceBlocks, savePost, setLayoutIdMeta } ) => {
+const LayoutPicker = ( {
+ getBlocks,
+ insertBlocks,
+ replaceBlocks,
+ savePost,
+ setNewsletterMeta,
+} ) => {
const { layouts, isFetchingLayouts, deleteLayoutPost } = useLayoutsState();
const insertLayout = layoutId => {
- const { post_content: content } = find( layouts, { ID: layoutId } ) || {};
+ const { post_content: content, meta = {} } = find( layouts, { ID: layoutId } ) || {};
const blocksToInsert = content ? parse( content ) : [];
const existingBlocksIds = getBlocks().map( ( { clientId } ) => clientId );
if ( existingBlocksIds.length ) {
@@ -47,21 +53,25 @@ const LayoutPicker = ( { getBlocks, insertBlocks, replaceBlocks, savePost, setLa
} else {
insertBlocks( blocksToInsert );
}
- setLayoutIdMeta( layoutId );
+ const metaPayload = {
+ template_id: layoutId,
+ ...meta,
+ };
+ setNewsletterMeta( metaPayload );
setTimeout( savePost, 1 );
};
const [ selectedLayoutId, setSelectedLayoutId ] = useState( null );
- const layoutBlocks = useMemo(() => {
+ const layoutPreviewProps = useMemo(() => {
const layout = selectedLayoutId && find( layouts, { ID: selectedLayoutId } );
- return layout ? parse( layout.post_content ) : null;
+ return layout ? { blocks: parse( layout.post_content ), meta: layout.meta } : null;
}, [ selectedLayoutId, layouts.length ]);
- const canRenderPreview = layoutBlocks && layoutBlocks.length > 0;
+ const canRenderPreview = layoutPreviewProps && layoutPreviewProps.blocks.length > 0;
const renderPreview = () =>
canRenderPreview ? (
-
+
) : (
{ __( 'Select a layout to preview.', 'newspack-newsletters' ) }
);
@@ -166,7 +176,7 @@ export default compose( [
savePost,
insertBlocks,
replaceBlocks,
- setLayoutIdMeta: id => editPost( { meta: { template_id: id } } ),
+ setNewsletterMeta: meta => editPost( { meta } ),
};
} ),
] )( LayoutPicker );
diff --git a/src/components/newsletter-preview/index.js b/src/components/newsletter-preview/index.js
new file mode 100644
index 000000000..18cbb8f37
--- /dev/null
+++ b/src/components/newsletter-preview/index.js
@@ -0,0 +1,45 @@
+/**
+ * WordPress dependencies
+ */
+import { BlockPreview } from '@wordpress/block-editor';
+import { Fragment, useMemo } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import './style.scss';
+
+const NewsletterPreview = ( { meta = {}, ...props } ) => {
+ const ELEMENT_ID = useMemo( () => `preview-${ Math.round( Math.random() * 1000 ) }`, [] );
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default NewsletterPreview;
diff --git a/src/components/newsletter-preview/style.scss b/src/components/newsletter-preview/style.scss
new file mode 100644
index 000000000..136fe2b68
--- /dev/null
+++ b/src/components/newsletter-preview/style.scss
@@ -0,0 +1,5 @@
+.newspack-newsletters__layout-preview {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+}
diff --git a/src/newsletter-editor/layout/index.js b/src/newsletter-editor/layout/index.js
index 93b34e4e2..f0780a999 100644
--- a/src/newsletter-editor/layout/index.js
+++ b/src/newsletter-editor/layout/index.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { find } from 'lodash';
+import { isEqual, find } from 'lodash';
/**
* WordPress dependencies
@@ -9,7 +9,6 @@ import { find } from 'lodash';
import { compose } from '@wordpress/compose';
import { parse, serialize } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
-import { BlockPreview } from '@wordpress/block-editor';
import { withDispatch, withSelect } from '@wordpress/data';
import { Fragment, useState, useEffect, useMemo } from '@wordpress/element';
import { Button, Modal, TextControl, Spinner } from '@wordpress/components';
@@ -22,22 +21,28 @@ import { LAYOUT_CPT_SLUG, NEWSLETTER_CPT_SLUG } from '../../utils/consts';
import { isUserDefinedLayout } from '../../utils';
import './style.scss';
import { setPreventDeduplicationForPostsInserter } from '../../editor/blocks/posts-inserter/utils';
+import NewsletterPreview from '../../components/newsletter-preview';
export default compose( [
withSelect( select => {
const { getEditedPostAttribute, isEditedPostEmpty, getCurrentPostId } = select( 'core/editor' );
const { getBlocks } = select( 'core/block-editor' );
const meta = getEditedPostAttribute( 'meta' );
- const { template_id: layoutId } = meta;
+ const { template_id: layoutId, background_color, font_body, font_header } = meta;
return {
layoutId,
postTitle: getEditedPostAttribute( 'title' ),
postBlocks: getBlocks(),
isEditedPostEmpty: isEditedPostEmpty(),
currentPostId: getCurrentPostId(),
+ stylingMeta: {
+ background_color,
+ font_body,
+ font_header,
+ },
};
} ),
- withDispatch( ( dispatch, { currentPostId } ) => {
+ withDispatch( ( dispatch, { currentPostId, stylingMeta } ) => {
const { replaceBlocks } = dispatch( 'core/block-editor' );
const { editPost } = dispatch( 'core/editor' );
const { saveEntityRecord } = dispatch( 'core' );
@@ -48,7 +53,7 @@ export default compose( [
editPost( { meta: { template_id: id } } );
saveEntityRecord( 'postType', NEWSLETTER_CPT_SLUG, {
id: currentPostId,
- meta: { template_id: id },
+ meta: { template_id: id, ...stylingMeta },
} );
},
saveLayout: payload =>
@@ -67,6 +72,7 @@ export default compose( [
postBlocks,
postTitle,
isEditedPostEmpty,
+ stylingMeta,
} ) => {
const [ warningModalVisible, setWarningModalVisible ] = useState( false );
const { layouts, isFetchingLayouts } = useLayoutsState();
@@ -108,13 +114,15 @@ export default compose( [
};
const postContent = useMemo( () => serialize( postBlocks ), [ postBlocks ] );
- const isPostContentSameAsLayout = postContent === usedLayout.post_content;
+ const isPostContentSameAsLayout =
+ postContent === usedLayout.post_content && isEqual( usedLayout.meta, stylingMeta );
const handleSaveAsLayout = () => {
setIsSavingLayout( true );
const updatePayload = {
title: newLayoutName,
content: postContent,
+ meta: stylingMeta,
};
saveLayout( updatePayload ).then( newLayout => {
setIsManageModalVisible( false );
@@ -130,8 +138,9 @@ export default compose( [
) {
setIsSavingLayout( true );
const updatePayload = {
- content: postContent,
id: usedLayout.ID,
+ content: postContent,
+ meta: stylingMeta,
};
saveLayout( updatePayload ).then( handleLayoutUpdate );
}
@@ -150,7 +159,8 @@ export default compose( [