古腾堡在保存时删除 table 标签

Gutenberg removing table tag on save

我正在尝试创建一个古腾堡块来跟踪练习集。我正在使用 RichText 组件来允许用户编辑我为他们预先填充的 table 中的默认值。

该块在编辑器上运行良好,保存后在 post 中正确呈现。但是,当我重新加载编辑器时,我收到此错误消息:Block validation: Expected tag name 'thead', instead saw 'table'. 这几乎就像 Gutenberg 正在剥离 table 标签但保留其他所有内容。

当然,这没有意义,但我不确定它还能是什么。

这是我的代码,经过大量编辑以提高可读性:

const { registerBlockType } = wp.blocks;
const { AlignmentToolbar, BlockAlignmentToolbar, BlockControls, RichText, useInnerBlockProps } = wp.blockEditor;
const { Component } = wp.element;

registerBlockType('bsd-strong-post/training-session', {
  title: __('Strong Post', 'bsd-strong-post'),
  description: __('Provides a short summary of a training session', 'bsd-strong-post'),
  category: 'common',
  icon: blockIcons.weight_lifting,
  keywords: [    
    __('strength workout', 'bsd-strong-post'),
    __('strong', 'bsd-strong-post'),
    __('training', 'bsd-strong-post')
  ],
  supports: {
    html: true
  },
  attributes: {
    /* ... */,
    dayTemplateContent: {
      type: 'string',
      source: 'html',
      selector: '.bsd-strong-post-training-template'
    },
    /* ... */
  },
  /* ... */
  edit: class extends Component {
    constructor(props) {
      super(...arguments);
      this.props = props;

      /* ... */

      this.dayTemplateHandler = this.dayTemplateHandler.bind(this);
      this.onChangeBlockTemplate = this.onChangeBlockTemplate.bind(this);
    }

    /* ... */

    dayTemplateHandler(new_val) { 
      const dayTemplateList = this.state.dayTemplateList;
      
      let selectedDayTemplate = dayTemplateList.filter(item => {
        return item.value == new_val;
      })

      if (selectedDayTemplate[0]['label']) {
        this.props.setAttributes({ 
          dayTemplateId: new_val,
          dayTemplateName: selectedDayTemplate[0]['label']
        });
      }

      this.getTemplate(new_val);
    }

    getTemplate(templateId) {
      api.getDayTemplate(templateId)
      .then((data) => {
        
        if (!data.status || data.status == 0) {
          return false;
        };

        if (!data.day_template) {
          return false;
        };

        this.props.setAttributes({ 
          dayTemplateContent: data.day_template.template_content          
        });

        return data.day_template;
      }).catch((err) => {
        console.log('getTemplate caught error')
        return false;
      });
    }

    onChangeBlockTemplate(value) {
      this.props.setAttributes({
        dayTemplateContent: value
      });
    }

    /* ... */

    render() {
      const { dayTemplateHandler, onChangeBlockTemplate, phaseControlHandler, programControlHandler, updateBlockAlignment, updateTextAlignment } = this;
      const { block_alignment, dayTemplateId, dayTemplateName, dayTemplateContent, phaseId, phaseName, programAuthor, programId, programName, programPhases, text_alignment } = this.props.attributes;

      /* ... */

      return [
        <InspectorControls>
          <PanelBody title={ __('Basics', 'bsd-strong-post') }>
              <SelectControl
                label={ __('Day', 'bsd-strong-post') }
                help={ __('The training session (e.g., Day One)', 'bsd-strong-post') }
                value={ dayTemplateId }
                options={ this.state.phaseTemplates }
                onChange={ dayTemplateHandler }
              />  
            }
          </PanelBody>
        </InspectorControls>,
        <div className='bsd-strong-post-block-editor'>
          <div className={ this.props.className }>
            <RichText
              placeholder={ __('Log your lifts here') }
              value={ dayTemplateContent }
              multiline={ false }
              onChange={ onChangeBlockTemplate }
              className='bsd-strong-post-training-log'
            />
          </div>
        </div>
      ];
    } 
  },

  save: (props) => {
    return (
      <div className={ `align${props.attributes.block_alignment}` }>
        <ul className='list-unstyled'style={{ textAlign: props.attributes.text_alignment }}>
          <li>
            <strong>{ __('Program', 'bsd-strong-post') }: </strong> 
            <span className='bsd-strong-post-program'>{ props.attributes.programName }</span>
          </li>
          <li>
            <strong>{ __('Phase', 'bsd-strong-post') }: </strong> 
            <span className='bsd-strong-post-phase-ph'>{ props.attributes.phaseName }</span>
          </li>
          <li>
            <strong>{ __('Day', 'bsd-strong-post') }: </strong> 
            <span className='bsd-strong-post-day-ph'>{ props.attributes.dayTemplateName }</span>
          </li>
          <li>
            <strong>{ __('Author', 'bsd-strong-post') }: </strong> 
            <span className='bsd-strong-post-author-ph'>{ props.attributes.programAuthor }</span>
          </li>
        </ul>        
        <RichText.Content
          value={ props.attributes.dayTemplateContent }
          className='bsd-strong-post-training-log'            
        />        
      </div>
    )
  }
});

这是重新加载时的控制台输出:

Content generated by 'save' function:

<div class="wp-block-bsd-strong-post-training-session alignwide"><ul class="list-unstyled"><li><strong>Program: </strong><span class="bsd-strong-post-program">Madcow</span></li><li><strong>Phase: </strong><span class="bsd-strong-post-phase-ph">Intermediate</span></li><li><strong>Day: </strong><span class="bsd-strong-post-day-ph">Day 1</span></li><li><strong>Author: </strong><span class="bsd-strong-post-author-ph">Madcow</span></li></ul>        
        <thead>
            <tr>
                <th scope="col">Exercise</th>
                <th scope="col">Set 1</th>
                <th scope="col">Set 2</th>
            </tr>
        </thead>
        <tbody>
            <tr class="bsd-strong-post-exercise-one">
                <td class="bsd-strong-post-exercise-name">Squat</td>
                <td class="bsd-strong-post-set-1">95 x 5</td>
                <td class="bsd-strong-post-set-2">135 x 5</td>
            </tr>
        </tbody>
    </div>

Content retrieved from post body:

<div class="wp-block-bsd-strong-post-training-session alignwide"><ul class="list-unstyled"><li><strong>Program: </strong><span class="bsd-strong-post-program">Madcow</span></li><li><strong>Phase: </strong><span class="bsd-strong-post-phase-ph">Intermediate</span></li><li><strong>Day: </strong><span class="bsd-strong-post-day-ph">Day 1</span></li><li><strong>Author: </strong><span class="bsd-strong-post-author-ph">Madcow</span></li></ul><table class='bsd-strong-post-training-template'>       
        <thead>
            <tr>
                <th scope='col'>Exercise</th>
                <th scope='col'>Set 1</th>
                <th scope='col'>Set 2</th>
            </tr>
        </thead>
        <tbody>
            <tr class='bsd-strong-post-exercise-one'>
                <td class='bsd-strong-post-exercise-name'>Squat</td>
                <td class='bsd-strong-post-set-1'>95 x 5</td>
                <td class='bsd-strong-post-set-2'>135 x 5</td>
            </tr>
        </tbody>
    </table></div>

我可以看到 Content generated by 'save' function: 下方显示的内容缺少 <table></table> 标签。我试图通过在 save 函数内的 RichText.Content 属性中添加 tagName='table' 来解决这个问题,但随后控制台显示重复的 <table></table> 标记.

编辑: 当用户对 InspectorControls 中的 Select 控件进行更改时,将填充 table。此操作调用 dayTemplateHandler,其中调用 getTemplate,一个从数据库获取 table 内容的函数。这是该输出的示例 (data.day_template.template_content):

<table class='bsd-strong-post-training-template'>       
        <thead>
            <tr>
                <th scope='col'>Exercise</th>
                <th scope='col'>Set 1</th>
                <th scope='col'>Set 2</th>
            </tr>
        </thead>
        <tbody>
            <tr class='bsd-strong-post-exercise-one'>
                <td class='bsd-strong-post-exercise-name'>Squat</td>
                <td class='bsd-strong-post-set-1'>95 x 5</td>
                <td class='bsd-strong-post-set-2'>135 x 5</td>
            </tr>
        </tbody>
    </table>

查看 table 模板并考虑错误,我怀疑问题出在 dayTemplateContent 属性的选择器上,.bsd-strong-post-training-template

第一次保存内容时,它成功地从数据库中加载了模板数据并保存了完整的table结构。重新加载内容时,块验证器失败,因为 dayTemplateContent 的选择器读取 table 的 css 选择器(即 thead)的子节点并且与预期不匹配内容。参考:HTML example of blockquote/paragraphs

尝试用 <div class="bsd-strong-post-training-template"> 包装 <table> 模板或更改选择器。