Skip to content

Commit

Permalink
Full Site Editing: Add a Template Part block (#32581)
Browse files Browse the repository at this point in the history
* Add a Template Part block.
It roughly works like the Content Slot block but, whereas that's a sort of placeholder for the template to be filled with a post or page, the Template Part is used to render a layout element into the template.
  • Loading branch information
Copons authored Apr 29, 2019
1 parent ed2051e commit ec422ed
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* eslint-disable wpcalypso/jsx-classname-namespace */
/**
* External dependencies
*/
import classNames from 'classnames';
import { get } from 'lodash';

/**
* WordPress dependencies
*/
import { IconButton, Placeholder, Toolbar } from '@wordpress/components';
import { withState } from '@wordpress/compose';
import { BlockControls } from '@wordpress/editor';
import { Fragment, RawHTML } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import PostAutocomplete from '../../components/post-autocomplete';
import fetchPost from '../../lib/fetch-post';
import './style.scss';

const setSelectedPost = async ( attributes, setState ) => {
const { selectedPostId, selectedPostType } = attributes;
const selectedPost = await fetchPost( selectedPostId, selectedPostType );
setState( {
selectedPost,
} );
};

const TemplatePartEdit = withState( {
isEditing: false,
selectedPost: null,
} )( ( { attributes, isEditing, selectedPost, setAttributes, setState } ) => {
const { align, selectedPostId } = attributes;

if ( !! selectedPostId && ! selectedPost ) {
setSelectedPost( attributes, setState );
}

const toggleEditing = () => setState( { isEditing: ! isEditing } );

const onSelectPost = post => {
setState( { isEditing: false, selectedPost: post } );
setAttributes( {
selectedPostId: get( post, 'id' ),
selectedPostType: get( post, 'type' ),
} );
};

const showToggleButton = ! isEditing || !! selectedPostId;
const showPlaceholder = isEditing || ! selectedPostId;
const showContent = ! isEditing && !! selectedPostId;

return (
<Fragment>
{ showToggleButton && (
<BlockControls>
<Toolbar>
<IconButton
className={ classNames( 'components-icon-button components-toolbar__control', {
'is-active': isEditing,
} ) }
label={ __( 'Change Template Part' ) }
onClick={ toggleEditing }
icon="edit"
/>
</Toolbar>
</BlockControls>
) }
<div
className={ classNames( 'a8c-template-part-block', {
[ `align${ align }` ]: align,
} ) }
>
{ showPlaceholder && (
<Placeholder
icon="layout"
label={ __( 'Template Part' ) }
instructions={ __( 'Select a template part to display' ) }
>
<div className="a8c-template-part-block__selector">
<PostAutocomplete
selectedPostTitle={ get( selectedPost, 'title.rendered' ) }
onSelectPost={ onSelectPost }
/>
{ !! selectedPostId && (
<a href={ `?post=${ selectedPostId }&action=edit` }>{ __( 'Edit' ) }</a>
) }
</div>
</Placeholder>
) }
{ showContent && (
<RawHTML className="a8c-template-part-block__content">
{ get( selectedPost, 'content.rendered' ) }
</RawHTML>
) }
</div>
</Fragment>
);
} );

export default TemplatePartEdit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* WordPress dependencies
*/
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import edit from './edit';
import './style.scss';

registerBlockType( 'a8c/template-part', {
title: __( 'Template Part' ),
description: __( 'Display a template part.' ),
icon: 'layout',
category: 'layout',
attributes: {
selectedPostId: { type: 'number' },
selectedPostType: { type: 'string' },
},
supports: {
align: [ 'wide', 'full' ],
anchor: true,
html: false,
reusable: false,
},
edit,
save: () => null,
} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

function render_template_part_block( $attributes ) {
if ( ! isset( $attributes['selectedPostId'] ) || ! is_int( $attributes['selectedPostId'] ) ) {
return;
}
$align = isset( $attributes['align'] ) ? ' align' . $attributes['align'] : '';
$post = get_post( $attributes['selectedPostId'] );
setup_postdata( $post );

$content = '<div class="a8c-template-part'. $align . '">'
. apply_filters( 'the_content', get_the_content() )
. '</div>';

wp_reset_postdata();
return $content;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.a8c-template-part-block.alignfull {
padding: 0 12px;
}

.a8c-template-part-block__selector {
width: 300px;
a {
font-family: sans-serif;
font-size: 13px;
padding-left: 8px;
}
}

.a8c-template-part-block__content {
pointer-events: none;
&::after {
content: '';
clear: both;
display: table;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
/**
* Plugin Name: Full Site Editing
*/

require_once( 'blocks/content-slot/index.php' );
require_once( 'blocks/template-part/index.php' );

class A8C_Full_Site_Editing {
static $initialized = false;
Expand Down Expand Up @@ -45,12 +47,18 @@ function register_script_and_style() {
);
}

// We only need to declare script and style as dependencies once
// Because they'll be then enqueued for every block.
function register_blocks() {
register_block_type( 'a8c/content-slot', array(
'editor_script' => 'a8c-full-site-editing-script',
'editor_style' => 'a8c-full-site-editing-style',
'render_callback' => 'render_content_slot_block',
) );

register_block_type( 'a8c/template-part', array(
'render_callback' => 'render_template_part_block',
) );
}
}

Expand Down
1 change: 1 addition & 0 deletions apps/full-site-editing/full-site-editing-plugin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
* Internal dependencies
*/
import './blocks/content-slot';
import './blocks/template-part';

0 comments on commit ec422ed

Please sign in to comment.