Im trying to create a Gutenberg dynamic block with dropdown list. I have completed block creation and rendering the block with selected dropdown value in the frontend.
How to set the dropdown selected with previous value when editing a post?
I have tried to access attribute value using props.attributes , but getting undefined
block.js
const { __ } = wp.i18n;
const { registerBlockType, RichText } = wp.blocks;
registerBlockType( 'gut/new-block', {
title: __( 'new-block - Test' ),
category: 'common',
attributes: {
category_id: {
type: 'number'
}
},
edit: function( props ) {
const { attributes: { category_id }, setAttributes } = props;
function setCategory( event ) {
const selected = event.target.querySelector( 'option:checked' );
setAttributes( { category_id: selected.value } );
event.preventDefault();
}
return (
<div className={ props.className }>
<select value={ category_id } onChange={ setCategory }>
<option value="120">Animals</option>
<option value="350">Architecture</option>
<option value="700">Nature</option>
<option value="800">People</option>
<option value="432">Tech</option>
</select>
</div>
);
},
save ( props ) {
return null
},
});
php
function gut_my_new_block() {
wp_register_script(
'gut-my-new-block',
plugins_url( 'new-block/dist/blocks.build.js', __FILE__ ),
array( 'wp-blocks', 'wp-element' )
);
register_block_type( 'gut/new-block', array(
'render_callback' => 'gut_render_block_my_newblock',
'editor_script' => 'gut-my-new-block',
) );
}
add_action( 'init', 'gut_my_new_block' );
function gut_render_block_my_newblock($params) {
return '<h3>selected category '.$params['category_id'].'</h3>';
}
Select values are saved as strings, so if you change the type to "string" it will work. Or you could parseInt() or Number() the value before saving and then toString() it back when pulling the value.
Related
I have created a rather complex Gutenebrg Block
I have hardcoded the Post / Project IDs and I am now struggling how to implement the update function. I use two different API Routes and want to give the user the possibilty to change the Block Content via typing in the ID in a field.
Passing an attribute into :
withSelect(select => {
return {
posts: select('core').getEntityRecords('/wp/v2', 'projects', {include: 2962}),
posts1: select('core').getEntityRecords('/wp/v2', 'posts', {include: 3432})
};
})
Most of the code below… It was rather tricky for me as a Gutenberg rookie...
/**
* Block dependencies
*/
import './style.scss';
/**
* Internal block libraries
*/
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { Spinner } = wp.components;
const { withSelect, useSelect } = wp.data;
const {
InspectorControls,
RichText,
MediaUpload,
URLInputButton
} = wp.blockEditor;
var dispatch = wp.data.dispatch;
dispatch( 'core' ).addEntities( [
{
name: 'projects', // route name
kind: '/wp/v2', // namespace
baseURL: '/wp/v2/projects/' // API path without /wp-json
},
{
name: 'posts', // route name
kind: '/wp/v2', // namespace
baseURL: '/wp/v2/posts/' // API path without /wp-json
}
]);
registerBlockType(
'jsforwpblocks/dynamic',
{
title: __( 'Example - Dynamic Block', 'jsforwpblocks'),
description: __( 'A look at how to build a basic dynamic block.', 'jsforwpblocks'),
icon:'shield',
category: 'widgets',
attributes: {
projektID: {
type: 'string',
},
},
edit:
withSelect( select => {
return {
posts: select( 'core' ).getEntityRecords( '/wp/v2', 'projects',{include: 2962}),
posts1: select( 'core' ).getEntityRecords( '/wp/v2', 'posts',{include: 3432})
};
} )
( ( { props, posts, posts1, className, isSelected, setAttributes,attributes } ) => {
if ( ! posts ) {
return (
<p className={className} >
<Spinner />
{ __( 'Loading Posts', 'jsforwpblocks' ) }
</p>
);
}
if ( 0 === posts.length ) {
return <p>{ __( 'No Posts', 'jsforwpblocks' ) }</p>;
}
function changeprojektid(projektID) {
// using some nice js features instead of typing
// { heading: heading }
setAttributes({ projektID });
withSelect( select => {
let query = 'include: 2962'
return {
posts: select( 'core' ).getEntityRecords( '/wp/v2', 'projects', {include: 2962})
};
} )
}
return (
<div>
<div className="copy">
<RichText
className="heading"
tagName="h2"
placeholder="Enter your ID"
value={attributes.projektID}
onChange={changeprojektid}
/>
</div>
<ul className={ className }>
{ posts.map( post => {
return (
<li>
<a className={ className } href={ post.link }>
{ post.title.rendered }
<img src={ post.projimage1.guid } />
</a>
</li>
);
}) }
</ul>
<ul className={ className }>
{ posts1.map( post => {
return (
<li>
<a className={ className } href={ post.link }>
{ post.title.rendered }
</a>
</li>
);
}) }
</ul>
</div>
);
} )
// end withAPIData
, // end edit
I try to add two new panels to the existing gutenberg document sidebar. One should contain a radio-button menu to set the height of the header image, and the other one a text-field to enter a subtitle for the page.
But because I do not want to use the outdated meta boxes technologie, there aren't hardly any tutorials how to accomplish this. I only found the following piece of code, but I have no idea how to shape it to my needs and where to put it ;) - My knowledge of coding is just not good enough, but I still need to implement this feature in my theme.
const { registerPlugin } = wp.plugins
const { PluginDocumentSettingPanel } = wp.editPost
const PluginDocumentSettingPanelDemo = () => (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
Custom Panel Contents
</PluginDocumentSettingPanel>
)
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})
Do you maybe have a guess how to achieve my idea? Thanks for you support, and greetings from Austria! Samuel
First of all, register the meta fields, so you have where to save the values. This goes in your plugin file or functions.php.
register_post_meta('post', 'customname_meta_subtitle', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true
));
register_post_meta('post', 'customname_meta_header_height', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true
));
You can check the documentation. We are telling WordPress to create 2 new post meta fields, with keys customname_meta_subtitle and customname_meta_header_height, which we will use in the Gutenberg part.
For the ES code, you will need the following:
const { registerPlugin } = wp.plugins
const { PluginDocumentSettingPanel } = wp.editPost
const { RadioControl, TextControl } = wp.components
const { withState } = wp.compose
const { withSelect, withDispatch } = wp.data
let SubtitleControl = ({ subtitle, handleSubtitleChange }) => (
<TextControl
label="Set subtitle"
value={subtitle}
onChange={subtitle => handleSubtitleChange(subtitle)}
/>
);
SubtitleControl = withSelect(
(select) => {
return {
subtitle: select('core/editor').getEditedPostAttribute('meta')['customname_meta_subtitle']
}
}
)(SubtitleControl);
SubtitleControl = withDispatch(
(dispatch) => {
return {
handleSubtitleChange: (value) => {
dispatch('core/editor').editPost({ meta: { customname_meta_subtitle: value } })
}
}
}
)(SubtitleControl);
let HeaderImageHeightControl = ({ height, handleHeightChange }) => (
<RadioControl
label="Set image height"
help="Set the height of the header image"
selected={height}
options={[
{ label: '100', value: '1' },
{ label: '200', value: '2' },
]}
onChange={handleHeightChange}
/>
);
HeaderImageHeightControl = withSelect(
(select) => {
return {
height: select('core/editor').getEditedPostAttribute('meta')['customname_meta_header_height']
}
}
)(HeaderImageHeightControl);
HeaderImageHeightControl = withDispatch(
(dispatch) => {
return {
handleHeightChange: value => {
dispatch('core/editor').editPost({ meta: { customname_meta_header_height: value } })
}
}
}
)(HeaderImageHeightControl);
const PluginDocumentSettingPanelDemo = () => (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
<SubtitleControl />
<HeaderImageHeightControl />
</PluginDocumentSettingPanel>
)
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})
Most of this code is described in the official WP tutorial, but feel free to ask if anything is unclear.
Finally, to use the new values, you can do something like this:
<h1><?php echo get_post_meta(get_the_ID(), 'customname_meta_subtitle')[0]; ?></h1>
<h1><?php echo get_post_meta(get_the_ID(), 'customname_meta_header_height')[0]; ?></h1>
This is to be used in the post template file, for the front-end visualization of the meta field info.
I hope this helps!
I need to create a wordpress Gutenberg block that will allow me to insert some data as name and surname, company name, the best sentence from the references.
So far I managed to create a Gutenberg block that is saving one text field.
dc-references-block.php
// register custom meta tag field
function dcr_register_post_meta() {
register_post_meta( 'page', 'dc_references_block_field', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
}
add_action( 'init', 'dcr_register_post_meta' );
function dcr_enqueue() {
wp_enqueue_script(
'dc-references-block-script',
plugins_url( 'dc-references-block.js', __FILE__ ),
array( 'wp-blocks', 'wp-element', 'wp-components' )
);
}
add_action( 'enqueue_block_editor_assets', 'dcr_enqueue' );
dc-references-block.js
( function( wp ) {
var el = wp.element.createElement;
var registerBlockType = wp.blocks.registerBlockType;
var TextControl = wp.components.TextControl;
registerBlockType( 'dc-references-block/dc-references-block', {
title: 'Title',
icon: 'edit',
category: 'common',
attributes: {
blockValue: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field'
}
},
edit: function( props ) {
var className = props.className;
var setAttributes = props.setAttributes;
function updateBlockValue( blockValue ) {
setAttributes({ blockValue });
}
return el(
'div',
{ className: className },
el( TextControl, {
label: 'write here name of company',
value: props.attributes.blockValue,
onChange: updateBlockValue
}
)
);
},
save: function() {
return null;
}
} );
} )( window.wp );
Whenever I try to add a second text field or textarea to the block I get an error "site does not support this block".
Could anyone explain to me how to, in this situation, add correctly more then one text field and textarea to a block?
It would be better if you included the code that did not work. In any case, I changed your code by adding another text input and a textarea (with relevant entries in attributes and meta).
Here is the modified code. Also, I have changed some of the code to be more readable.
Javascript
( function( wp ) {
const el = wp.element.createElement;
const registerBlockType = wp.blocks.registerBlockType;
const TextControl = wp.components.TextControl;
const TextareaControl = wp.components.TextareaControl;
registerBlockType( 'dc-references-block/dc-references-block', {
title: 'Title',
icon: 'edit',
category: 'common',
attributes: {
blockValue: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field'
},
// Add two new attributes
name: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field_name'
},
desc: {
type: 'string',
source: 'meta',
meta: 'dc_references_block_field_desc'
}
},
edit: function( props ) {
const className = props.className;
const setAttributes = props.setAttributes;
// Original element with onChange event as an anonymous function
const text = el( TextControl, {
label: 'write here name of company',
value: props.attributes.blockValue,
key: 'companyName',
onChange: function( value ) {
setAttributes( { name: value } );
}
} );
//Add two new elements
const secondText = el( TextControl, {
label: 'Write your name',
value: props.attributes.name,
key: 'username',
onChange: function( value ) {
setAttributes( { name: value } );
}
} );
const textArea = el( TextareaControl, {
label: 'Write a description',
value: props.attributes.desc,
key: 'desc',
onChange: function( value ) {
setAttributes( { desc: value } );
}
} );
return el(
'div',
{ className: className },
// Children of the main div as an array
[ text, secondText, textArea ]
);
},
save: function() {
return null;
}
} );
}( window.wp ) );
PHP
register_post_meta( 'page', 'dc_references_block_field', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
// register two new meta corresponding to attributes in JS
register_post_meta( 'page', 'dc_references_block_field_name', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
register_post_meta( 'page', 'dc_references_block_field_desc', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
) );
I want to create a block with editable fields, but I can't find out why I keep getting this error: 'Your site doesn't include support for the block. You can leave this block intact, convert its content to a Custom HTML block, or remove it entirely'. Does anyone know what might be producing such an error? Am I doing something wrong?
PHP code:
function protex_contact_gutenberg_block_enqueue_scripts(){
$required_js_files = array(
'wp-blocks',
'wp-i18n',
'wp-element',
'wp-editor'
);
wp_enqueue_script( 'react', 'https://unpkg.com/react#16/umd/react.development.js', $required_js_files );
$required_js_files[] = 'react';
wp_enqueue_script( 'react-dom', 'https://unpkg.com/react-dom#16/umd/react-dom.development.js', $required_js_files );
wp_enqueue_script( 'babel', 'https://unpkg.com/babel-standalone#6/babel.min.js', $required_js_files );
$required_js_files[] = 'babel';
wp_register_script( 'protex_contact_gutenberg_block_gutenberg_js', plugin_dir_url( __FILE__ ) . 'assets/prtx_contact.js', $required_js_files );
register_block_type('protex-contact/block', array(
'editor_script' => 'protex_contact_gutenberg_block_gutenberg_js',
'editor_script' => 'babel',
'editor_script' => 'react',
'editor_script' => 'react-dom',
));
}
add_action( 'init', 'protex_contact_gutenberg_block_enqueue_scripts' );
function protex_contact_gutenberg_block_gutenberg_modify_jsx_tag( $tag, $handle, $src ) {
if ( 'my_custom_gutenberg_block_gutenberg_js' == $handle ) {
$tag = str_replace( "<script type='text/javascript'", "<script type='text/babel'", $tag );
}
return $tag;
}
add_filter( 'script_loader_tag', 'protex_contact_gutenberg_block_gutenberg_modify_jsx_tag', 10, 3 );
JS code:
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { RichText } = wp.editor;
registerBlockType( 'protex-contact/block', {
title: __( 'Protex konakt', 'protex-contact' ),
icon: 'id',
category: 'common',
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'p',
},
},
edit({ attributes, className, setAttributes }) {
const { content } = attributes;
function onChangeContent( newContent ) {
setAttributes( { content: newContent } );
}
return (
<div className={ className }>
<RichText
tagName="p"
className="prtx_contact_input"
value={ content }
onChange={ onChangeContent } />
</div>
);
},
save({ attributes }) {
let { content } = attributes;
return (
<RichText.Content
tagName="p"
value={ content }
/>
);
},
} );
Check your path when registering this script:
wp_register_script( 'protex_contact_gutenberg_block_gutenberg_js', plugin_dir_url( __FILE__ ) . 'assets/prtx_contact.js', $required_js_files );
If you are calling plugin_dir_url( __FILE__ ) from a subdirectory, then the url will include that subdirectory. For example, if I call plugin_dir_url( __FILE__ ) from a file in the directory path 'plugins/my-custom-plugin/library', the url will end with '/my-custom-plugin/library/' which may not be the path you want.
If calling from a subdirectory, I would use
wp_register_script( 'protex_contact_gutenberg_block_gutenberg_js', plugins_url( 'assets/prtx_contact.js', dirname( __FILE__ ) ), $required_js_files );
If calling from many levels deep, then you may need to addjust dirname( __FILE__ ) to something like dirname( __FILE__ , 2 ) to traverse back up however far you need to go (or consider passing in the path to the "assets" folder so you don't have to calculate it on the fly).
I had a similar issue as you, and the problem was that the script was not being loaded due to an incorrect path. Outside of that, given the number of script dependencies you are registering, I would check that all the other scripts are being loaded correctly and not creating any issues.
I want to add a new button with popup to TinyMCE. But i never see the button. I probably are doing wrong this modification. How to insert the new button on that TinyMCE Code?
I have this TinyMCE Code for showing in Wordpress Front-End:
$qt = '';
if( $this->options[ 'wpcc_edit_in_html' ] ) $qt = array( 'buttons' => 'strong,em,block,del,ul,ol,li,spell,close' );
else {
$qt = FALSE;
add_filter( 'wp_default_editor', create_function( '', 'return "tinymce";' ) ); // force visual editor
}
$editor_settings = array(
'theme_advanced_blockformats' => array( 'h2','h3','p' ),
'wpautop' => true,
'media_buttons' => false,
'tinymce' => array(
'theme_advanced_buttons1' => 'bold,italic,blockquote,strikethrough,bullist,numlist,spellchecker,|,undo,redo,|,mygallery_button',
'theme_advanced_buttons2' => '',
'theme_advanced_buttons3' => '',
'theme_advanced_buttons4' => ''
),
'quicktags' => $qt
);
And this one to insert new button:
function filter_mce_button( $buttons ) {
// add a separation before our button, here our button's id is "mygallery_button"
array_push( $buttons, '|', 'mygallery_button' );
return $buttons;
}
function filter_mce_plugin( $plugins ) {
// this plugin file will work the magic of our button
$plugins['myplugin'] = plugin_dir_url( __FILE__ ) . 'mygallery_plugin.js';
return $plugins;
}
add_filter( 'mce_buttons', array( $this, 'filter_mce_button' ) );
add_filter( 'mce_external_plugins', array( $this, 'filter_mce_plugin' ) );
Read this tutorial. https://www.gavick.com/magazine/adding-your-own-buttons-in-tinymce-4-editor.html#tc-section-4
Very detailed tutorial. But the bare essentials are as follows: in your functions.php add this code to register and create your button:
function add_container_button() {
if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') )
return;
if ( get_user_option('rich_editing') == 'true') {
add_filter('mce_external_plugins', 'add_container_plugin');
add_filter('mce_buttons_3', 'register_container_button');
}
}
add_action('init', 'add_container_button');
function register_container_button($buttons) {
array_push($buttons, "|", "skizzar_container");
return $buttons;
}
function add_container_plugin($plugin_array) {
$plugin_array['skizzar_container'] = plugin_dir_url( __FILE__ ) . 'shortcodes-js/container.js';;
return $plugin_array;
}
Then you'll need to create a js file which handles how the buttons acts in the editor (you can see mine is referenced in the code above as container.js. Here is the code of my js file:
(function() {
tinymce.PluginManager.add('skizzar_container', function( editor, url ) {
editor.addButton( 'skizzar_container', {
title: 'Add a Container',
icon: 'icon dashicons-media-text',
onclick: function() {
editor.windowManager.open( {
title: 'Container',
body: [{
type: 'listbox',
name: 'style',
label: 'Style',
'values': [
{text: 'Clear', value: 'clear'},
{text: 'White', value: 'white'},
{text: 'Colour 1', value: 'colour1'},
{text: 'Colour 2', value: 'colour2'},
{text: 'Colour 3', value: 'colour3'},
]
}],
onsubmit: function( e ) {
editor.insertContent( '[container style="' + e.data.style + '"]<br /><br />[/container]');
}
});
}
});
});
})();
This creates a popup with a dropdown menu where the user can select a style. Hope this helps in some way