Forum Replies Created

Viewing 15 replies - 16 through 30 (of 44 total)
  • Thread Starter Steve

    (@bugdens)

    Unfortunately, there’s a problem with this solution.

    get_the_content() doesn’t work in all circumstances.
    I’m using a 3rd party element and this function just returns the content for the page of course and not the element.

    So it would be much better to access the attributes for the nested blocks directly in PHP rather than extracting from the content.

    Just to recap, I can access the top level attributes as follows:

    function render_html($attributes, $content, $post) {
        ob_start();
        $SomeAttribute = $attributes['SomeAttribute'];

    At the risk of repeating my question, does anyone know how to access the attributes for nested blocks?

    Best Regards,

    Steve

    Thread Starter Steve

    (@bugdens)

    Hi Adam,

    Thank you so much for taking a look at this.

    Sure, I put the edit.js below.

    Steve

    import { useEffect } from '@wordpress/element';
    
    import {
    	RichText,
    	useBlockProps,
    	InnerBlocks,
    	InspectorControls,
    	PanelColorSettings,
    	//ContrastChecker,
    	withColors,
    } from '@wordpress/block-editor';
    
    import {
    	Panel,
    	PanelBody,
    	PanelRow,
    	RangeControl,
    	RadioControl,
    	ToggleControl,
    	TextControl,
    } from '@wordpress/components';
    
    import { __ } from '@wordpress/i18n';
    import './editor.scss';
    
    function Edit(props) {
    	const {
    		attributes,
    		setAttributes,
    		backgroundColor,
    		//textColor,
    		setBackgroundColor,
    		//setTextColor,
    	} = props;
    
    	const {
    		ColumnsXS,
    		ColumnsSM,
    		ColumnsMD,
    		ColumnsLG,
    		ColumnsXL,
    		ColumnsXXL,
    		mainTitle,
    		mainTitleAlignment,
    		EnableSocialMediaButtons,
    		DefaultButtonTextValue,
    		TitlePosition,
    		UniqueID,
    		LayoutStyle,
    		//BelowImageCardTitleClass,
    		//AboveImageCardTitleClass,
    	} = attributes;
    
    	//Generate a value for the UniqueID if not set
    
    	const onChangeID = (newID) => {
    		setAttributes({ UniqueID: newID });
    	};
    
    	const onChangeColumnsXS = (newColumns) => {
    		setAttributes({ ColumnsXS: newColumns });
    	};
    
    	const onChangeColumnsSM = (newColumns) => {
    		setAttributes({ ColumnsSM: newColumns });
    	};
    
    	const onChangeColumnsMD = (newColumns) => {
    		setAttributes({ ColumnsMD: newColumns });
    	};
    
    	const onChangeColumnsLG = (newColumns) => {
    		setAttributes({ ColumnsLG: newColumns });
    	};
    
    	const onChangeColumnsXL = (newColumns) => {
    		setAttributes({ ColumnsXL: newColumns });
    	};
    
    	const onChangeColumnsXXL = (newColumns) => {
    		setAttributes({ ColumnsXXL: newColumns });
    	};
    
    	const onChangeMainTitle = (value) => {
    		setAttributes({ mainTitle: value });
    	};
    
    	const onChangeTitleAlignment = (value) => {
    		setAttributes({ mainTitleAlignment: value });
    	};
    
    	const onChangeLayoutStyle = (value) => {
    		setAttributes({ LayoutStyle: value });
    	};
    
    	const onChangedDefaultButtonText = (value) => {
    		setAttributes({ DefaultButtonTextValue: value });
    	};
    
    	const onChangeTitlePosition = (value) => {
    		setAttributes({ TitlePosition: value });
    		//(value);
    	};
    
    	useEffect(() => {
    		if (TitlePosition === 'above-image') {
    			setAttributes({
    				AboveImageCardTitleClass: 'title-above-image-displayed',
    			});
    			setAttributes({
    				BelowImageCardTitleClass: 'title-below-image-not-displayed',
    			});
    		} else {
    			setAttributes({
    				AboveImageCardTitleClass: 'title-above-image-not-displayed',
    			});
    			setAttributes({
    				BelowImageCardTitleClass: 'title-below-image-displayed',
    			});
    		}
    	}, [TitlePosition]);
    
    	//useEffect(() => {
    	//return;
    	//document.getElementById {UniqueID}
    	//const SetTitlePosition = (value) => {
    	// 	if (TitlePosition === 'above-image') {
    	// 		//Display the title above the image
    
    	// 		const a = document.getElementsByClassName(
    	// 			<code>title-above-image-not-displayed ${UniqueID}</code>
    	// 		);
    
    	// 		[...a].forEach(
    	// 			(x) => (x.className += ' title-above-image-displayed ')
    	// 		);
    	// 		[...a].forEach((x) =>
    	// 			x.classList.remove('title-above-image-not-displayed')
    	// 		);
    
    	// 		//Hide the title below the image
    	// 		const b = document.getElementsByClassName(
    	// 			<code>title-below-image-displayed  ${UniqueID}</code>
    	// 		);
    	// 		[...b].forEach(
    	// 			(x) => (x.className += ' title-below-image-not-displayed')
    	// 		);
    	// 		[...b].forEach((x) =>
    	// 			x.classList.remove('title-below-image-displayed')
    	// 		);
    	// 	} else {
    	// 		//**************************************************************************************************************
    	// 		//Find every instance of the class which disables the display of the social media buttons and replace it with
    	// 		//the class to enable the display.
    	// 		const a = document.getElementsByClassName(
    	// 			<code>title-above-image-displayed ${UniqueID}</code>
    	// 		);
    	// 		[...a].forEach(
    	// 			(x) => (x.className += ' title-above-image-not-displayed')
    	// 		);
    	// 		[...a].forEach((x) =>
    	// 			x.classList.remove('title-above-image-displayed')
    	// 		);
    
    	// 		const b = document.getElementsByClassName(
    	// 			<code>title-below-image-not-displayed  ${UniqueID}</code>
    	// 		);
    	// 		[...b].forEach(
    	// 			(x) => (x.className += ' title-below-image-displayed')
    	// 		);
    	// 		[...b].forEach((x) =>
    	// 			x.classList.remove('title-below-image-not-displayed')
    	// 		);
    
    	// 		//**************************************************************************************************************
    	// 	}
    	// 	//};
    	// }, [TitlePosition, LayoutStyle]);
    
    	const onChangeEnableSocialMediaButtons = (value) => {
    		setAttributes({ EnableSocialMediaButtons: value });
    	};
    
    	//If the social media buttons are enabled, search through each card and display the social media buttons for each.
    	useEffect(() => {
    		if (EnableSocialMediaButtons === true) {
    			//Find every instance of the class which disables the display of the social media buttons and replace it with
    			//the class to enable the display.
    			const a = document.getElementsByClassName(
    				'social-media-links-disabled'
    			);
    			[...a].forEach(
    				(x) => (x.className += ' social-media-links-enabled')
    			);
    			[...a].forEach((x) =>
    				x.classList.remove('social-media-links-disabled')
    			);
    		} else {
    			//**************************************************************************************************************
    			//Find every instance of the class which disables the display of the social media buttons and replace it with
    			//the class to enable the display.
    			const a = document.getElementsByClassName(
    				'social-media-links-enabled'
    			);
    			[...a].forEach(
    				(x) => (x.className += ' social-media-links-disabled')
    			);
    			[...a].forEach((x) =>
    				x.classList.remove('social-media-links-enabled')
    			);
    			//**************************************************************************************************************
    		}
    	}, [EnableSocialMediaButtons]);
    
    	//heading alignment
    	const mainTitleClass = <code>main-heading-align-${mainTitleAlignment}</code>;
    
    	if (UniqueID === '') {
    		const lID =
    			Math.random().toString(36).substring(2, 15) +
    			Math.random().toString(36).substring(2, 15);
    		onChangeID(lID);
    		// console.log('just set it to = ' + lID);
    	}
    
    	// let divStyles = {};
    	// const className = getColorClassName(
    	// 	'background-color',
    
    	//);
    	//className={backgroundColor.class}
    	//console.log('props');
    	//console.log(props);
    	//const myClasses = <code><code>${backgroundColor.class} netmonics-xs-is-${ColumnsXS}-columns netmonics-sm-is-${ColumnsSM}-columns netmonics-md-is-${ColumnsMD}-columns netmonics-lg-is-${ColumnsLG}-columns netmonics-xl-is-${ColumnsXL}-columns netmonics-xxl-is-${ColumnsXXL}-columns</code></code>;
    
    	//console.log(myClasses);
    	const myClasses = <code>${backgroundColor.class} netmonics-xs-is-${ColumnsXS}-columns netmonics-sm-is-${ColumnsSM}-columns netmonics-md-is-${ColumnsMD}-columns netmonics-lg-is-${ColumnsLG}-columns netmonics-xl-is-${ColumnsXL}-columns netmonics-xxl-is-${ColumnsXXL}-columns</code>;
    	//console.log(myClasses);
    	//const myClasses =
    	//' netmonics-xs-is-2-columns netmonics-sm-is-3-columns netmonics-md-is-3-columns netmonics-lg-is-4-columns netmonics-xl-is-4-columns netmonics-xxl-is-4-columns ';
    
    	return (
    		<div
    			id="{UniqueID}"
    			{...useBlockProps({
    				className: myClasses,
    			})}
    		>
    			<InspectorControls>
    				<PanelColorSettings
    					title={__('Color Settings', 'text-box')}
    					icon="admin-appearance"
    					initialOpen={false}
    					disableCustomColors={false}
    					colorSettings={[
    						{
    							value: backgroundColor.color,
    							onChange: setBackgroundColor,
    							label: __('Background Color', 'text-box'),
    						},
    						// {
    						// 	value: textColor.color,
    						// 	onChange: setTextColor,
    						// 	label: __('Text Color', 'text-box'),
    						// },
    					]}
    				>
    					{/* <ContrastChecker
    						textColor={textColor.color}
    						backgroundColor={backgroundColor.color}
    					/> */}
    				</PanelColorSettings>
    
    				<Panel header="">
    					<PanelBody title="Columns" initialOpen={false}>
    						<PanelRow>
    							{__(
    								'Set the number of columns for each screen size',
    								'team-members'
    							)}
    						</PanelRow>
    						<PanelRow>{__('', 'team-members')}</PanelRow>
    						<RangeControl
    							label={__(
    								'Extra Small (less than 575px)',
    								'team-members'
    							)}
    							min={1}
    							max={6}
    							onChange={onChangeColumnsXS}
    							value={ColumnsXS}
    						/>
    						<RangeControl
    							label={__(
    								'Small (between 575px and 768px)',
    								'team-members'
    							)}
    							min={1}
    							max={6}
    							onChange={onChangeColumnsSM}
    							value={ColumnsSM}
    						/>
    						<RangeControl
    							label={__(
    								'Medium (between 768px and 992px)',
    								'team-members'
    							)}
    							min={1}
    							max={6}
    							onChange={onChangeColumnsMD}
    							value={ColumnsMD}
    						/>
    						<RangeControl
    							label={__(
    								'Large (between 992px and 1200px)',
    								'team-members'
    							)}
    							min={1}
    							max={6}
    							onChange={onChangeColumnsLG}
    							value={ColumnsLG}
    						/>
    						<RangeControl
    							label={__(
    								'XL (between 1200px and 1400px)',
    								'team-members'
    							)}
    							min={1}
    							max={6}
    							onChange={onChangeColumnsXL}
    							value={ColumnsXL}
    						/>
    						<RangeControl
    							label={__(
    								'XXL (greater than 1400px)',
    								'team-members'
    							)}
    							min={1}
    							max={6}
    							onChange={onChangeColumnsXXL}
    							value={ColumnsXXL}
    						/>
    					</PanelBody>
    				</Panel>
    
    				<Panel header="">
    					<PanelBody
    						title="Call to Action Button "
    						initialOpen={false}
    					>
    						<TextControl
    							label="Default Text"
    							value={DefaultButtonTextValue}
    							onChange={onChangedDefaultButtonText}
    							help={__('Enter the default text for the button')}
    						/>
    					</PanelBody>
    				</Panel>
    
    				<Panel header="">
    					<PanelBody title="Main Heading" initialOpen={false}>
    						<PanelRow>
    							{__('Configure the heading', 'team-members')}
    						</PanelRow>
    						<PanelRow>
    							{__('', 'team-members')}
    
    							<RadioControl
    								label="Alignment"
    								selected={mainTitleAlignment}
    								options={[
    									{ label: 'Left', value: 'left' },
    									{ label: 'Centre', value: 'center' },
    								]}
    								onChange={onChangeTitleAlignment}
    							/>
    						</PanelRow>
    					</PanelBody>
    				</Panel>
    
    				<Panel header="">
    					<PanelBody title="Layout Style" initialOpen={false}>
    						<PanelRow>
    							{__('Configure the layout', 'team-members')}
    						</PanelRow>
    						<PanelRow>
    							{__('', 'team-members')}
    
    							<RadioControl
    								label="Layout"
    								selected={LayoutStyle}
    								options={[
    									{ label: 'Stacked', value: 'stacked' },
    									{
    										label: 'Image Left',
    										value: 'image-left',
    									},
    								]}
    								onChange={onChangeLayoutStyle}
    							/>
    						</PanelRow>
    					</PanelBody>
    				</Panel>
    
    				<Panel header="">
    					<PanelBody title="Social Media Buttons" initialOpen={false}>
    						<PanelRow>{__('', 'team-members')}</PanelRow>
    
    						<PanelRow>
    							<ToggleControl
    								label="Enable Social Media Buttons"
    								checked={EnableSocialMediaButtons}
    								onChange={onChangeEnableSocialMediaButtons}
    							/>
    						</PanelRow>
    					</PanelBody>
    				</Panel>
    
    				{/* It only makes sense to display the title position options if the layout style is stacked */}
    				{LayoutStyle === 'stacked' && (
    					<Panel header="">
    						<PanelBody title="Title" initialOpen={false}>
    							<PanelRow>{__('', 'team-members')}</PanelRow>
    
    							<PanelRow>
    								<RadioControl
    									label="Set title position above or below the image"
    									selected={TitlePosition}
    									options={[
    										{
    											label: 'Above',
    											value: 'above-image',
    										},
    										{
    											label: 'Below',
    											value: 'below-image',
    										},
    									]}
    									onChange={onChangeTitlePosition}
    								/>
    							</PanelRow>
    						</PanelBody>
    					</Panel>
    				)}
    			</InspectorControls>
    
    			<RichText
    				placeholder={__('UniqueID', 'team-member')}
    				tagName="p"
    				onChange={onChangeID}
    				value={UniqueID}
    				allowedFormats={[]}
    				className="netmonics-cards-unique-id"
    			/>
    
    			<RichText
    				placeholder={__('Main Title', 'team-members')}
    				tagName="h2"
    				value={mainTitle}
    				allowedFormats={[]}
    				onChange={onChangeMainTitle}
    				className={mainTitleClass}
    			/>
    
    			<InnerBlocks
    				allowedBlocks={['netmonics/generic-card']}
    				orientation="horizontal" // Set the orientation to horizontal as the blocks are aligned horizontally and when dragged and dropped
    				// this will cause a blue vertical line to appear indicating where the block will be dropped.
    				template={[
    					['netmonics/generic-card'],
    					['netmonics/generic-card'],
    					['netmonics/generic-card'],
    				]}
    				//templateLock="all"  //Prevent more items being added, 'insert' is also a valid option.
    			/>
    		</div>
    	);
    }
    
    export default withColors({
    	backgroundColor: 'background-color',
    	// textColor: 'color',
    })(Edit);
    Thread Starter Steve

    (@bugdens)

    I’m not sure because under the section titled ‘block wrapper props’ it says ‘classNames’ plural:

    The first thing to notice here is the use of the useBlockProps React hook on the block wrapper element. In the example above, the block wrapper renders a “div” in the editor, but in order for the Gutenberg editor to know how to manipulate the block, add any extra classNames . . .

    Though the example below does show just a single class.

    Steve

    Thread Starter Steve

    (@bugdens)

    I’ve just noticed you modified your reply, sorry, I’ll take a look at that.

    Thread Starter Steve

    (@bugdens)

    It seems I can’t show ticks because this site uses them for displaying code.

    I put them where ‘xxx’ is in the following string:
    const myClasses = xxx<code>${backgroundColor.class} netmonics-xs-is-${ColumnsXS}-columns netmonics-sm-is-${ColumnsSM}-columns netmonics-md-is-${ColumnsMD}-columns netmonics-lg-is-${ColumnsLG}-columns netmonics-xl-is-${ColumnsXL}-columns netmonics-xxl-is-${ColumnsXXL}-columns</code>xxx;

    Thread Starter Steve

    (@bugdens)

    Hi Adam,

    Thank you for the idea.

    It doesn’t work unfortunately, I got errors with the above line, tried putting it in ticks i.e. ` but still didn’t work.
    const myClasses =<code>${backgroundColor.class} netmonics-xs-is-${ColumnsXS}-columns netmonics-sm-is-${ColumnsSM}-columns netmonics-md-is-${ColumnsMD}-columns netmonics-lg-is-${ColumnsLG}-columns netmonics-xl-is-${ColumnsXL}-columns netmonics-xxl-is-${ColumnsXXL}-columns</code>;

    Please let me know if you have any other ideas and I’ll give them a try.

    Best Regards,

    Steve

    • This reply was modified 3 years, 11 months ago by Steve.
    Thread Starter Steve

    (@bugdens)

    I found a way to solve this.

    I generated an ID for each block which is stored as an attribute.

    I can access the ID attribute in PHP and then check each line in the comments for that ID. When I find it, I know that the next line contains the item attributes for the block.
    I stop reading when I detect the closing tag for the block.

    That way each block only loads it’s own comments which contain the attributes.

    I hope that makes sense.

    Thread Starter Steve

    (@bugdens)

    Unfortunately, I discovered an issue with the above code.

    I’ve now discovered that it extracts the content for all blocks on the page not just the block making the call.

    Does anyone know how to obtain the content for the block making the call rather than for the whole page?

    To recap, I use a callback function ‘render_html’ function which extracts the comments as follows:

    function render_html($attributes, $content, $post) {
    
        ob_start();
    
        //Load the block's content
        $dom1 = new DOMDocument;
        $dom1->loadHTML(get_the_content());
    
        $xpath1 = new DOMXpath($dom1);
        //Get the comments
        $comments = $xpath1->query('.//comment()', $dom1);

    Best Regards,

    Steve

    • This reply was modified 3 years, 11 months ago by Steve.
    Thread Starter Steve

    (@bugdens)

    Hi,

    I’ve solved this problem now, in case anyone is interested, this is what I did:

    1) I removed source/query etc. from the attributes so that the attributes would not be stored in the html but as JSON in the comments of the block’s content.

    2) I changed the top level save function to return the innerblock as follows:

    import { InnerBlocks } from ‘@wordpress/block-editor’;

    export default function save() {
    return <InnerBlocks.Content />;
    }

    3) I changed the inner block’s save to return null:
    export default function Save() { return null; }

    4) I changed the PHP as follows, the comments explain what’s going on (I hope):

    
    <?php
    /**
     * Plugin Name:       Cards
     * Description:       A generic cards block
     * Requires at least: 5.9.3
     * Requires PHP:      7.0
     * Version:           0.1.0
     * Author:            Stephen Bugden
     * License:           GPL-2.0-or-later
     * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
     * Text Domain:       generic-cards
     *
     * @package           netmonics
     */
     
    function render_html($attributes, $content, $post) {
     
        $post = get_post($post_id);
    // = parse_blocks($post->post_content);
     
        ob_start(); ?>
     
            <!-- <h1>Attributes<?php echo esc_html(var_dump($attributes)) ?>!</h3>
            <h3>The number of columns is <?php echo esc_html($attributes['myColumns']) ?>!</h3>
            <h2>The content is:</h2><p><?php echo esc_html($content) ?>!</p>
            <h2>The content is </h2><p><?php echo esc_html(get_the_content()) ?>!</p>
            <h2>The content is </h2><p><?php echo var_dump(parse_blocks( get_the_content() )) ?>!</p>       
            <h2>The post is </h2><p><?php echo var_dump($post) ?>!</p>             -->
            <!-- Write out the block's content -->
            <h2>The content is </h2><p><?php echo esc_html(get_the_content()) ?>!</p>
           <?php 
            
            // $parsed_blocks = parse_blocks($post->post_content);
            // echo '<pre><h2>parsed blocks </h2>';
            // print_r($content);
            // echo '</pre>';
     
        //Load the block's content
        $dom1 = new DOMDocument;
        $dom1->loadHTML(get_the_content());
        $xpath1 = new DOMXpath($dom1);
     
        echo "<h1>Comments</h1>";
        //Get the comments
        $comments = $xpath1->query('.//comment()', $dom1);
     
        //Filter out the the comments for the InnerBlocks
        $commentPrefix = "wp:netmonics/generic-card {";
        $JSON = "";
        foreach($comments as $comment){
            if (substr( trim($comment->nodeValue.PHP_EOL), 0, strlen($commentPrefix) ) === $commentPrefix) {
                //Add a comma to the end of each line except for the last line
                if ($JSON !== "") {
                    $JSON = $JSON . ",";
                }
                //Retrieve the JSON from the comment
                $JSON .= substr( $comment->nodeValue.PHP_EOL,strlen($commentPrefix), strlen($comment->nodeValue.PHP_EOL) - strlen($commentPrefix) - 3 );
            }
        }
     
        //Create an array for the details
        $JSON = '{"card-details": [' . $JSON . ']}';
        echo $JSON;
     
        //Create a JSON object from the JSON string
        $decoded_json = json_decode($JSON, true);
        $cardDetails = $decoded_json['card-details'];
        echo "<br><br>";
     
        //Loop through the JSON write out the details.
        foreach($cardDetails as $cardDetail) {
            echo 'Name: ' . $cardDetail['name'] . "<br>";
            echo 'Bio: ' . $cardDetail['bio'] . "<br>";
            echo 'Description: ' . $cardDetail['description'] . "<br>";
            
     
            $socialLinks = $cardDetail['socialLinks'];
            if (!is_null($socialLinks))
            {
                if (!empty($socialLinks)) {
                    // list is not empty.
                    echo "<br>";
     
                    foreach($socialLinks as $socialLink)
                    {
                            echo '&nbsp;&nbsp;icon:' . $socialLink['icon'] . "<br>";
                            echo '&nbsp;&nbsp;link:' . $socialLink['link'] . "<br>";
                            echo "<br>";
                    }
                }
            }
            echo "<br>";
        }
     
        return ob_get_clean();
    }
     
     
    function cards_init() {
       register_block_type_from_metadata( __DIR__, array(
           'render_callback' => 'render_html'
       ) );
    }
     
     
    add_action( 'init', 'cards_init' );
    

    See the content contains the JSON for the innerblocks:

    The content is

    
    <!– wp:block {"ref":4939} /–> <!– wp:block {"ref":6275} /–> <!– wp:kadence/rowlayout {"uniqueID":"_0bfc30-08","columns":1,"colLayout":"equal","inheritMaxWidth":true} –> <div class="wp-block-kadence-rowlayout alignnone"><div id="kt-layout-id_0bfc30-08" class="kt-row-layout-inner kt-layout-id_0bfc30-08"><div class="kt-row-column-wrap kt-has-1-columns kt-gutter-default kt-v-gutter-default kt-row-valign-top kt-row-layout-equal kt-tab-layout-inherit kt-m-colapse-left-to-right kt-mobile-layout-row kb-theme-content-width"><!– wp:kadence/column {"uniqueID":"_3ab532-7c"} –> <div class="wp-block-kadence-column inner-column-1 kadence-column_3ab532-7c"><div class="kt-inside-inner-col"><!– wp:netmonics/generic-cards –> <!– wp:netmonics/generic-card {"name":"Phil","bio":"bio","id":10676,"url":"https://netmonics6.local/wp-content/uploads/2022/05/Phil-14.jpg","socialLinks":[{"icon":"facebook","link":"https://facebook.com"},{"icon":"twitter","link":"https://twitter.com"}]} /–> <!– wp:netmonics/generic-card {"name":"Robert","bio":"bio","id":10679,"url":"https://netmonics6.local/wp-content/uploads/2022/05/Robert-8.jpg"} /–> <!– wp:netmonics/generic-card {"name":"Steve","bio":"bio","id":10680,"url":"https://netmonics6.local/wp-content/uploads/2022/05/Steve-Not-Despeckled-4.jpg"} /–> <!– /wp:netmonics/generic-cards –></div></div> <!– /wp:kadence/column –></div></div></div> <!– /wp:kadence/rowlayout –>!
    

    The JSON strings combined into an array:

    Comments

    
    {“card-details”: [{“name”:”Phil”,”bio”:”bio”,”id”:10676,”url”:”https://netmonics6.local/wp-content/uploads/2022/05/Phil-14.jpg”,”socialLinks”:[{“icon”:”facebook”,”link”:”https://facebook.com”},{“icon”:”twitter”,”link”:”https://twitter.com”}]} ,{“name”:”Robert”,”bio”:”bio”,”id”:10679,”url”:”https://netmonics6.local/wp-content/uploads/2022/05/Robert-8.jpg”} ,{“name”:”Steve”,”bio”:”bio”,”id”:10680,”url”:”https://netmonics6.local/wp-content/uploads/2022/05/Steve-Not-Despeckled-4.jpg”} ]}
    

    The values extracted from the JSON object:

    Name: Phil
    Bio: bio
    Description:
    icon:facebook
    link:https://facebook.com
    icon:twitter
    link:https://twitter.com

    Name: Robert
    Bio: bio
    Description:

    Name: Steve
    Bio: bio
    Description:

    So now I have the attributes stored as JSON. The save can be rewritten as PHP so now changes appear instantly without having to refresh each instance of the block and changes to the HTML won’t break the block.

    I did get stuck for a while because I didn’t realise that the innerblock was registered with the same name as another block. This meant that my changes weren’t picked up and it took me a while to realise what was going on. That explains why I wasn’t seeing the JSON in the content, as commented on above.

    I hope this all makes sense. Finally, my dream of creating blocks which update on the fly and don’t easily break seems possible.

    Best Regards,

    Steve

    • This reply was modified 4 years ago by Yui.
    • This reply was modified 4 years ago by Yui. Reason: formatting
    Thread Starter Steve

    (@bugdens)

    I’ve tried modifying the function to include the $content variable:

    function render_html($attributes, $content) {
    	
    	ob_start(); ?>
     	  <h1>Attributes<?php echo esc_html(var_dump($attributes)) ?>!</h3>
     	  <h3>The number of columns is <?php echo esc_html($attributes['myColumns']) ?>!</h3>
    	   <h2>The content is:</h2><p><?php echo esc_html($content) ?>!</p>
    	   <h2>The content is </h2><p><?php echo esc_html(get_the_content()) ?>!</p>
    	   <h2>The content is </h2><p><?php echo var_dump(parse_blocks( get_the_content() )) ?>!</p>
    	   
    	   
     	  <?php 
    	   return ob_get_clean();
    }

    But I don’t see the attributes in the output.

    I’ve defined the attributes as follows:

    attributes: {
    		name: {
    			type: 'string',
    		},
    		bio: {
    			type: 'string',
    		},
    		id: {
    			type: 'number',
    		},
    		alt: {
    			type: 'string',
    			default: '',
    		},
    		url: {
    			type: 'string',
    		},
    		description: {
    			type: 'string',
    		}

    So as I don’t use the source as ‘html’ I thought that meant the values would be stored separately in a JSON block.

    I’m stuck for what to try next. Can anyone please help?

    If my question isn’t clear, please let me know, I can try to clarify my explanations.

    Best Regards,

    Steve

    Thread Starter Steve

    (@bugdens)

    Thank you to @dranand220 for replying to me, I received an email but can’t see any way to respond in this thread.

    Thread Starter Steve

    (@bugdens)

    Does it perhaps mean:

    save: () => {
          return <InnerBlocks.Content />
    }

    I’ve tried this and it doesn’t make any difference to the attributes, I only get the top level not the attributes from the innerblocks.

    Thread Starter Steve

    (@bugdens)

    I was just reading this:
    https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/

    It says that the save function should return null, so I’ve changed it as follows:

    export default function save({ attributes }) {
    	return null;
    }

    It also says:
    If you are using InnerBlocks in a dynamic block you will need to save the InnerBlocks in the save callback function using <InnerBlocks.Content/>

    I assume this means in the PHP callback function, in my case from the code above that would be inside the ‘render_html()’ function. Just don’t know how to apply <InnerBlocks.Content/> to that function.

    Anyone got any ideas? No idea if this would make the attributes accessible though.

    Steve

    Thread Starter Steve

    (@bugdens)

    Resolved!

    Thread Starter Steve

    (@bugdens)

    OK sure will do, sorry didn’t realise I should do that.

    Thank you once again.

Viewing 15 replies - 16 through 30 (of 44 total)