是否以编程方式删除古登堡区块?

时间:2019-12-04 作者:Brian

我想知道什么是以编程方式删除古腾堡块的好方法。

我有一个自定义的内容类型,我可以通过React和WP API添加的选择字段选择论坛帖子。然后将此帖子的标题和描述添加到帖子内容中。

以下是块:

/**
 * BLOCK: my-forum-block
 *
 * Registering a basic block with Gutenberg.
 * Simple block, renders and saves the same content without any interactivity.
 */

//  Import CSS.
import \'./editor.scss\';
import \'./style.scss\';

const { __ } = wp.i18n; // Import __() from wp.i18n
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
const { InspectorControls } = wp.editor;
const { SelectControl } = wp.components;
const { Component } = wp.element;

class mySelectPosts extends Component {
    // Method for setting the initial state.
    static getInitialState( selectedPost ) {
        return {
            posts: [],
            selectedPost: selectedPost,
            post: {},
        };
    }
    // Constructing our component. With super() we are setting everything to \'this\'.
    // Now we can access the attributes with this.props.attributes
    constructor() {
        super( ...arguments );
        this.state = this.constructor.getInitialState( this.props.attributes.selectedPost );
        // Bind so we can use \'this\' inside the method.
        this.getOptions = this.getOptions.bind(this);
        // Load posts.
        this.getOptions();
        // bind it
        this.onChangeSelectPost = this.onChangeSelectPost.bind(this);
    }

    onChangeSelectPost( value ) {
        // Find the post
        const post = this.state.posts.find( ( item ) => { return item.id == parseInt( value ) } );
        //console.log(\'this post\');
        //console.log(post);
        // Set the state
        this.setState( { selectedPost: parseInt( value ), post } );
        // Set the attributes
        this.props.setAttributes( {
            selectedPost: parseInt( value ),
            title: post.title.rendered,
            content: post.content.rendered,
            link: post.link,
            due_date: post.due_date,
            slug: post.slug,
        });
    }

    /**
     * Loading Posts
     */
    getOptions() {

        const CustomPost = wp.api.models.Post.extend( {
            urlRoot: wpApiSettings.root + \'wp/v2/topic\',
            defaults: {
                type: \'topic\',
            },
        } );
        const CustomPosts = wp.api.collections.Posts.extend( {
            url: wpApiSettings.root + \'wp/v2/topic\',
            model: CustomPost,
        } );
        const someCustomPosts = new CustomPosts();
        /* someCustomPosts.fetch().then( ( posts ) => {
            // do something with the custom posts
        } ); */

        return ( someCustomPosts ).fetch({ data: { \'filter\': { \'orderby\': \'title\', \'order\': \'ASC\' } } }).then( ( posts ) => {
                if( posts && 0 !== this.state.selectedPost ) {
            // If we have a selected Post, find that post and add it.

            const post = posts.find( ( item ) => { return item.id == this.state.selectedPost } );
            // This is the same as { post: post, posts: posts }
            this.setState( { post, posts } );
            } else {
                this.setState({ posts });
            }
        } );
    }

    render() {
        let options = [ { value: 0, label: __( \'Select a Post\' ) } ];
        let output  = __( \'Loading Posts\' );
        if( this.state.posts.length > 0 ) {
            const loading = __( \'We have %d posts. Choose one.\' );
            output = loading.replace( \'%d\', this.state.posts.length );
            this.state.posts.forEach((post) => {
                options.push({value:post.id, label:post.title.rendered});
        });
        } else {
            output = __( \'No posts found. Please create some first.\' );
        }
        // Checking if we have anything in the object
        if( this.state.post.hasOwnProperty(\'title\') ) {
            output = <div className="post">
                <a href={ this.state.post.link }><h2 dangerouslySetInnerHTML={ { __html: this.state.post.title.rendered } }></h2></a>
            <p dangerouslySetInnerHTML={ { __html: this.state.post.content.rendered } }></p>
            </div>;
            this.props.className += \' has-post\';
        } else {
            this.props.className += \' no-post\';
        }
        return [
            !! this.props.isSelected && ( <InspectorControls key=\'inspector\'>
                <SelectControl onChange={this.onChangeSelectPost} value={ this.props.attributes.selectedPost } label={ __( \'Select a Post\' ) } options={ options } />
            </InspectorControls>
    ),
    <div className={this.props.className}>{output}</div>
    ]
    }
}

/**
 * Register: aa Gutenberg Block.
 *
 * Registers a new block provided a unique name and an object defining its
 * behavior. Once registered, the block is made editor as an option to any
 * editor interface where blocks are implemented.
 *
 * @link https://wordpress.org/gutenberg/handbook/block-api/
 * @param  {string}   name     Block name.
 * @param  {Object}   settings Block settings.
 * @return {?WPBlock}          The block, if it has been successfully
 *                             registered; otherwise `undefined`.
 */
registerBlockType( \'cgb/block-my-forum-block\', {
    // Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
    title: __( \'Choose LearnDash Forum Topic\' ),
    icon: \'shield\', 
    category: \'common\',
    keywords: [
        __( \'learndash\' ),
        __( \'forum\' ),
        __( \'my-forum-block\' ),
    ],

    attributes: {
        content: {
            type: \'array\',
            source: \'children\',
            selector: \'p\',
        },
        title: {
            type: \'string\',
            selector: \'h3\'
        },
        link: {
            type: \'string\',
            selector: \'a\'
        },
        selectedPost: {
            type: \'number\',
            default: 0,
        },
        due_date: {
            type: \'string\',
        },
        slug: {
            type: \'string\',
        },
    },

    /**
     * The edit function describes the structure of your block in the context of the editor.
     * This represents what the editor will render when the block is used.
     *
     * The "edit" property must be a valid function.
     *
     * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
     *
     * @param {Object} props Props.
     * @returns {Mixed} JSX Component.
     */
    edit: mySelectPosts,

    /**
     * The save function defines the way in which the different attributes should be combined
     * into the final markup, which is then serialized by Gutenberg into post_content.
     *
     * The "save" property must be specified and must be a valid function.
     *
     * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
     *
     * @param {Object} props Props.
     * @returns {Mixed} JSX Frontend HTML.
     */
    save: function( props ) {
        return (
                <div id = {`${props.attributes.slug}`} className="contenttype-wrapper sometopictype-discussion" data-id = {`${props.attributes.selectedPost}`}>
                    <div className = "heading d-flex flex-row">
                        <i className="contenticon fas fa-users fa-7x"></i>
                        <div className = "col">
                            <div className = "row required-discussion-text"><span className="content-name">Required Discussion&nbsp;&nbsp;&nbsp; <i class="far fa-calendar-alt"></i>&nbsp;&nbsp;&nbsp;Due: {props.attributes.due_date}</span></div>
                            <div className = "row"><a href={ props.attributes.link }><h3 dangerouslySetInnerHTML={ { __html: props.attributes.title } }></h3></a></div>
                        </div>
                    </div>
                    <div className = "row discussion-overview" dangerouslySetInnerHTML={ { __html: props.attributes.content } } ></div>
                </div>
        );
    },
} );
但如果我删除了论坛帖子,那么该块也应该被删除。我想我可以阅读自定义帖子的内容并使用PHPxpath 解析该块,然后将其删除,但想知道是否还有其他方法,特别是因为PHP的DOM相关函数在看到意外标记时可能会崩溃。

我了解了WP Rest API以及块本身是如何作为端点的。这让我有点困惑。这让我想到,如果块有端点,这是否意味着我可以通过API调用删除块?或者,这些端点是否仅用于块类型(如“布局我的布局块”),而不用于渲染块?

谢谢Brian

Edit:

添加的块代码

1 个回复
SO网友:WebElaine

对于最初的方法,当您删除论坛帖子时,搜索数据库并删除引用该特定帖子的任何块,看起来实现这一点的唯一方法是使用正则表达式,它可能会在将来的更新中中断。

你可以钓到delete_post 钩住,验证删除的帖子是“论坛”帖子,然后获取所有可能包含论坛块的帖子,循环浏览它们,然后parse_blocks() 因此,您可以检查当前帖子是否包含以论坛帖子ID为属性的论坛块。

但是,在这个过程出现故障的地方,我们目前没有serialize_blocks() 函数将块转换回HTML注释。(他们正在讨论adding one in Trac 但它还没有准备好。)因此,即使您可以识别包含要查找的块的所有帖子,您也必须创建一个正则表达式来更新实际的post_content 在这些职位中。

值得一提的是,以下是代码:

<?php
add_action(\'delete_post\', \'wpse_delete_forum_blocks\', 10, 1);
// The forum post ID is the only argument
function wpse_delete_forum_blocks($post_id) {
    $post_type = get_post_type($post_id);
    // Only run this code if the deleted post was a "forum" CPT
    if($post_type == \'forum\') {
        // Get all posts that may contain the forum block
        // Arguments are up to you - perhaps only a specific post type can contain it
        $check_posts = get_posts(
            array(
                // Get all posts
                \'numberpost\' => -1
                // Get "post" post type / adjust as needed
                \'post_type\' => \'post\'
            )
        );
        // Loop through all the posts
        foreach($check_posts as $post) {
            // If the post has blocks
            if(has_blocks($post->post_content)) {
                // Parse the blocks
                $blocks = parse_blocks($post->post_content);
                // Loop through the blocks
                foreach($blocks as $block) {
                    // If this is a "forum" block, and its "post_id" attribute matches the id we\'re looking for
                    // (make sure to change this to your applicable namespace and block name)
                    if($block[\'blockName\'] === \'stmu/icon-heading\' && $block[\'attrs\'][\'post_id\'] === $post_id) {
                        // This is where you need to create a regular expression to remove just this block.
                    }
                }
            }
        }
    }
}
?>
同时,服务器端呈现允许您在找到帖子时显示帖子,或者在帖子不存在时不显示任何内容。

相关推荐