Search code examples
phpwordpresswordpress-gutenberg

Making a WordPress Plugin that Adds a Gutenberg Block for Academic Article Abstracts And Keywords Using ChatGPT


I don't have much experience with WordPress development, so I asked ChatGPT to create a WordPress plugin that adds a new Gutenberg block that allows me to write Abstracts & Keywords in a box with a title and background color for a website that accepts academic articles.

ChatGPT gave me the following code, which activates but doesn't add a new Gutenberg block. Here's a description of the code:

1. Main Plugin PHP File:

<?php
/**
 * Plugin Name: Abstract and Keywords Block
 * Description: Adds a Gutenberg block for adding an abstract and keywords to an article
 * Version: 1.0
 * Author: Clevious
 * License: GPL2
 */

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Enqueue block editor only JavaScript and CSS
 */
function abstract_keywords_block_editor_assets() {
    // Make paths variables so we don't write em twice ;)
    $block_path = 'block.js';

    // Enqueue the bundled block JS file
    wp_enqueue_script(
        'abstract_keywords_block-editor-script', // script handle
        plugins_url( $block_path, __FILE__ ), // script url
        array( 'wp-blocks', 'wp-i18n', 'wp-element' ), // dependencies
        filemtime( plugin_dir_path( __FILE__ ) . $block_path ) // version
    );


    // Make paths variables so we don't write em twice ;)
    $style_path = 'editor.css';

    // Enqueue optional editor only styles
    wp_enqueue_style(
        'abstract_keywords_block-editor-css',
        plugins_url( $style_path, __FILE__ ),
        array( 'wp-blocks' ),
        filemtime( plugin_dir_path( __FILE__ ) . $style_path )
    );
}

// Hook scripts function into block editor hook
add_action( 'enqueue_block_editor_assets', 'abstract_keywords_block_editor_assets' );


/**
 * Register block
 */
function register_abstract_keywords_block() {

    // Register our block editor script
    wp_register_script(
        'abstract_keywords_block-editor-script',
        plugins_url( 'block.js', __FILE__ ),
        array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ),
        filemtime( plugin_dir_path( __FILE__ ) . 'block.js' )
    );

    // Register our block editor styles
    wp_register_style(
        'abstract_keywords_block-editor-css',
        plugins_url( 'editor.css', __FILE__ ),
        array( 'wp-edit-blocks' ),
        filemtime( plugin_dir_path( __FILE__ ) . 'editor.css' )
    );

    // Register our block
    register_block_type( 'abstract-keywords-block/block', array(
        'editor_script' => 'abstract_keywords_block-editor-script',
        'editor_style'  => 'abstract_keywords_block-editor-css',
    ) );
}

// Hook registration function into block init
add_action( 'init', 'register_abstract_keywords_block' );

/**

    Add custom CSS to the block
    */
    function abstract_keywords_block_custom_css() {
    $css = '.wp-block-abstract-keywords-block .title { color: #fff; background-color: #2508a5; }
    .wp-block-abstract-keywords-block .abstract-keywords-box { background-color: #fff; box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1); }';
    wp_add_inline_style( 'abstract_keywords_block-editor-css', $css );
    }
    add_action( 'enqueue_block_editor_assets', 'abstract_keywords_block_custom_css' );

?>

2. Block.js file:

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { RichText, MediaUpload } = wp.editor;

registerBlockType( 'abstract-keywords-block/block', {
    title: __( 'Abstract and Keywords' ),
    icon: 'list-view',
    category: 'common',
    attributes: {
        title: {
            type: 'string',
            source: 'html',
            selector: '.title'
        },
        abstract: {
            type: 'string',
            source: 'html',
            selector: '.abstract'
        },
        keywords: {
            type: 'string',
            source: 'html',
            selector: '.keywords'
        },
        image: {
            type: 'string',
            source: 'attribute',
            selector: 'img',
            attribute: 'src'
        }
    },
    edit: function( props ) {
        const { attributes: { title, abstract, keywords, image }, setAttributes } = props;

        const onChangeTitle = ( newTitle ) => {
            setAttributes( { title: newTitle } );
        };

        const onChangeAbstract = ( newAbstract ) => {
            setAttributes( { abstract: newAbstract } );
        };

        const onChangeKeywords = ( newKeywords ) => {
            setAttributes( { keywords: newKeywords } );
        };

        const onSelectImage = ( newImage ) => {
            setAttributes( { image: newImage.sizes.full.url } );
        };

        return (
            <div className={ props.className }>
                <RichText
                    tagName="h2"
                    placeholder={ __( 'Title' ) }
                    value={ title }
                    onChange={ onChangeTitle }
                    className="title"
                />
                <RichText
                    tagName="p"
                    placeholder={ __( 'Abstract' ) }
                    value={ abstract }
                    onChange={ onChangeAbstract }
                    className="abstract"
                />
                <RichText
                    tagName="p"
                    placeholder={ __( 'Keywords' ) }
                    value={ keywords }
                    onChange={ onChangeKeywords }
                    className="keywords"
                />
                <div className="abstract-keywords-box">
                    <MediaUpload
                        onSelect={ onSelectImage }
                        type="image"
                        value={ image }
    
                        render={ ( { open } ) => (
                        <div>
                        <img src={ image } alt={ __( 'Uploaded Image' ) } />
                        <button className="upload-button" onClick={ open }>
                        { __( 'Upload Image' ) }
                        </button>
                        </div>
                        ) }
                        />
                        </div>
                        </div>
                        );
                        },
                        save: function( props ) {
                            const { attributes: { title, abstract, keywords, image } } = props;

                            return (
                                <div>
                                    <h2 className="title">{ title }</h2>
                                    <p className="abstract">{ abstract }</p>
                                    <p className="keywords">{ keywords }</p>
                                    <img src={ image } className="abstract-keywords-box-image" alt={ __( 'Abstract and Keywords Image' ) } />
                                </div>
                            );
                        },

3. Editor.css File:

/* Title */
.wp-block-abstract-keywords-block .title {
    font-size: 1.5em;
    margin-bottom: 1em;
    padding: 0.5em;
    text-align: center;
}

/* Input Fields */
.wp-block-abstract-keywords-block input[type="text"] {
    width: 100%;
    padding: 0.5em;
    margin-bottom: 1em;
    box-sizing: border-box;
}

/* Abstract and Keywords Box */
.wp-block-abstract-keywords-block .abstract-keywords-box {
    padding: 1em;
    text-align: center;
}

/* Upload Image Button */
.wp-block-abstract-keywords-block .upload-button {
    display: inline-block;
    margin: 1em auto;
    padding: 0.5em 1em;
    background-color: #2508a5;
    color: #fff;
    text-align: center;
    text-decoration: none;
    border-radius: 3px;
    cursor: pointer;
}

/* Image */
.wp-block-abstract-keywords-block img {
    max-width: 100%;
    height: auto;
    margin: 0 auto;
    display: block;
}

Solution

  • I recommend creating your block via an officially supported way, eg:

    npx @wordpress/create-block abstract-keywords
    

    By using @wordpress/create-block you start with a basic, functional block that compiles and includes tools to help you manage and build your project - which is so much more beneficial to start with than what ChatGPT produced.

    However... it would be a interesting learning exercise to figure out where ChatGPT went wrong; noting it doesn't actually know what to do, it just produces something that looks like you might expect. I'm curious why ChatGPT focused on pretty CSS styling and didnt care whether it would function.. our jobs are safe for now..

    Be better than ChatGPT, learn from the Documentation written by human experts.