Skip to content

Instantly share code, notes, and snippets.

@vanpariyar
Last active January 21, 2022 12:00
Show Gist options
  • Save vanpariyar/2221450ff22495b06622b515515209a2 to your computer and use it in GitHub Desktop.
Save vanpariyar/2221450ff22495b06622b515515209a2 to your computer and use it in GitHub Desktop.
Create sidebar for the custom tag and post type selection on WordPress editor formally Gutenberg with Dynamic block
{
"apiVersion": 2,
"name": "demo/content-with-sidebar",
"version": "0.1.0",
"title": "Content With Sidebar Block",
"category": "demo",
"attributes": {
"mediaURL": {
"type": "string",
"default": ""
},
"mediaAlt": {
"type": "string",
"default": ""
},
"technologies": {
"type": "object",
"default": {}
},
"services": {
"type": "object",
"default": {}
},
"serviceHeadingTag": {
"type":"string",
"default": "h3"
},
"serviceHeading": {
"type":"string",
"default": "Services Provided"
},
"technologiesHeadingTag": {
"type":"string",
"default": "h3"
},
"technologiesHeading": {
"type":"string",
"default": "Technologies Used"
},
"tagText": {
"type":"string",
"default": "Tags"
},
"shareText": {
"type":"string",
"default": "Share this case study"
},
"title":{
"type":"string",
"default": ""
},
"link":{
"type":"string",
"default": ""
},
"excerpt":{
"type":"string",
"default": ""
},
"tags":{
"type":"array",
"default": []
}
},
"description": "This Block can be used in the Case study and Project details page",
"supports": {
"html": false,
"align": ["full"]
},
"textdomain": "realmdigital",
"editorScript": "file:index.js",
"editorStyle": "file:index.css"
}
/**
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-i18n/
*/
import { __ } from '@wordpress/i18n'
import { Button, CheckboxControl, PanelBody, PanelRow, RadioControl, Spinner, TextControl } from '@wordpress/components'
import { useSelect, select } from '@wordpress/data'
import { useState, useEffect } from '@wordpress/element'
export const TechImage = ({ mediaId }) => {
const post = useSelect(
select => {
let query = {
include: [mediaId],
}
const selectedTechnologies = select('core').getMedia(mediaId) || []
return selectedTechnologies
},
[mediaId],
)
return <img src={post.source_url} alt={post.alt_text} />
}
export const ServicesDisplay = ({ props }) => {
const {
attributes: { services },
setAttributes,
} = props
const posts = useSelect(
select => {
let query = {
include: Object.keys(services),
}
const selectedServices = select('core').getEntityRecords('postType', 'service', query) || []
return selectedServices
},
[services],
)
return (
<ul className="related-article-list">
{posts &&
posts.map((post, key) => {
return (
<li key={key}>
<a href={post.link} title={post.title.rendered}>
{post.title.rendered}
</a>
</li>
)
})}
</ul>
)
}
export const TagDisplay = ({ tag }) => {
const tagObject = useSelect(select => {
const selectedTags = select('core').getEntityRecord('taxonomy', 'post_tag', tag) || []
return selectedTags
}, [])
return (
<>
{tagObject && (
<li>
<a href={tagObject.link} title={tagObject.name}>
{tagObject.name}
</a>
</li>
)}
</>
)
}
export const TechnologyDisplay = ({ props }) => {
const {
attributes: { technologies },
setAttributes,
} = props
const posts = useSelect(
select => {
let query = {
include: Object.keys(technologies),
}
const selectedTechnologies = select('core').getEntityRecords('postType', 'technology', query) || []
return selectedTechnologies
},
[technologies],
)
return (
<ul>
{posts &&
posts.map((post, key) => {
return (
<li key={key}>
<a href={post.link} title={post.title.rendered}>
<TechImage mediaId={post.featured_media} />
</a>
</li>
)
})}
</ul>
)
}
export const ServicesSelector = ({ props }) => {
const {
attributes: { services },
setAttributes,
} = props
const [searchTerm, setSearchTerm] = useState('')
const [checkedObj, setCheckedObj] = useState(services)
const options = useSelect(
select => {
let dynamicOptions = []
let query = {
per_page: 10, // set -1 to display ALL
search: searchTerm,
}
const posts = select('core').getEntityRecords('postType', 'service', query) || []
if (posts) {
dynamicOptions = posts.map((post, key) => {
return {
id: post.id,
label: post.title.rendered,
value: post.slug,
}
})
}
return dynamicOptions
},
[searchTerm, services],
)
return (
<>
<TextControl
label={__('Type to filter Services')}
help={__('Suggestions will show below')}
value={searchTerm}
placeholder={__('Type Your Keyword')}
onChange={setSearchTerm}
/>
{options.length ? (
options.map((v, key) => (
<CheckboxControl
key={key}
className="check_items"
label={v.value}
checked={checkedObj[v.id] == null ? '' : checkedObj[v.id]}
onChange={check => {
let tempCheckedObject = { ...checkedObj }
check ? (tempCheckedObject[v.id] = true) : delete tempCheckedObject[v.id]
setAttributes({ services: { ...tempCheckedObject } })
setCheckedObj(tempCheckedObject)
}}
/>
))
) : (
<div>
<Spinner /> No Result Found
</div>
)}
{<hr />}
</>
)
}
export const TechnologySelector = ({ props }) => {
const {
attributes: { technologies },
setAttributes,
} = props
const [searchTerm, setSearchTerm] = useState('')
const [checkedObj, setCheckedObj] = useState(technologies)
const options = useSelect(
select => {
let dynamicOptions = []
let query = {
per_page: 10, // set -1 to display ALL
search: searchTerm,
}
const posts = select('core').getEntityRecords('postType', 'technology', query) || []
if (posts) {
dynamicOptions = posts.map((post, key) => {
return {
id: post.id,
label: post.title.rendered,
value: post.slug,
}
})
}
return dynamicOptions
},
[searchTerm, technologies],
)
return (
<>
<TextControl
label={__('Type to Filter Technologies')}
help={__('Suggestions will show below')}
value={searchTerm}
placeholder={__('Type Your Keyword')}
onChange={setSearchTerm}
/>
{options.length ? (
options.map((v, key) => (
<CheckboxControl
key={key}
className="check_items"
label={v.value}
checked={checkedObj[v.id] == null ? '' : checkedObj[v.id]}
onChange={check => {
let tempCheckedObject = { ...checkedObj }
check ? (tempCheckedObject[v.id] = true) : delete tempCheckedObject[v.id]
setAttributes({ technologies: { ...tempCheckedObject } })
setCheckedObj(tempCheckedObject)
}}
/>
))
) : (
<div>
<Spinner /> No Result Found
</div>
)}
{<hr />}
</>
)
}
<?php
add_filter('register_block_type_args', function ($settings, $name) {
if ($name == 'demo/content-with-sidebar') {
$settings['render_callback'] = 'demo_blocks_content_with_sidebar';
}
return $settings;
}, null, 2);
function demo_blocks_content_with_sidebar($block_attributes, $content)
{
/**
* Getting author ID for the post
*/
global $post;
$author_id = $post->post_author;
$related_articles_count = 3;
ob_start();
?>
<section class="article-detail-section case-study-detail-section">
<div class="container">
<div class="article-wrapper">
<div class="article-left-block cms-content">
<div class="content-block">
<?php echo $content;?>
</div>
</div>
<div class="article-right-block">
<div class="right-block-wrapper">
<div class="article-right-inner">
<div class="share-block">
<p><?php echo $block_attributes['shareText'];?></p>
<ul class="social-share">
<li>
<a target="_blank" href="https://facebook.com/sharer/sharer.php?u=<?php echo urlencode(get_the_permalink()); ?>" target="_blank" rel="noopener" aria-label="Share on Facebook"><img src="<?php echo get_template_directory_uri(); ?>/public/images/facebook.svg" alt="Facebook-logo" /></a>
</li>
<li>
<a target="_blank" href="https://twitter.com/intent/tweet/?text=<?php echo urlencode(get_the_title()); ?>&amp;url=<?php echo urlencode(get_the_permalink()); ?>" target="_blank" rel="noopener" aria-label="Share on Twitter"><img src="<?php echo get_template_directory_uri(); ?>/public/images/twitter.svg" alt="Twitter-logo" /></a>
</li>
<li>
<a target="_blank" href="https://www.linkedin.com/shareArticle?mini=true&amp;url=<?php echo urlencode(get_the_permalink()); ?>&amp;title=<?php echo get_the_title(); ?>.&amp;summary=<?php echo urlencode(get_the_excerpt()); ?>&amp;source=<?php echo urlencode(get_the_permalink()); ?>" target="_blank" rel="noopener" aria-label="Share on LinkedIn"><img src="<?php echo get_template_directory_uri(); ?>/public/images/linkedin.svg" alt="Linekdin-logo" /></a>
</li>
</ul>
</div>
<div class="related-article-block services-block">
<h3><?php echo $block_attributes['serviceHeading'];?></h3>
<?php if (isset($block_attributes['technologiesHeading'])) :?>
<ul class="related-article-list">
<?php foreach ($block_attributes['services'] as $service => $value) :?>
<li>
<a href="<?php the_permalink($service);?>" title="<?php echo get_the_title($service)?>"><?php echo get_the_title($service)?></a>
<?php endforeach;?>
</ul>
<?php endif;?>
</div>
<div class="technology-block">
<h3><?php echo $block_attributes['technologiesHeading'];?></h3>
<?php if (isset($block_attributes['technologiesHeading'])) :?>
<ul>
<?php foreach ($block_attributes['technologies'] as $technology => $value) :?>
<li>
<a href="<?php the_permalink($technology);?>" title="<?php echo get_the_title($technology)?>"><img src="<?php echo get_the_post_thumbnail_url($technology)?>" alt="<?php echo get_the_title($technology)?>" /></a>
</li>
<?php endforeach;?>
</ul>
<?php endif;?>
</div>
<div class="article-tag-block">
<h3><?php echo $block_attributes['tagText'];?></h3>
<?php
$post_tags = get_the_terms($post, 'post_tag');
if ($post_tags && !is_wp_error($post_tags)) : ?>
<ul class="article-tag-list">
<?php foreach ($post_tags as $tag) : ?>
<li><a href="<?php echo get_tag_link($tag->term_id) ?>" title="<?php echo $tag->name?>"><?php echo $tag->name?></a></li>
<?php endforeach ?>
</ul>
<?php endif?>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<?php
$return_html = ob_get_clean();
return $return_html;
}
/**
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-i18n/
*/
import { __ } from '@wordpress/i18n'
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-block-editor/#useBlockProps
*/
import { InnerBlocks, InspectorControls, RichText, useBlockProps } from '@wordpress/block-editor'
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* Those files can contain any CSS code that gets applied to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './editor.scss'
import { Button, CheckboxControl, PanelBody, PanelRow, RadioControl, Spinner, TextControl } from '@wordpress/components'
import { useSelect, select } from '@wordpress/data'
import { useState, useEffect } from '@wordpress/element'
import Heading from '../components/Heading'
import { ServicesSelector, TechnologySelector, TagDisplay, ServicesDisplay, TechnologyDisplay } from './components'
/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#edit
*
* @return {WPElement} Element to render.
*/
const InspectorControlPanel = ({ props }) => {
return (
<PanelBody title={__('Control Panel ⚙️')} initialOpen={true}>
<PanelRow className="realm-selector-list d-block">
<ServicesSelector props={props} />
</PanelRow>
<PanelRow className="realm-selector-list d-block">
<TechnologySelector props={props} />
</PanelRow>
</PanelBody>
)
}
export default function Edit(props) {
const blockProps = useBlockProps({
className: 'article-detail-section case-study-detail-section',
})
const {
attributes: { technologies, services, shareText, tagText, technologiesHeading, serviceHeading },
setAttributes,
} = props
const title = select('core/editor').getEditedPostAttribute('title') || ''
const link = select('core/editor').getEditedPostAttribute('link') || ''
const excerpt = select('core/editor').getEditedPostAttribute('excerpt') || ''
const tags = select('core/editor').getEditedPostAttribute('tags') || ''
return (
<>
<InspectorControls>
<InspectorControlPanel props={props} />
</InspectorControls>
<section {...blockProps}>
<div className="container">
<div className="article-wrapper">
<div className="article-left-block cms-content">
<InnerBlocks />
</div>
<div className="article-right-block">
<div className="right-block-wrapper">
<div className="article-right-inner">
<div className="share-block">
<RichText
tagName="p"
value={shareText}
allowedFormats={['core/bold', 'core/italic']}
onChange={shareText => setAttributes({ shareText })}
placeholder={__('Heading...')}
/>
<ul className="social-share">
<li>
<a
target="_blank"
href={`https://facebook.com/sharer/sharer.php?u=${encodeURIComponent(
link,
)}`}
target="_blank"
rel="noopener"
aria-label="Share on Facebook"
>
<img
src="../../app/themes/realmdigital/public/images/facebook.svg"
alt="Facebook-logo"
/>
</a>
</li>
<li>
<a
target="_blank"
href={`https://twitter.com/intent/tweet/?text=${encodeURIComponent(
title,
)}&amp;url=${encodeURIComponent(link)}`}
target="_blank"
rel="noopener"
aria-label="Share on Twitter"
>
<img
src="../../app/themes/realmdigital/public/images/twitter.svg"
alt="Twitter-logo"
/>
</a>
</li>
<li>
<a
target="_blank"
href={`https://www.linkedin.com/shareArticle?mini=true&amp;url=${encodeURI(
link,
)}&amp;title=${encodeURIComponent(
title,
)}.&amp;summary=${encodeURIComponent(
excerpt,
)}&amp;source=${encodeURIComponent(link)}`}
target="_blank"
rel="noopener"
aria-label="Share on LinkedIn"
>
<img
src="../../app/themes/realmdigital/public/images/linkedin.svg"
alt="Linekdin-logo"
/>
</a>
</li>
</ul>
</div>
<div className="related-article-block services-block">
<RichText
tagName="h3"
value={serviceHeading}
allowedFormats={['core/bold', 'core/italic']}
onChange={serviceHeading => setAttributes({ serviceHeading })}
placeholder={__('Heading...')}
/>
<ServicesDisplay props={props} />
</div>
<div className="technology-block">
<RichText
tagName="h3"
value={technologiesHeading}
allowedFormats={['core/bold', 'core/italic']}
onChange={technologiesHeading => setAttributes({ technologiesHeading })}
placeholder={__('Heading...')}
/>
<TechnologyDisplay props={props} />
</div>
{tags.length ? (
<div className="article-tag-block">
<RichText
tagName="h3"
value={technologiesHeading}
allowedFormats={['core/bold', 'core/italic']}
onChange={technologiesHeading => setAttributes({ technologiesHeading })}
placeholder={__('Heading...')}
/>
<ul className="article-tag-list">
{tags.map((tag, key) => {
return <TagDisplay tag={tag} key={key} />
})}
</ul>
</div>
) : (
''
)}
</div>
</div>
</div>
</div>
</div>
</section>
</>
)
}
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/
.wp-block-demo-content-with-sidebar .realm-selector-list {
display: block;
}
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks'
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss'
/**
* Internal dependencies
*/
import Edit from './edit'
import save from './save'
import icons from '../components/icons'
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType('demo/content-with-sidebar', {
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
icon: icons.realmdigitalLogo,
})
/**
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-i18n/
*/
import { __ } from '@wordpress/i18n'
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-block-editor/#useBlockProps
*/
import { InnerBlocks } from '@wordpress/block-editor'
/**
* The save function defines the way in which the different attributes should
* be combined into the final markup, which is then serialized by the block
* editor into `post_content`.
*
* @see https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#save
*
* @return {WPElement} Element to render.
*/
export default function save(props) {
return <InnerBlocks.Content />
}
/**
* The following styles get applied both on the front of your site
* and in the editor.
*
* Replace them with your own styles or remove the file completely.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment