Skip to content

How to add a new Component

Create new Component

Clone the repository and navigate to the themes/everyday-base-theme directory if you haven’t already.

To create a new component we go into the folder blocks/components and add there a new folder for example job-list.

Inside the folder we add following file job-list.jsx. Now we have a new empty react component.

For a faster development. We generate via Visual Studio Code vscode snippets. Feel free to add more snippets for your needs. You can find the snippets in the theme folder under .vscode/snippets.code-snippets.

"React Component WordPress Block": {
"scope": "javascript,typescript,javascriptreact,typescriptreact",
"prefix": "rcblock",
"body": [
"import { registerBlockType } from '@wordpress/blocks';",
"import { layout } from '@wordpress/icons';",
"registerBlockType('basetheme/${TM_FILENAME_BASE}', {",
" title: '${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}',",
" icon: layout,",
" category: 'layout',",
" description: 'A Description',",
" keywords: '[]',",
" supports: {},",
" attributes: {},",
"",
" edit: EditComponent,",
" save: SaveComponent,",
"});",
"",
"function EditComponent(props) {",
" const { attributes, setAttributes } = props;",
" return (",
" <div>",
" <h1>Hello World</h1>",
" </div>",
" );",
"}",
"",
"function SaveComponent() {",
" return (",
" <div>",
" <h1>Hello World</h1>",
" </div>",
" );",
"}",
""
],
"description": "Register a WordPress block using the filename as the component name"
},


With typing the prefix rcblock we generate the whole boilerplate code for a new WordPress block. It’s automatically add the component name based on the filename. We must changed then the icon and the category.

Below is now the example of the new component.

import { registerBlockType } from '@wordpress/blocks';
import { layout } from '@wordpress/icons';
registerBlockType('basetheme/job-list', {
title: 'Job-list',
icon: layout,
category: 'layout',
description: 'A Description',
keywords: '[]',
supports: {},
attributes: {},
edit: EditComponent,
save: SaveComponent,
});
function EditComponent(props) {
const { attributes, setAttributes } = props;
return (
<div>
<h1>Hello World</h1>
</div>
);
}
function SaveComponent() {
return (
<div>
<h1>Hello World</h1>
</div>
);
}

Where to Import the Component

After we initialise the component, we need to import it into the relevant files.

In the functions.php file we had a filter to deactivate not used blocks. To activate the new block we must add it to the list of allowed blocks.

Search for follwing function allowed_blocks and add the new component basetheme/job-list into the array.

function allowed_blocks($allowed_block_types)
{
return array(
'core/paragraph',
'basetheme/accordion-container',
'basetheme/accordion-item',
'basetheme/big-teaser',
'basetheme/blog-post',
'basetheme/button',
'basetheme/call-to-action-container',
'basetheme/call-to-action-item',
'basetheme/card',
'basetheme/container',
'basetheme/heading',
'basetheme/text',
'basetheme/button',
'basetheme/blog-post',
'basetheme/google-maps',
'basetheme/reference',
'basetheme/accordion-container',
'basetheme/footer-container',
'basetheme/footer-item',
'basetheme/footer-navigation',
'basetheme/footer-social-media-container',
'basetheme/footer-social-media-icon',
'basetheme/footer-text',
'basetheme/grid-container',
'basetheme/grid-item',
'basetheme/person',
'basetheme/hero-slider',
'basetheme/hero-slider-item',
'basetheme/image',
'basetheme/logo-swiper-container',
'basetheme/logo-swiper-item',
'basetheme/navigation',
'basetheme/image-swiper',
'basetheme/image-swiper-item',
'basetheme/test',
"basetheme/list",
"basetheme/list-item",
"basetheme/job-list",
'contact-form-7/contact-form-selector',
);
}

To use the new block, we also must import the new block into registerBlocks/block.php.

In there we add a new JSXBlock import. If we want to use the dynamic php render, we must set the callback to true.

new JSXBlock("basetheme/job-list", false);

Global and private blocks

After we registered the block, we must decide if we want to use the block as a global block or private block.

To use the block as global we don’t have to do anything. The block is now available in the Gutenberg editor for all pages and posts.

If we want to use the block as a private block, we must import the block into the allowed blocks of a container or grid item and set the parent to the block inside the registerBlockType.

registerBlockType('basetheme/job-list', {
title: 'Job List',
icon: postAuthor,
category: 'components',
description: 'Job List Block to display open jobs',
keywords: '[]',
parent: ['basetheme/container', 'basetheme/grid-item'],
supports: {},
attributes: { ...defaultHeadingAttributes },
edit: EditComponent,
save: SaveComponent,
});

To use the block in blocks/layout/container/container.jsx or blocks/layout/grid/grid-item.jsx we must add the block into the ALLOWED_BLOCKS array.

const ALLOWED_BLOCKS = [
'basetheme/heading',
'basetheme/text',
'basetheme/button',
'basetheme/blog-post',
'basetheme/google-maps',
'basetheme/reference',
'basetheme/accordion-container',
'basetheme/test',
'basetheme/list',
'basetheme/job-list',
'contact-form-7/contact-form-selector',
'core/html',
];

After importing the basetheme/job-list, you must start the dev or build task to compile the new block and update the existing ones. Once the build has completed, the basetheme/job-list component can be used in the Gutenberg editor.

We see now following component in the backend and frontend.

Hello World

Build the Component

This is our example Component

Job Title

Date

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea

Apply Now

The Joblist Component should have following structure.

  • Title
  • Date
  • Description
  • Link to the Job

So we will start with the title. For the Title we will import from the utilties the heading component. You can have a look at the heading component here.

Import Heading Component

First we must import the Heading component.

import { Heading, defaultHeadingAttributes } from '@utilities/heading/heading';

Inside the registerBlockType we add the default attributes.

attributes: { ...defaultHeadingAttributes },

Inside our EditComponent function we add now the heading component.

<Heading
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={false}
enableLevelSelection={false}
className="fs-26 fw-bold"
/>

Now our component should look like this.

import { registerBlockType } from '@wordpress/blocks';
import { postAuthor } from '@wordpress/icons';
import { Heading, defaultHeadingAttributes } from '@utilities/heading/heading';
registerBlockType('basetheme/job-list', {
title: 'Job List',
icon: postAuthor,
category: 'components',
description: 'Job List Block to display open jobs',
keywords: '[]',
supports: {},
attributes: { ...defaultHeadingAttributes },
edit: EditComponent,
save: SaveComponent,
});
function EditComponent(props) {
const { attributes, setAttributes } = props;
return (
<div>
<Heading
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={false}
enableLevelSelection={false}
className="fs-26 fw-bold"
/>
</div>
);
}
function SaveComponent() {
return (
<div>
<h1>Hello World</h1>
</div>
);
}

Add starting Date.

For the Date we want to use not the core date picker. We want a string to add ab sofort or a specific date.

For this we want to add the core RichText to the component.

import { RichText } from '@wordpress/block-editor';

In the attributes we will add a new attribute called startingDate.

attributes: {
...defaultHeadingAttributes,
startingDate: {
type: 'string',
default: 'Ab Sofort',
},
},

And in our EditComponent function we will add the RichText component.

<RichText
tagName="div"
className="fs-14 fw-light"
value={attributes.startingDate}
onChange={(value) => setAttributes({ startingDate: value })}
/>

Now our component should look like this.

import { registerBlockType } from '@wordpress/blocks';
import { postAuthor } from '@wordpress/icons';
import { RichText } from '@wordpress/block-editor';
import { Heading, defaultHeadingAttributes } from '@utilities/heading/heading';
registerBlockType('basetheme/job-list', {
title: 'Job List',
icon: postAuthor,
category: 'components',
description: 'Job List Block to display open jobs',
keywords: '[]',
supports: {},
attributes: {
...defaultHeadingAttributes,
startingDate: {
type: 'string',
default: 'Ab Sofort',
},
},
edit: EditComponent,
save: SaveComponent,
});
function EditComponent(props) {
const { attributes, setAttributes } = props;
return (
<div>
<Heading
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={false}
enableLevelSelection={false}
className="fs-26 fw-bold"
/>
<RichText
tagName="div"
className="fs-14 fw-light"
value={attributes.startingDate}
onChange={(value) => setAttributes({ startingDate: value })}
/>
</div>
);
}
function SaveComponent() {
return (
<div>
<h1>Hello World</h1>
</div>
);
}

Import Text Component

For our Description we want to import our Text Component.

import { Text, defaultTextAttributes } from '@utilities/text/text';

Add the defaultTextAttributes to attributes.

attributes: {
...defaultHeadingAttributes,
startingDate: {
type: 'string',
default: 'Ab Sofort',
},
...defaultTextAttributes,
},

In the EditComponent we add now the Text Component.

<Text
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={true}
className="fs-16"
/>

Now our component should look like this.

import { registerBlockType } from '@wordpress/blocks';
import { postAuthor } from '@wordpress/icons';
import { RichText } from '@wordpress/block-editor';
import { Text, defaultTextAttributes } from '@utilities/text/text';
import { Heading, defaultHeadingAttributes } from '@utilities/heading/heading';
registerBlockType('basetheme/job-list', {
title: 'Job List',
icon: postAuthor,
category: 'components',
description: 'Job List Block to display open jobs',
keywords: '[]',
supports: {},
attributes: {
...defaultHeadingAttributes,
startingDate: {
type: 'string',
default: 'Ab Sofort',
},
...defaultTextAttributes,
},
edit: EditComponent,
save: SaveComponent,
});
function EditComponent(props) {
const { attributes, setAttributes } = props;
return (
<div>
<Heading
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={false}
enableLevelSelection={false}
className="fs-26 fw-bold"
/>
<RichText
tagName="div"
className="fs-14 fw-light"
value={attributes.startingDate}
onChange={(value) => setAttributes({ startingDate: value })}
/>
<Text
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={true}
className="fs-16"
/>
</div>
);
}
function SaveComponent() {
return (
<div>
<h1>Hello World</h1>
</div>
);
}

Import Button Component

Now we want to import our Button Component.

import { Button, defaultButtonAttributes } from '@utilities/button/button';

Add the defaultButtonAttributes to attributes

attributes: {
...defaultHeadingAttributes,
startingDate: {
type: 'string',
default: 'Ab Sofort',
},
...defaultTextAttributes,
...defaultButtonAttributes,
},

In the EditComponent we add now the Button Component.

<Button attributes={attributes} setAttributes={setAttributes} />

Our component should look like this.

import { registerBlockType } from '@wordpress/blocks';
import { postAuthor } from '@wordpress/icons';
import { RichText } from '@wordpress/block-editor';
import { Text, defaultTextAttributes } from '@utilities/text/text';
import { Heading, defaultHeadingAttributes } from '@utilities/heading/heading';
import { Button, defaultButtonAttributes } from '@utilities/button/button';
registerBlockType('basetheme/job-list', {
title: 'Job List',
icon: postAuthor,
category: 'components',
description: 'Job List Block to display open jobs',
keywords: '[]',
supports: {},
attributes: {
...defaultHeadingAttributes,
startingDate: {
type: 'string',
default: 'Ab Sofort',
},
...defaultTextAttributes,
...defaultButtonAttributes,
},
edit: EditComponent,
save: SaveComponent,
});
function EditComponent(props) {
const { attributes, setAttributes } = props;
return (
<div>
<Heading
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={false}
enableLevelSelection={false}
className="fs-26 fw-bold"
/>
<RichText
tagName="div"
className="fs-14 fw-light"
value={attributes.startingDate}
onChange={(value) => setAttributes({ startingDate: value })}
/>
<Text
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={true}
className="fs-16"
/>
<Button attributes={attributes} setAttributes={setAttributes} />
</div>
);
}
function SaveComponent() {
return (
<div>
<h1>Hello World</h1>
</div>
);
}

Now we have finished building the Job List Block for the backend. We will continue to build now the frontend rendering with dynamic PHP rendering.

Dynamic PHP Rendering

To enable dynamic PHP rendering, we must set the second parameter in the JSXBlock import to true. And add inside the job-list folder a new file called job-list.php

new JSXBlock("job-list", true);

To get more inside for dynamic php rendering you can read this documentation and this blogpost.


For the frontend rendering we can remove the save function and we must return null.

edit: EditComponent,
save: () => null,

Our component should look like this.

import { registerBlockType } from '@wordpress/blocks';
import { postAuthor } from '@wordpress/icons';
import { RichText } from '@wordpress/block-editor';
import { Text, defaultTextAttributes } from '@utilities/text/text';
import { Heading, defaultHeadingAttributes } from '@utilities/heading/heading';
import { Button, defaultButtonAttributes } from '@utilities/button/button';
registerBlockType('basetheme/job-list', {
title: 'Job List',
icon: postAuthor,
category: 'components',
description: 'Job List Block to display open jobs',
keywords: '[]',
supports: {},
attributes: {
...defaultHeadingAttributes,
startingDate: {
type: 'string',
default: 'Ab Sofort',
},
...defaultTextAttributes,
...defaultButtonAttributes,
},
edit: EditComponent,
save: () => null,
});
function EditComponent(props) {
const { attributes, setAttributes } = props;
return (
<div>
<Heading
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={false}
enableLevelSelection={false}
className="fs-26 fw-bold"
/>
<RichText
tagName="div"
className="fs-14 fw-light"
value={attributes.startingDate}
onChange={(value) => setAttributes({ startingDate: value })}
/>
<Text
attributes={attributes}
setAttributes={setAttributes}
enableAlignment={true}
className="fs-16"
/>
<Button attributes={attributes} setAttributes={setAttributes} />
</div>
);
}

Now we can start to build our dynamic php component.

Import Heading Component

Because we use the Heading utility we also have a Heading component available for our PHP file. So we can start to build our job-list.php file with the Heading component.

<?php
use basetheme\Utilities\Heading_Utils;
Heading_Utils::init_heading($attributes);
?>
<div>
<?php echo Heading_Utils::render_heading($attributes["heading"], $attributes, "fs-26 fw-bold"); ?>
</div>

We deactivate the Level Selection, so we can set a fixed h2 or h3 tag for the heading.

$attributes["tag"] = "h2";

Our php rendering should look like this.

<?php
use basetheme\Utilities\Heading_Utils;
$attributes["tag"] = "h2";
Heading_Utils::init_heading($attributes);
?>
<div>
<?php echo Heading_Utils::render_heading($attributes["heading"], $attributes, "fs-26 fw-bold"); ?>
</div>

Rendering Starting Date

Now we want to add our starting Date string. First we must check if the startingDate attribute is set. If is not set we must set a default value.

if (!isset($attributes["startingDate"])) {
$attributes["startingDate"] = "Ab Sofort";
}

And to display the starting date we can use following code.

<div class="fs-14 fw-light"><?php echo esc_html($attributes["startingDate"]); ?></div>

Our php rendering should look like this.

<?php
use basetheme\Utilities\Heading_Utils;
$attributes["tag"] = "h2";
Heading_Utils::init_heading($attributes);
if (!isset($attributes["startingDate"])) {
$attributes["startingDate"] = "Ab Sofort";
}
?>
<div>
<?php echo Heading_Utils::render_heading($attributes["heading"], $attributes, "fs-26 fw-bold"); ?>
<div class="fs-14 fw-light"><?php echo esc_html($attributes["startingDate"]); ?></div>
</div>

Import Text Component

For the job description, we use the utility Text Component.

use basetheme\Utilities\Text_Utils;
if (!isset($attributes["text"])) {
$attributes["text"] = "";
}
<?php echo Text_Utils::render_text($attributes["text"], $attributes, "fs-16"); ?>

Our php rendering should look like this.

<?php
use basetheme\Utilities\Heading_Utils;
use basetheme\Utilities\Text_Utils;
$attributes["tag"] = "h2";
Heading_Utils::init_heading($attributes);
if (!isset($attributes["startingDate"])) {
$attributes["startingDate"] = "Ab Sofort";
}
if (!isset($attributes["text"])) {
$attributes["text"] = "";
}
?>
<div>
<?php echo Heading_Utils::render_heading($attributes["heading"], $attributes, "fs-26 fw-bold"); ?>
<div class="fs-14 fw-light"><?php echo esc_html($attributes["startingDate"]); ?></div>
<?php echo Text_Utils::render_text($attributes["text"], $attributes, "fs-16"); ?>
</div>

Add Button Component

Use the Button Component utility to handle links.

<?php
use basetheme\Utilities\Button_Utils;
Button_Utils::init_button($attributes);
?>
<?php Button_Utils::render_button($attributes); ?>

Our php rendering should look like this.

<?php
use basetheme\Utilities\Heading_Utils;
use basetheme\Utilities\Text_Utils;
use basetheme\Utilities\Button_Utils;
$attributes["tag"] = "h2";
Heading_Utils::init_heading($attributes);
if (!isset($attributes["startingDate"])) {
$attributes["startingDate"] = "Ab Sofort";
}
if (!isset($attributes["text"])) {
$attributes["text"] = "";
}
Button_Utils::init_button($attributes);
?>
<div>
<?php echo Heading_Utils::render_heading($attributes["heading"], $attributes, "fs-26 fw-bold"); ?>
<div class="fs-14 fw-light"><?php echo esc_html($attributes["startingDate"]); ?></div>
<?php echo Text_Utils::render_text($attributes["text"], $attributes, "fs-16"); ?>
<?php Button_Utils::render_button($attributes); ?>
</div>

Now we finished with our first component.

If you want to know how to render a child element inside a Component. Please visit following components