137
0

Hướng dẫn tạo block Gutenberg với dynamic content

137
gutenberg-1
Thời gian đọc: 4 phút

Chào mọi người đến với Series lập trình block Gutenberg trong WordPress. Series này giành cho những bạn thích Wordpess nhưng muốn tìm cảm giác làm theme, giao diện WordPress theo hướng mới mẻ không bị nhàm chán, thích làm giao diện trong CMS và trang web với React.

Với bài lần trước mình đã giới thiệu cách tạo Block Gutenberg đầu tiên. Thì bài viết này Hướng dẫn tạo block Gutenberg với dynamic content sẽ hướng dẫn các bạn từ block Gutenberg các bạn tạo ở bài trước sẽ thêm dynamic content, tùy chỉnh font-size, vân vân và mây mây…

Dynamic content với Component RichText

Tiếp tục với file heading/index.jsx các bạn có thể tham khảo lại link này. Các bạn scroll lên đầu file import RichText vào block Heading.

import { RichText } from '@wordpress/editor'

Sau đó chúng ta cùng thêm thuộc tính attributes vào hàm constructor trong block heading

/*.........*/
class Heading extends Component {
    constructor(props) {
        super(props)
        this.data = {
            slug: 'themewa/heading',
            title: __('Heading', 'wa-gutenberg'),
            description: __('Heading create by Wolfactive', 'wa-gutenberg'),
            category: 'page-wolfactive',
            icon: (
                <svg width="1em" height="1em" viewBox="0 0 512 512">
                    <path
                        d="M448 96v320h32a16 16 0 0 1 16 16v32a16 16 0 0 1-16 16H320a16 16 0 0 1-16-16v-32a16 16 0 0 1 16-16h32V288H160v128h32a16 16 0 0 1 16 16v32a16 16 0 0 1-16 16H32a16 16 0 0 1-16-16v-32a16 16 0 0 1 16-16h32V96H32a16 16 0 0 1-16-16V48a16 16 0 0 1 16-16h160a16 16 0 0 1 16 16v32a16 16 0 0 1-16 16h-32v128h192V96h-32a16 16 0 0 1-16-16V48a16 16 0 0 1 16-16h160a16 16 0 0 1 16 16v32a16 16 0 0 1-16 16z"
                        fill="currentColor"
                    />
                </svg>
            ),
            keywords: [
                __('Heading', 'wa-gutenberg'),
                __('Wolf Active', 'wa-gutenberg'),
            ],
            attributes: {
                content: {
                    type: 'string',
                    source: 'html',
                    selector: 'p'
                },
            }
        }
    }

    /* ............. */
}
export default Heading

Tiếp theo mình phải sửa lại hàm edit trong block heading

edit(){
    return edit: ({ attributes, setAttributes}) => {
        const {content} = attributes;
                const onChangeContent = (content) =>{
                    setAttributes({content})
                }
        return(
               <RichText
                   tagName="p"
                   className="rich-text"
                   onChange={onChangeContent}
                   value={content}
                />

            )
        }
}

Ở đây mình tạo hàm onChangeContent để có thể dynamic content khi user nhập vào RichText. Sau khi đã chỉnh xong hàm edit. Chúng ta cùng qua chỉnh hàm save

save: ({attributes}) =>{
    const {content , alignment} = attributes;
        return (
             <RichText.Content
                  tagName="p"
                  value={content}
                  style={{textAlign : alignment}}
               />
         );
     }

Hàm Save sẽ lấy content được hàm edit setAttributes để lưu vào database của WordPress. Và bước cuối cùng là sửa lại hàm registerBlockType

init() {
    let { slug, title, description, category, icon, keywords,attributes } = this.data
        return registerBlockType(slug, {
            title: title,
            description: description,
            category: category,
            icon: icon,
            keywords: keywords,
            attributes: attributes,
            edit: this.edit(),
            save: this.save()
        })
    }

Và vậy là các bạn đã có thể nhập content bất kỳ và lưu vào database. Tuy nhiên dynamic content thôi thì cũng chưa đủ. Mình sẽ hướng dẫn các bạn thêm các tính năng khác như thay đổi font-size , canh chỉnh lề. Tuy nhiên trước tiên cần phải refactor lại code do file này đã quá dài heading/index.jsx
P/s: Các bạn có thể tìm hiêu hơn về RichText tại đây

Refactor code cho block Heading

Lượt sơ qua file heading/index.jsx thì có thể nhìn thấy hiện tại hàm edit đang rất dài nếu chúng ta thêm một số thuộc tính nữa sẽ còn dài thêm nên mình sẽ tách thành file riêng. Mình tạo file heading/edit.jsx và bắt đầu import các package cần thiết để sử dụng.

import { Component} from '@wordpress/element'
import {
    RichText,
} from '@wordpress/editor'
import { __ } from '@wordpress/i18n'

Copy và refactor code từ index.jsx sang edit.jsx

class EditHeading extends Component {
    constructor(props) {
        super(props)
        const { attributes } = this.props
        this.state = {
            attributes: attributes,
        }
    }

    onChangeContent = (content) => {
        this.props.setAttributes({ content })
    }
    render() {
        const { attributes } = this.props
        const { content} = attributes
        return (
                <RichText
                    tagName={'p'}
                    className="rich-text"
                    onChange={this.onChangeContent}
                    value={content}
                    placeholder={__('Enter Heading...', 'custom-block')}
                    keepPlaceholderOnFocus={true}
                />
        )
    }
}

export default EditHeading

Vào file index.jsx để sửa lại hàm edit

/*.........*/
import EditHeading from './edit'
/*.........*/
edit() {
        return EditHeading
    }

Vậy là chúng ta đã xong phần refactor code, tiếp tục đi đến phần thêm các tính năng như thay đổi font-size, canh chỉnh lề

Thêm component FontSizePicker và AlignmentToolbar vào block heading

Trong file edit.jsx chúng ta thêm các component cần thiết cho việc thêm chức năng

import {
    AlignmentToolbar,
    BlockControls,
    RichText,
    FontSizePicker,
    InspectorControls,
} from '@wordpress/editor'

Thêm các hàm cần thiết để bắt sự kiện change của các components

onChangeAlignment = (alignment) => {
        this.props.setAttributes({ alignment })
    }
    onChangeFontSize = (fontSize) => {
        this.props.setAttributes({ fontSize })
    }

Chỉnh lại một chút phần return về từ file edit.jsx

return (
            <>
                <BlockControls>
                    <AlignmentToolbar
                        value={alignment}
                        onChange={this.onChangeAlignment}
                    />
                </BlockControls>
                <InspectorControls>
                    <FontSizePicker
                        withSlider={true}
                        onChange={this.onChangeFontSize}
                    />
                </InspectorControls>
                <RichText
                    tagName={'p'}
                    className="rich-text"
                    onChange={this.onChangeContent}
                    value={content}
                    style={{ textAlign: alignment, fontSize: fontSize }}
                    placeholder={__('Enter Heading...', 'custom-block')}
                    keepPlaceholderOnFocus={true}
                />
            </>
        )

Sau đó chúng ta vào lại file index.jsx để chỉnh sửa lại attributes và hàm save

  • Thuộc tính attributes
    attributes: {
    content: {
    type: 'string',
    source: 'html',
    selector: 'p',
    },
    alignment: {
        type: 'string',
    },
    fontSize: {
        type: 'number',
    },
    },
  • Hàm save
    save() {
        return ({ attributes }) => {
            let { content, alignment, fontSize } = attributes
            return (
                <>
                    <RichText.Content
                        tagName="p"
                        value={content}
                        className="rich-text"
                        style={{ textAlign: alignment, fontSize: fontSize }}
                    />
                </>
            )
        }
    }

    Và đây là kết quả thu được
    gutenberg-voi-dynamic-content

    Tổng kết

    Với bài này mình đã hướng dẫn các bạn cách khai báo và tạo block Gutenberg với dynamic content và thêm một số tính năng như chình font-size, canh lề. Tuy nhiên nếu hàm edit va hàm save trả về các thẻ HTML không giống nhau dẫn đến lỗi sẽ xảy ra trong lần reload vảo edit của post tiếp theo. Qua bài sau mình sẽ hướng dẫn các bạn giải quyết issue này.
    Các bạn có thể tham khảo tổng quan về series tại đây
    Cảm ơn các bạn đã đón đọc. Các bạn có thắc mắc hay có vấn đề cần giải đáp thì hay inbox vào fanpage Wolfactive nhé.