• How to create a Gutenberg block with your own list, inside which there will be other tags?

    I found this solution to create a block with a list:

    return el(
    				'div',
    				{ className: props.className },
    				el( RichText, {
    					tagName: 'ul',
    					multiline: 'li',
    					placeholder: i18n.__(
    						'Write yours ingredients…',
    						'gutenberg-examples'
    					),
    					value: attributes.ingredients,
    					onChange: function( value ) {
    						props.setAttributes( { ingredients: value } );
    					},
    					className: 'ingredients',
    				} )
    			);
    		},
    		save: function( props ) {
    			var attributes = props.attributes;
    
    			return el(
    				'div',
    				{ className: props.className },
    
    				el( RichText.Content, {
    					tagName: 'ul',
    					className: 'ingredients',
    					value: attributes.ingredients,
    				} )
    			);

    But it outputs the result:

    <ul class="ingredients"> 
    <li>Ingredient 1</li>
    <li>Ingredient 2</li>
    <li>Ingredient 3</li>
    </ul>

    And I need to do:

    <ul class="list"><li class="list-item1">
        <input type="checkbox" class="hidden-box" id="ingr1">
        <label for="ingr1" class="check--label">
          <span class="check--label-box"></span>
          <span class="check--label-text">Ingredient 1.</span>
        </label>
      </li><li class="list-item2">
        <input type="checkbox" class="hidden-box" id="ingr2">
        <label for="ingr2" class="check--label">
          <span class="check--label-box"></span>
          <span class="check--label-text">Ingredient 2.</span>
        </label>
      </li><li class="list-item3">
        <input type="checkbox" class="hidden-box" id="ingr3">
        <label for="ingr3" class="check--label">
          <span class="check--label-box"></span>
          <span class="check--label-text">Ingredient 3.</span>
        </label>
      </li></ul>

    Does anyone know how to put <input>, <label> and <span> inside < li > ?

    ///Sorry for the bad english. I hope my question is clear.

    • This topic was modified 4 years, 10 months ago by mrvigner.
    • This topic was modified 4 years, 10 months ago by mrvigner.
    • This topic was modified 4 years, 10 months ago by mrvigner.
Viewing 11 replies - 1 through 11 (of 11 total)
  • @mrvigner

    I don’t think this can be done with the multiline approach as I think that can only insert one wrapping HTML tag.

    I manages to get it to work with some data manipulation and recursions within the save function as follows:

    
    edit: function( props ) {
    	var attributes = props.attributes;
    	return el(
    		'div',
    		{ className: props.className },
    		el( 
    			editor.RichText, {
    				tagName: 'ul',
    				placeholder: i18n.__(
    					'Write yours ingredients…',
    					'gutenberg-examples'
    				),
    				value: attributes.ingredients,
    				onChange: function( value ) {
    					props.setAttributes( { ingredients: value } );
    				},
    				className: 'ingredients',
    			}
    		)
    	);
    },
    save: function( props ) {
    	var attributes = props.attributes;
    	var ingredients = attributes.ingredients.split( '<br>' );
    	var content = '';
    	var openspan = '<span class="check--label-box"></span><span class="check--label-text">';
    	var closetags = '</span><label></li>';
    	var len = ingredients.length;
    
    	for ( var i = 0; i < len; i++) {
    		content = content + '<li class="list-item' + ( i + 1 ) + '">';
    		content = content + '<input type="checkbox" class="hidden-box" id="ingr' + ( i + 1 ) + '">';
    		content = content + '<label for="ingr' + ( i + 1 ) + '" class="check--label">';
    		content = content + openspan + ingredients[i] + closetags;
    	}
    
    	return el(
    		'div',
    		{ className: props.className },
    		el(
    			editor.RichText.Content, {
    				tagName: 'ul',
    				className: 'list',
    				value: content,
    			}
    		)
    	);
    }
    
    Thread Starter mrvigner

    (@mrvigner)

    @mattyrob Thanks for the help. I tried to apply your code, but for some reason, saving the text entered in the block does not work.

    Here is the complete block.js code with the implementation of your solution:

    ( function( blocks, editor, i18n, element, components, _ ) {
    	var __ = i18n.__;
    	var el = element.createElement;
    	var RichText = editor.RichText;
    
    	blocks.registerBlockType( 'gutenberg-examples/recipe-ingredient', {
    		title: __( 'Ingredients', 'gutenberg-examples' ),
    		icon: 'index-card',
    		category: 'layout',
    		attributes: {
    			ingredients: {
    				type: 'array',
    				source: 'children',
    				selector: '.ingredients',
    			},
    		},
    
    		edit: function( props ) {
    			var attributes = props.attributes;
    
    			return el(
    				'div',
    				{ className: props.className },				
    				el( RichText, {
    					tagName: 'ul',
    					placeholder: i18n.__(
    						'Write a list of ingredients…',
    						'gutenberg-examples'
    					),
    					value: attributes.ingredients,
    					onChange: function( value ) {
    						props.setAttributes( { ingredients: value } );
    					},
    					className: 'ingredients',
    				} )
    			);
    		},
    		save: function( props ) {
    	var attributes = props.attributes;
    	var ingredients = attributes.ingredients.split( '<br/>' );
    	var content = '';
    	var openspan = '<span class="check--label-box"></span><span class="check--label-text">';
    	var closetags = '</span><label></li>';
    	var len = ingredients.length;
    
    	for ( var i = 0; i < len; i++) {
    		content = content + '<li class="list-item' + ( i + 1 ) + '">';
    		content = content + '<input type="checkbox" class="hidden-box" id="ingr' + ( i + 1 ) + '">';
    		content = content + '<label for="ingr' + ( i + 1 ) + '" class="check--label">';
    		content = content + openspan + ingredients[i] + closetags;
    	}
    
    	return el(
    		'div',
    		{ className: props.className },
    		el(
    			editor.RichText.Content, {
    				tagName: 'ul',
    				className: 'list',
    				value: content,
    			}
    		)
    	);
    },
    	} );
    } )(
    	window.wp.blocks,
    	window.wp.editor,
    	window.wp.i18n,
    	window.wp.element,
    	window.wp.components,
    	window._
    );
    

    Am I doing something wrong?

    • This reply was modified 4 years, 10 months ago by mrvigner.

    @mrvigner

    First the separator for the ‘ingredients’ is <br> not <br /> so your code currently won’t create the correct array.

    And I also think the attribute definition is causing issues, my version works fine without the there.

    Also I’m using window.wp.blockEditor rather than window.wp.editor but that’s more for future version and I don’t think it will make a difference now.

    Thread Starter mrvigner

    (@mrvigner)

    @mattyrob

    I tried it <br/> instead of <br>, because it didn’t work, and in the source code of the editor it was clear that it put <br/> when I do the transfer. But that is not the problem….

    @mrvigner

    Weird, I’m getting <br> although that may be theme dependent.

    Try removing the attribute section from your code.

    I was using this:

    ( function( blocks, editor, i18n, element ) {
    	var __ = i18n.__;
    	var el = element.createElement;
    	var RichText = editor.RichText;
    
    	blocks.registerBlockType(
    		'ingredients/shortcode',
    		{
    			title: __( 'Ingredients' ),
    			icon: 'index-card',
    			category: 'widgets',
    			edit: function( props ) {
    				var attributes = props.attributes;
    				return el(
    					'div',
    					{ className: props.className },
    					el( 
    						RichText, {
    							tagName: 'ul',
    							placeholder: __(
    								'Write yours ingredients…',
    								'gutenberg-examples'
    							),
    							value: attributes.ingredients,
    							onChange: function( value ) {
    								props.setAttributes( { ingredients: value } );
    							},
    							className: 'ingredients',
    						}
    					)
    				);
    			},
    			save: function( props ) {
    				var attributes = props.attributes;
    				console.log( attributes.ingredients );
    				var ingredients = attributes.ingredients.split( '<br>' );
    				var content = '';
    				var openspan = '<span class="check--label-box"></span><span class="check--label-text">';
    				var closetags = '</span><label></li>';
    				var len = ingredients.length;
    
    				for ( var i = 0; i < len; i++) {
    					content = content + '<li class="list-item' + ( i + 1 ) + '">';
    					content = content + '<input type="checkbox" class="hidden-box" id="ingr' + ( i + 1 ) + '">';
    					content = content + '<label for="ingr' + ( i + 1 ) + '" class="check--label">';
    					content = content + openspan + ingredients[i] + closetags;
    				}
    
    				return el(
    					'div',
    					{ className: props.className },
    					el(
    						RichText.Content, {
    							tagName: 'ul',
    							className: 'list',
    							value: content,
    						}
    					)
    				);
    			}
    		}
    	);
    } )(
    	window.wp.blocks,
    	window.wp.blockEditor,
    	window.wp.i18n,
    	window.wp.element
    );
    
    
    Thread Starter mrvigner

    (@mrvigner)

    @mattyrob Thanks, it worked!

    True, when adding a new article it works. And if you then try to edit an article that has this block – an empty white page instead of an editor.

    Now I’ll try to look at the logs for errors.

    Thread Starter mrvigner

    (@mrvigner)

    @mattyrob The only error found – “the block editor requires javascript. please enable javascript in your browser settings or try the Classic editor plugin.”

    Present only when editing those entries where this widget is inserted ??

    @mrvigner

    I suspect the issue now is the parsing of the data to create the editor block, I suspect an attribute {} is required and probably some processing in the edit function.

    Thread Starter mrvigner

    (@mrvigner)

    @mrvigner

    Do I understand correctly: in the function “edit” I now need to cut out the text from the html code in order to finally get in the block in the editor “line <br> line <br> line <br>”?

    So that later the save function could convert “line<br>line<br>line<br>” back to the code required on the front-end?

    Thread Starter mrvigner

    (@mrvigner)

    Or, if I understand correctly, the instructions for the following attributes should remove the markup leaving only the text?

    https://developer.www.ads-software.com/block-editor/developers/block-api/block-attributes/#text

    sd

    blocks.registerBlockType(
    		'ingredients/shortcode',
    		{
    			title: __( 'Ingredients' ),
    			icon: 'index-card',
    			category: 'widgets',
    			attributes: {
    				content: {
    				type: 'string',
    				source: 'text',
    				selector: '.ingredients'
    			}
    		},
    • This reply was modified 4 years, 10 months ago by mrvigner.

    @mrvigner @mattyrob

    I seem to get the same error like you(the content generated by the save function is different compared to the one retrieved from the post body), did you by any chance managed to solve this problem ?

    • This reply was modified 4 years, 6 months ago by nik92.
Viewing 11 replies - 1 through 11 (of 11 total)
  • The topic ‘How to create a Gutenberg block with your own list, inside which there will be o’ is closed to new replies.