I'm trying to add an autocomplete functionality on my TextControl component in WordPress Gutenberg Sidebar. I need help on how to do it. Here's my js file:
( function ( wp ) {
var registerPlugin = wp.plugins.registerPlugin;
var PluginSidebar = wp.editPost.PluginSidebar;
var el = wp.element.createElement;
var TextControl = wp.components.TextControl;
var ToggleControl = wp.components.ToggleControl;
var useState = wp.element.useState;
var useSelect = wp.data.useSelect;
var useDispatch = wp.data.useDispatch;
var autoComplete = wp.data.autoComplete;
// Function that initializes the Product Link text field.
var CpwProductLinkField = function ( props ) {
var productLinkFieldValue = useSelect( function ( select ) {
return select( 'core/editor' ).getEditedPostAttribute(
'meta'
)[ 'prodlink' ];
}, [] );
var editPost = useDispatch( 'core/editor' ).editPost;
return el( TextControl, {
label: 'Product Link',
value: productLinkFieldValue,
onChange: function ( content ) {
editPost( {
meta: { prodlink: content },
} );
},
} );
};
// Function that renders the fields.
registerPlugin( 'sidebar', {
render: function () {
return el(
PluginSidebar,
{
name: 'sidebar',
icon: 'admin-post',
title: 'Paywall Settings',
},
el(
'div',
{ className: 'plugin-sidebar-content' },
el( CpwProductLinkField )
)
);
},
} );
} )( window.wp );
I tried implementing the AutoComplete component, but it doesn't work.
Related
I use Gutenberg with WordPress for a website with students.
I would like to display a list with all students (roles : student)
and exclude from the list the student who is logged in.
I tried two solutions.
First solution with getUsers() function. When I'm logged like an administrator all works fine but when a student is logged, he does not have permission to view the list. Only administrators have permission.
Second solution with a custom API route. I got a promise pending.
First solution :
import { __ } from '#wordpress/i18n';
import { CheckboxControl } from '#wordpress/components';
import { registerPlugin } from '#wordpress/plugins';
import { PluginDocumentSettingPanel } from '#wordpress/edit-post';
import { useSelect, useDispatch } from '#wordpress/data';
import { useEntityProp } from '#wordpress/core-data';
import { useState, setState, useEffect } from '#wordpress/element';
const metaboxStudents = () => {
const postType = useSelect( ( select ) => {
return select( 'core/editor' ).getCurrentPostType();
});
if ( postType !== 'subject-imposed' ) {
return null;
}
const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
const authors = useSelect( ( select ) => {
return select( 'core' ).getUsers( { roles: 'student' } );
}, [] );
if ( !posts ) {
return null;
}
const handleCheckboxChange = (data) => {
const isChecked = meta._metafield_students.some(checkedCheckbox => checkedCheckbox === data);
if (isChecked) {
setMeta( { _metafield_students: meta._metafield_students.filter( ( checkedCheckbox) => checkedCheckbox !== data) } );
} else {
setMeta( { _metafield_students: meta._metafield_students.concat(data) } );
}
};
return(
<PluginDocumentSettingPanel
name="list-students"
title={ __( 'List of students', 'ccn-gut' ) }
className='editor-styles-metabox'
>
<div className="gut-checkboxes-group">
{ posts.map( ( data ) => (
wp.data.select("core").getCurrentUser().id !== data.id
? (
<CheckboxControl
label={ data.name }
key={`student-${data.id}`}
value={ data.id }
checked={ meta._metafield_students.some(checkedCheckbox => checkedCheckbox === data.id) }
onChange={ () => handleCheckboxChange(data.id) }
/>
) : null
) ) }
</div>
</PluginDocumentSettingPanel>
);
};
registerPlugin('plugin-document-students', {
render: metaboxStudents,
icon: null
});
Second solution :
PHP for my WordPress plugin :
wp_localize_script( 'wp-api', 'wpApiSettings', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' )
));
PHP for API route :
function student_api_rest() {
register_rest_route('api/v1/', 'students', array(
'methods' => 'GET',
'callback' => 'student_api_results'
));
}
function student_api_results($data) {
....
}
index.js :
import apiFetch from '#wordpress/api-fetch';
wp.apiFetch.use( apiFetch.createNonceMiddleware( wpApiSettings.nonce ) );
const [users, setUsers] = useState( null );
useEffect( () => {
wp.apiFetch( { path: '/api/v1/students' } ).then(
(result) => {
setUsers( result );
}
)
}, []);
console.log(users);
Which solution to choose and how to resolve one of those two solutions? Permission VS promise Pending
you should be able to add capabilities to the custom user types of "students". look for where the student role was activated, it should look something like this
add_role( $role, $display_name, $capabilities );
and your looking to add list_users as a capability I believe. You can find the full list of capabilities here https://wordpress.org/support/article/roles-and-capabilities/ and heres the link directly to the list_users section of that https://wordpress.org/support/article/roles-and-capabilities/#list_users
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',
) );
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.
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