WordPress Gutenberg get block styles from useBlockProps - javascript

I am adding styles when registering my block:
styles: [
{ name: "my-style-1", label: "Style Name" }
{ name: "my-style-2", label: "Style Name 2" }
],
In the edit() and save() function how can I see which style/classname was selected?
I tried for example:
edit( { attributes, setAttributes, styles } ) {
const blockProps = useBlockProps();
const { quote, name, title } = attributes;
console.log(styles);
console.log(blockProps.styles);
...
But it returns undefined.
I need to use the styles for conditions for example...
if (style == 'my-style-1') {
// do something if style 1 was selected
}

The selected Block Style name as defined in your styles[{...}] is available in the edit() function as className:
edit({ attributes, setAttributes, className}) {
console.log(className);
...
}
I'd suggest if you want to reorder elements based on their style, create Block Styles and use CSS flexbox to manage the reordering, eg display:flex for your wrapper div and order: ... for the child elements (like <img> and <p>). By using styles, when the content is saved the underlying HTML markup doesn't change so less change of getting the dreaded 'block validation' error (plus you get a preview of the style in the Editor). Make sure to save blockProps in the save() so the selected class is applied, eg:
edit({ attributes, setAttributes, className }) {
const blockProps = useBlockProps();
console.log(className);
return (
<div {...blockProps}>
<h2>Hello</h2><img />
</div>
);
},
save({ attributes }) {
const blockProps = useBlockProps.save();
return (<div {...blockProps}><h2>Hello</h2><img /></div>)
}
The generated class applied to the <div> will be .wp-block-myblock-name .is-style-my-style-1

I would recommend you to use Block Variations instead of Block Styles. When creating a variation you can assign attribute values.
For example:
index.php
registerBlockType('xy/yourBlock', {
title: 'xy',
description: 'xy',
attributes: {
quote: {
type: 'string'
},
name: {
type: 'string'
},
title: {
type: 'string'
},
style: {
type: 'string'
}
},
variations: [
{
name: 'my-style-1',
isDefault: true,
title: 'Style Name',
attributes: { style: 'my-style-1' },
scope: 'transform',
},
{
name: 'my-style-2',
title: 'Style Name 2',
attributes: { style: 'my-style-2' },
scope: 'transform',
},
],
})
With scope: 'transform' you can select your variation in the block settings on the right side. Once a variation is selected you can access it in your edit and save file like any other attribute.
edit( { attributes, setAttributes } ) {
const { quote, name, title, style } = attributes;
console.log(style);
if (style == 'my-style-1') {
// do something if style 1 was selected
}

Related

Multiple NuxtJS og:image Meta Tags

In the specification of Open Graph protocol - Arrays it is documented that multiple versions of the type og:image may be arranged.
We use on components basis this structure in NuxtJS ssr:
export default {
data() {
return {
title: 'Home page'
}
},
head() {
return {
title: this.title,
meta: [
{
hid: 'description',
name: 'description',
content: 'Home page description'
}
// And others...
]
}
}
}
The goal is to have multiple nodes of the tag <meta property="og:image" content="https://example.com/rock.jpg" /> generated by NuxtJS Meta. The thinking is, since these are dynamic pages, to build an array and merge them into the meta array.
export default {
data() {
return {
title: 'Home page'
}
},
head() {
return {
title: this.title,
meta: [
{
hid: 'description',
name: 'description',
content: 'Home page description'
}
// And others...
...this.getMetaOgImages
]
}
},
computed: {
getMetaOgImages() {
const tempArr = []
// this.images comes from map state vuex-store
this.images.forEach(image => {
tempArr.push(
{
hid: 'og:image',
property: 'og:image',
content: image.url
},
{
hid: 'og:image:secure_url',
property: 'og:image:secure_url',
content: image.url
}
)
})
return tempArr
}
}
}
The computed property contains all urls, but in the browser (in the generated <meta> tags) only the first element is present.
It seems to me that vue-meta filters out the other elements because they are considered duplicates.
Can anyone confirm this or does anyone have experience with outputting multiple elements?
According to the specification this is valid and should not be a problem.

Recreating the columns block - building a custom block

As the title, I am looking to recreate the basic functionality of the WP columns block. The reason for this is-
WP adds a number of controls that I do not want the user to have (variations, width slider)
The allowed blocks, a column, lets the user add any sort of content they like. I am looking to have control over this with an allowed block list
I have created the following edit function:
( function( wp ) {
var registerBlockType = wp.blocks.registerBlockType;
var el = wp.element.createElement;
var __ = wp.i18n.__;
const { RadioControl, PanelBody, RangeControl } = wp.components;
const { useBlockProps, InspectorControls, InnerBlocks } = wp.blockEditor;
const allowedBlocks = [ 'core/paragraph', 'core/button' ];
registerBlockType( 'wpboiler-core/columns', {
apiVersion: 2,
title: __(
'Columns',
'columns'
),
description: __(
'A block for displaying content in columns',
'columns'
),
category: 'design',
icon: 'schedule',
supports: {
html: false,
},
attributes: {
columnselect: {
type: 'number',
default: 2,
},
},
edit: function(props) {
const { attributes, setAttributes } = props;
const { columnselect } = attributes;
const onChangeColumnRange = value => setAttributes({ columnselect: value });
let columnsContainer = [];
for(var n = 1; n <= columnselect; n++) {
columnsContainer.push(
el(
'div',
null,
el(
InnerBlocks, {
allowedBlocks: allowedBlocks,
}
)
)
);
};
return el(
'section',
useBlockProps(attributes),
// INSPECTOR CONTROL BEGIN
el(
InspectorControls,
null,
el(
PanelBody,
{
title: "Columns",
},
el(
RangeControl, {
min: 2,
max: 4,
value: columnselect,
onChange: onChangeColumnRange,
}
),
),
),
// INSPECTOR CONTROL END
el(
'div',
{ className: 'columns__container' },
columnsContainer
),
);
},
save: function() {
return null;
},
} );
}(
window.wp
) );
The issue I am coming up against is multiple InnerBlocks. The function creates a list of InnerBlock areas. However, editing one area changes them all.
I believe one method to get around this would be to create a custom column block which contains an InnerBlock component, and render that in the for loop instead of InnerBlock. So something along the lines of...
for(var n = 1; n <= columnselect; n++) {
columnsContainer.push(
{RENDER_COLUMN_BLOCK}
);
};
But if I did this, would I still come up with the same issue? That editing one of the columns would in fact edit them all? Does each instance need to have an ID to know which is being edited?
And I am also struggling to find out how I render another custom component inside a block when not using a build-step (es5).
Any help on this task would be appreciated.
Update
A 'solution' I have created after coming across the following post is as follows, where it basically turns off the block appender once the desired column count is reached. Each new instance creates a custom block called column which has its own set of allowed blocks.
// COLUMNS index.js
( function( wp ) {
var registerBlockType = wp.blocks.registerBlockType;
var el = wp.element.createElement;
var __ = wp.i18n.__;
const { useSelect } = wp.data;
const { useBlockProps, InnerBlocks } = wp.blockEditor;
const allowedBlocks = [ 'wpboiler-core/column' ];
registerBlockType( 'wpboiler/columns', {
apiVersion: 2,
title: __(
'Columns',
'columns'
),
description: __(
'Displays content in columns',
'columns'
),
category: 'design',
icon: 'schedule',
supports: {
html: false,
},
edit: function(props) {
const { attributes, clientId } = props;
const innerBlockCount = useSelect((select) => select('core/block-editor').getBlock(clientId).innerBlocks);
return el(
'section',
useBlockProps(attributes),
__( 'Add columns by pressing the + icon. Maximum 4 columns', 'columns' ),
el(
'div',
{ className: 'columns__container' },
innerBlockCount.length > 3 ?
el(
InnerBlocks, {
allowedBlocks: allowedBlocks,
renderAppender: false
}
)
:
el(
InnerBlocks, {
allowedBlocks: allowedBlocks,
}
),
)
);
},
save: function() {
return el(
'section',
{ className: 'columns' },
el(
'div',
{ className: 'columns__container' },
el(
InnerBlocks.Content, {},
),
),
);
},
} );
}(
window.wp
) );
// COLUMN - INDIVIDUAL index.js
( function( wp ) {
var registerBlockType = wp.blocks.registerBlockType;
var el = wp.element.createElement;
var __ = wp.i18n.__;
const { useBlockProps, InnerBlocks } = wp.blockEditor;
const allowedBlocks = [ 'core/heading', 'core/paragraph', 'core/button', 'core/list' ];
registerBlockType( 'wpboiler/column', {
apiVersion: 2,
title: __(
'Column',
'column'
),
description: __(
'Displays an individual column',
'column'
),
category: 'widgets',
icon: 'schedule',
supports: {
html: false,
},
parent: [ 'wpboiler-core/columns' ],
edit: function() {
return el(
'div',
useBlockProps(),
el(
'div',
{ className: 'column' },
el(
InnerBlocks,
{
allowedBlocks: allowedBlocks,
},
),
),
);
},
save: function() {
return el(
'div',
{ className: 'column' },
el(
InnerBlocks.Content, {},
),
);
},
} );
}(
window.wp
) );
However, doing it this way removes the need for the range control/columns select. But it does act in a similar (although not identical) way to the native columns block.
Again, other suggestions are welcomed.
You are correct in that you cannot have multiple <InnerBlocks> within a single block. Your best option is, as you suggest, to use two blocks: a columns wrapper block with a single <InnerBlocks> component that can only contain column blocks. Each column block can then have its own <InnerBlocks> component.
You will not need to loop over anything, since the <InnerBlocks> component will take care of rendering all the column blocks for you. Essentially you will have a columns block that outputs:
<InnerBlocks
allowedBlocks={ ['my/columns'] }
orientation="horizontal"
/>
Then your column block will just output:
<InnerBlocks/>
This is exactly how the WordPress core columns block works. I have also successfully used this myself to replace the built-in columns block.
Finally, although it seems like a lot of extra work to add a build step, I highly encourage it. It makes the code significantly easier to read and work with.

Customizing dropdown button for CKeditor 5

Managed to add a custom dropdown button to the toolbar:
But I don't know how to add a label or an icon to it.
Here's my code:
import Plugin from '#ckeditor/ckeditor5-core/src/plugin';
import Model from '#ckeditor/ckeditor5-ui/src/model';
import { createDropdown, addListToDropdown } from '#ckeditor/ckeditor5-ui/src/dropdown/utils';
import Collection from '#ckeditor/ckeditor5-utils/src/collection';
import imageIcon from '#ckeditor/ckeditor5-core/theme/icons/image.svg';
export default class ImageDropdown extends Plugin {
static get pluginName() {
return 'ImageDropdown';
}
init() {
const editor = this.editor;
const t = editor.t;
const defaultTitle = t('Add image');
const dropdownTooltip = t('Image');
// Register UI component
editor.ui.componentFactory.add('imageDropdown', locale => {
const dropdownView = createDropdown( locale );
dropdownView.set({
label: 'Image',
tooltip: true
});
dropdownView.buttonView.set( {
isOn: false,
withText: true,
tooltip: dropdownTooltip
});
dropdownView.extendTemplate( {
attributes: {
class: [
'ck-image-dropdown'
]
}
});
// The collection of the list items.
const items = new Collection();
items.add( {
type: 'button',
model: new Model( {
label: 'Uppload image',
icon: imageIcon
})
});
items.add( {
type: 'button',
model: new Model( {
label: 'Image URL',
icon: imageIcon
})
});
// Create a dropdown with a list inside the panel.
addListToDropdown( dropdownView, items );
return dropdownView;
});
}
}
Setting labels, icons etc. for a dropdown button should take place on the dropdown's view instance:
dropdownView.buttonView.set({
label: 'some-label',
icon: 'path/to/some/icon'
tooltip: true
});
Note that these properties are observable and can be dynamically evaluated based on some state using the ObservableMixin#bind function.
See an example here: https://github.com/ckeditor/ckeditor5-alignment/blob/894745ecb1e8bd94286b4089eb16079034eb8a0b/src/alignmentui.js#L107-L124

Change default size of the <p> tag in CKEditor

I want to change the default font size of the CKEditor <p> tag.
I have tried all given options in documentation but nothing is working.
config.format_p = { element: 'p', attributes: { 'class': 'normalPara' } };
config.format_p = { element: 'p', attributes: { 'style': 'font-size:20px' } };
config.fontSize_defaultLabel = '12px';
config.fontSize_style = {
element: 'p',
styles: { 'font-size': '#(size)' },
overrides: [ { element: 'font', attributes: { 'size': '100px'} } ]
};
Adjust the default style available in the contents.css file. You can use the config.contentsCss configuration option to point to your custom styles (to avoid overwriting changes introduced to the default contents.css file on upgrade).

move item control bar videojs

I'm using the video.js 4.12 library and I want replace control bar items. For example, move one of my custom buttons to the 2nd slot of the control bar.
How do I change the order of items on the taskbar? I had no luck on Google.
Videojs place good class on elements. By this way you can identify control bar's elements.
To handle the item's order I used Jquery :
var createPrevButton = function() {
var props = {
className: 'vjs-control player-prev-button', //We use this class in Jquery
innerHTML: '<div class="vjs-control-content"></div>',
role: 'button',
'aria-live': 'polite',
tabIndex: 0
};
return videojs.Component.prototype.createEl(null, props);
};
var myPlayer = me.player = videojs(me.idVideo, {
plugins : { chapters : {} },
children: {
controlBar: {
children: [
{
name: 'playToggle'
},
{
name: 'currentTimeDisplay'
},
{
name: 'timeDivider'
},
{
name: 'durationDisplay'
}
/*
...........
*/
]
}
}
});
$(".player-prev-button").insertAfter(".vjs-play-control");
$(".player-next-button").insertAfter(".player-prev-button");
After the instanciation of my player just handle item by Jquery.
I think it's better than use CSS.
But the best way should be by videojs's option or somethink like that

Categories

Resources