Support » Developing with WordPress » Gutenberg issue

  • I am a plugin developer and i made several custom blocs for the gutenberg editor.
    Everything works correctly, including the preview in the editor, until the published page is re-opened in the editor: I get the error message:

    This page contains unexpected or invalid content and the two buttons ‘Resolve’ and ‘Convert to HTML’

    The block definition of one of my custom blocks is:

    function wppa_gutenberg_photo_block() {
    
        wp_register_script(
            'wppa-gutenberg-photo',
            plugins_url( 'js/wppa-gutenberg-photo.js', __FILE__ ),
            array( 'wp-blocks', 'wp-element' )
        );
    
        register_block_type( 'wppa/gutenberg-photo', array(
            'editor_script' => 'wppa-gutenberg-photo',
        ) );
    }
    add_action( 'init', 'wppa_gutenberg_photo_block' );
    

    The content of the page as seen by the classic editor is:

    <!-- wp:wppa/gutenberg-photo -->
    <p>[photo 102]</p>
    <!-- /wp:wppa/gutenberg-photo -->
    

    It looks as if Gutenberg suddely forgot that my blocktype wppa/gutenberg-photo exists…

    I now added this code, to ‘manually’ change wppa/gutenberg-photo into wp:shortcode as if it were a wp shortcode:

    // Fix Gutenberg bug
    function wppa_fix_gutenberg_shortcodes() {
    global $wpdb;
    
    	if ( strpos( $_SERVER['REQUEST_URI'], '/wp-admin/post.php' ) !== false &&
    		 strpos( $_SERVER['REQUEST_URI'], 'action=edit' ) !== false ) {
    
    		$post = strval( intval ( $_GET['post'] ) );
    
    		// Get posts with wppa block_categories
    		$posts = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->posts
    													  WHERE ID = %d
    													  AND ( post_content LIKE %s
    													  OR post_content LIKE %s )",
    													  $post,
    													  '%' . $wpdb->esc_like( 'wp:wppa/gutenberg-photo' ) . '%',
    													  '%' . $wpdb->esc_like( 'wp:wppa/gutenberg-wppa' ) . '%' ), ARRAY_A );
    
    		if ( ! empty( $posts ) ) {
    			foreach( $posts as $post ) {
    				$new_content = str_replace( array( 'wp:wppa/gutenberg-photo', 'wp:wppa/gutenberg-wppa' ), 'wp:shortcode', $post['post_content'] );
    				$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts
    											   SET post_content = %s
    											   WHERE ID = %d", $new_content, $post['ID'] ) );
    			}
    		}
    	}
    }
    add_action( 'admin_init', 'wppa_fix_gutenberg_shortcodes' );
    

    Now the error disappears.
    This is obviously a workaround. I tried to declare my blocktype as shortcode but that conflicts with the generic wp shortcode blocktype.

    What am i doing wrong?

Viewing 6 replies - 1 through 6 (of 6 total)
  • Hi Jacob!

    Did you edit the save function multiple times? Have you tried removing the old block, then add it again? It’s possible that the error occurs because the behavior of the save function has been altered.

    // https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#validation-faq

    // https://developer.wordpress.org/block-editor/developers/block-api/block-deprecation/

    I’ve changed my block’s save behavior and old content now includes invalid blocks. How can I fix this?

    Refer to the guide on Deprecated Blocks to learn more about how to accommodate legacy content in intentional markup changes.

    Hope that helps.

    Best Regards,
    Ismael

    Thread Starter Jacob N. Breetvelt

    (@opajaap)

    Thanx for your reply.

    It is certainly not a deprepreciation issue because it happens right away after:
    new page -> add block -> save -> view page -> edit page.

    This triggered me (from the faq article):

    A block is invalid if its regenerated markup does not match what is saved in post content, so often this can be caused by the attributes of a block being parsed incorrectly from the saved content.

    This simplifies my question into:

    In what var or returned by what function do i get the saved content of the block when i re-edit an existing paage?

    FYI the block definiotion:

    // Actions on dom ready
    jQuery(document).ready(function(){
    
     // Register our block
     wppaPhotoRegisterBlockType( 'wppa/gutenberg-photo', {
    
      title:   'WPPA Photo',
      icon:   el( 'img',
          {
           src:  wppaImageDirectory+'camera32.png',
           style:  wppaPhotoDialogIconStyle,
          } ),
      category:  'wppa-shortcodes',
      edit:   function( props ) {
    
          var shortcode = props.attributes.shortcode || '';
          var photo = props.attributes.photo || '';
    
          if ( photo.length ) {
           var id = parseInt( 1000 * Math.random() );
           wppaGutenbergGetPhotoShortcodeRendered( shortcode, id );
           return el( 'div', {id:id} , 'Loading...' );
          }
          else {
           var Uid = 'wppa-photo-dialog-' + wppaPhotoDialogCounter;
           wppaPhotoDialogCounter++;
           wppaPhotoDialog = el( 'div', { id: Uid, style: wppaPhotoDialogBlockStyle }, 'placeholder' );
           setTimeout( function() {
            jQuery( '#' + Uid ).html( wppaPhotoDialogHtml );
           }, 100 );
           setTimeout( function() {
    
            // Bind onchange handler to ready button
            jQuery( '#wppa-shortcode-photo-ready' ).on( 'click',
             function() {
              var res = wppaPhotoEvaluate(),
               sc = res.shortcode,
               photo = res.photo;
    
              if ( sc.length ) {
               props.setAttributes({
                shortcode: sc,
                photo: photo
               });
              }
             });
           }, 150 );
           return wppaPhotoDialog;
          }
         },
      save:   function( props ) {
    
          var shortcode = props.attributes.shortcode || '';
    
          if ( shortcode.length ) {
           return shortcode;
          }
         },
     } );
    

    Full source in https://downloads.wordpress.org/plugin/wp-photo-album-plus.7.3.05.010.zip
    file: /js/wppa-gutenberg-photo.js

    Thread Starter Jacob N. Breetvelt

    (@opajaap)

    Additional info:

    The console log tells me:

    Block validation: Expected end of content, instead saw  
    Object { type: "Chars", chars: "[photo 104]" }  . blocks.js:7992:21
    Block validation: Block validation failed for 'wppa/gutenberg-photo' ( 
    Object { name: "wppa/gutenberg-photo", icon: {…}, attributes: {…}, keywords: [], save: save(props), title: "WPPA Photo", category: "wppa-shortcodes", edit: edit(props)
     }
     ).
    
    Content generated by 'save' function:
    

    When i log this in the save proc right after opening the page in the editor:
    console.log('content is now: '+props.attributes.content);
    i get:
    content is now: undefined

    I have the feeling that i am close…

    Thread Starter Jacob N. Breetvelt

    (@opajaap)

    If i had the content of the block, in the example above: [photo 102] in a var, i could fill the dialog with the appropriate info by reverse engineering, so the outcome of wppaPhotoEvaluate() would be consistent with the existing value and return this in the save function.

    Unfortunately i can not find in the documentation how to retrieve the content of the block in a var, what should be quite simple. I checked props, props.attributes …. nothing.

    Please help me

    Hi!

    Thank you for the clarification.

    I think the issue lies on the save function because it is returning a shortcode instead of an instance of a wp element. And because of this the editor recognizes it as a shortcode and automatically converts it to a shortcode block.

    Have you tried creating a dynamic block instead, or use the render_callback?

    // https://developer.wordpress.org/block-editor/tutorials/block-tutorial/creating-dynamic-blocks/

    Please review the save function.

    // https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#save

    For most blocks, the return value of save should be an instance of WordPress Element representing how the block is to appear on the front of the site.

    If there is a need to have other information as part of the save, developers can consider one of these two alternatives:
    – Use dynamic blocks and dynamically retrieve the required information on the server.
    – Store the external value as an attribute which is dynamically updated in the block’s edit function as changes occur.

    Best Regards,
    Ismael

    Thread Starter Jacob N. Breetvelt

    (@opajaap)

    Returning a wp element is not a good idea because it implies a html tag.
    There are various reasons why i do not want that. e.g.: https://wppa.nl/docs-by-subject/slideshow-array/

    I also do not want to save the front-end rendered html, because it can change when e.g. the generated shortcode is something like
    [wppa type="slide" album="#lasten,4.6..7,12" cache="inf" delay="yes"]
    (as generated by my other shortcode generator) and photos or comments are added.

    I did some testing with the simpler [photo nnn] shortcode generator, and, once i should have the content in a string like [photo 104] i only need to add a few lines to the edit and save functions to get the shortcode generator dialog re-opend with the current settings:

    in the edit function right before // Bind onchange handler to ready button:
    (using ‘#photo-104’ instead of the value derived from the existing block content)

    // Select the old value
    jQuery( '#photo-104' ).prop( 'selected', true );
    wppaPhotoEvaluate();

    and in the save function added the else{} condition (using ‘[photo 104]’ instead of the so eagerly wanted var with this text being the existing block content when re-editing):

    if ( shortcode.length ) {
      return shortcode;
    }
    else {
      return '[photo 104]';
    }

    In this situation, when re-editing the page, the dialog re-appears with the values selected as before, so the user can change his mind and select a different photo afterall. And no errormessage on the console!

    If it is too complex to simply make the content of the block available in the code, i will revert back to the situation where i change the blocktype through the backdoor to 'wp:shortcode' and therefor not having the feature of re-opening the dialog when the page is re-edited.

Viewing 6 replies - 1 through 6 (of 6 total)
  • The topic ‘Gutenberg issue’ is closed to new replies.