Category: WordPress

  • Custom Block Building Workshop

    Custom Block Building Workshop

    This is a written version of a workshop given most recently at WordCamp Rochester 2024. The workshop is more hands-on, but my hope is that the code and explanations here are detailed enough to help you in creating your first custom block.

    The code for the plugin is available on my GitHub profile, and you can walk through the commits to see the order in which the plugin is built.

    This workshop assumes a basic understanding of PHP and JavaScript, as well as a code editor and somewhere to test the code, such as a test WordPress site, or a local development environment. It does not require the use of React or another JavaScript framework, nor does it require build tools.

    I won’t be describing every single line-by-line change, but if you follow along and view the commits, you should be able to see everything that changes for each step.

    Setting Up the Plugin

    Start by creating a folder in your wp-content/plugins folder in WordPress. You can name the folder whatever you want, though I’m going with testimonial-block-workshop.

    Create plugin files

    Add new files to plugin folder

    In that folder, create three files: testimonial-block.php, testimonial-block.js, and testimonial-block.css. These files are going to hold the code to register the plugin, build the block, and style the block, respectively.

    Add plugin header code

    Add plugin header code

    The following code, placed into testimonial-block.php, will let the plugin show up in the site dashboard. This starts the PHP file and uses PHP comments as a way to register the plugin. We’re providing a name, description, version, and author. All of these show up in the dashboard, and the version is important for when updates come in the future.

    <?php
    /**
     * Plugin Name: Testimonial Block Workshop
     * Description: Basic Custom Testimonial Block with no build tools needed - Workshop Demo
     * Version: 1.0.0
     * Author: david wolfpaw
     */

    After you save this code, you should be able to go to the plugin dashboard and see your plugin! Activate it and make it look all highlighted and happy.

    A screenshot of the WordPress plugin dashboard, showing the Testimonial Block Workshop plugin activated.

    Add exit code and define version constant

    Add exit code and define version constant

    Now we’re gonna add code to the PHP file that will ensure that the plugin file doesn’t get accessed directly, and defines a constant for the version of the plugin. We’ll be using this later.

    if ( ! defined( 'ABSPATH' ) ) {
    	exit; // Exit if accessed directly.
    }
    // Define plugin version
    define( 'TESTIMONIAL_BLOCK_VERSION', '1.0.0' );

    Registering the Block

    Now that we’re setup, it’s time to register the block, so that it’s visible in the WordPress editor.

    Register PHP for the block

    register PHP for the block

    This code registers the JavaScript file for the plugin, which is where we’ll be doing the most work. Note that we first register the file with wp_register_script, and then we use register_block_type and tell it which script file to use.

    // Function to register the block and enqueue scripts/styles
    function register_testimonial_block() {
    	// Register the block's JavaScript file
    	wp_register_script(
    		'testimonial-block-script', // Unique script handle
    		plugins_url( 'testimonial-block.js', __FILE__ ), // URL of where the block file exists
    		array( 'wp-blocks', 'wp-block-editor' ), // Scripts that should load before this script
    		TESTIMONIAL_BLOCK_VERSION, // Version of the plugin script (optional)
    		true, // Is script in HTML Footer (optional)
    	);
    	// Register the block type with the scripts and styles
    	register_block_type(
    		// Block namespace and name
    		'workshop/testimonial-block',
    		// Array of arguments for the block
    		array(
    			'editor_script' => 'testimonial-block-script',
    		)
    	);
    }
    add_action( 'init', 'register_testimonial_block' );

    Register JS for the block

    register JS for the block

    In the JavaScript file, we likewise register the block. We use the same namespace and name for the block that we used in the PHP file (workshop/testimonial-block).

    The main things that we’re doing are adding a title and icon, as well as choosing the category of blocks that it will go into for when we select it. The edit and save functions right now are just returning a paragraph tag. The goal at this point is to test to ensure that we can see the block in the editor, and that when we save it, something will display on the frontend of the site.

    (function (blocks, element) {
        const { registerBlockType } = blocks;
        const { createElement } = element;
        // Step 1: Register the block
        registerBlockType('workshop/testimonial-block', {
            title: 'Workshop Testimonial Block', // Block title
            icon: 'admin-comments', // Icon from WordPress dashicons
            category: 'common', // Category in the block inserter
            edit: function () {
                return createElement('p', null, 'Workshop Testimonial Block'); // Placeholder text in editor
            },
            save: function () {
                return createElement('p', null, 'Workshop Testimonial Block'); // Placeholder text on frontend
            }
        });
    })(window.wp.blocks, window.wp.element);

    With both of these files saved, you should be able to go to edit a post or page and find your block.

    A screenshot of the WordPress editor showing the Workshop Testimonial Block that we're making

    Creating Fields to Edit Block

    Alright, now that we’ve gotten really set up, it’s time to create some fields for our block. We’re going to create some text fields, an image upload button, and color selectors.

    Add editable text fields

    Add editable text fields

    The following code adds some of the other constants that we need to make text controls, and adds two text fields: testimonialText and authorName to unsurprisingly store the testimonial text, and the author name.

    (function (blocks, element, blockEditor, components) {
        const { registerBlockType } = blocks;
        const { TextControl } = components; // Import the TextControl component
        const { createElement, Fragment } = element;
    
        // Step 1: Register the block
        registerBlockType('workshop/testimonial-block', {
            title: 'Workshop Testimonial Block', // Block title
            icon: 'admin-comments', // Icon from WordPress dashicons
            category: 'common', // Category in the block inserter
            // Step 2: Add Editable Text Fields
            attributes: {
                testimonialText: { type: 'string', default: '' }, // Testimonial text
                authorName: { type: 'string', default: '' }, // Author name
            },
            edit: function ({ attributes, setAttributes }) {
                const { testimonialText, authorName } = attributes;
                return createElement(
                    Fragment,
                    null,
                    // Add TextControl for Testimonial Text
                    createElement(TextControl, {
                        label: 'Testimonial Text',
                        value: testimonialText,
                        onChange: (value) => setAttributes({ testimonialText: value }),
                        placeholder: 'Enter the testimonial text…'
                    }),
                    // Add TextControl for Author Name
                    createElement(TextControl, {
                        label: 'Author Name',
                        value: authorName,
                        onChange: (value) => setAttributes({ authorName: value }),
                        placeholder: 'Enter the author’s name…'
                    })
                );
            },
            save: function ({ attributes }) {
                return createElement('p', null, 'Custom Testimonial Block'); // Placeholder text on frontend
            }
        });
    })(window.wp.blocks, window.wp.element, window.wp.blockEditor, window.wp.components);

    We are creating the elements that you’ll be able to see on the backend of the site, including labels and placeholders for those fields.

    a screenshot of the testimonial block backend, showing the editable text fields

    Display text on frontend

    Display text on frontend

    The save function will affect what saves tot he database to display on the frontend of the site. We’ve replaced the placeholder paragraph with a div that holds a blockquote and bolded paragraph tag for the testimonial text and the author name.

    save: function ({ attributes }) {
        // Step 3: Create Elements to Display Text on Frontend
        const { testimonialText, authorName } = attributes;
        return createElement('div', null,
            createElement('blockquote', null, testimonialText),
            createElement('p', { style: { fontWeight: 'bold' } }, authorName)
        );
    }
    a screenshot of the testimonial block frontend, showing the text fields

    Add image upload controls

    Add image upload controls

    Same as before, we add the constants needed for the media uploader. We’re going to be saving the URL of the image to use on the frontend. We’re also creating a button that says “Upload Author Image” if no image is set, and changes to “Change Author Image” if an image is already present.

    (function (blocks, element, blockEditor, components) {
        const { registerBlockType } = blocks;
        // Step 4: Add Button and Media Upload Components
        const { TextControl, Button } = components; // Import the Button Component
        const { MediaUpload, MediaUploadCheck } = blockEditor; // Import the Media Upload Components
        const { createElement, Fragment } = element;
    
        registerBlockType('workshop/testimonial-block', {
            title: 'Workshop Testimonial Block', // Block title
            icon: 'admin-comments', // Icon from WordPress dashicons
            category: 'common', // Category in the block inserter
    
            attributes: {
                testimonialText: { type: 'string', default: '' }, // Testimonial text
                authorName: { type: 'string', default: '' }, // Author name
                // Step 4: Add Image URL Attribute
                authorImage: { type: 'string', default: '' }, // Author image URL
            },
            edit: function ({ attributes, setAttributes }) {
                // Step 4: Add Image URL Attribute
                const { testimonialText, authorName, authorImage } = attributes;
    
                return createElement(
                    Fragment,
                    null,
                    // Step 4: Add Media Upload for Author Image
                    // Media Upload for Author Image
                    createElement(MediaUploadCheck, {},
                        createElement(MediaUpload, {
                            onSelect: (media) => setAttributes({ authorImage: media.url }),
                            allowedTypes: ['image'],
                            value: authorImage,
                            render: ({ open }) => createElement(Button, { onClick: open, className: 'is-primary' }, authorImage ? 'Change Author Image' : 'Upload Author Image')
                        })
                    ),
                    // Display Uploaded Image in Editor
                    authorImage && createElement('img', { src: authorImage, alt: 'Author Image' }),
                    // Add TextControl for Testimonial Text
                    createElement(TextControl, {
                        label: 'Testimonial Text',
                );
            },
    a screenshot of the testimonial block backend, showing the image upload

    Display image on frontend

    Display image on frontend

    Same as with the text, we’re now using the same code to create an image element on the frontend to display our author image.

    save: function ({ attributes }) {
        const { testimonialText, authorName, authorImage } = attributes;
        return createElement('div', null,
            // Step 5: Render Image on Frontend
            authorImage && createElement('img', { src: authorImage, alt: 'Author Image' }),
            createElement('blockquote', null, testimonialText),
            createElement('p', { style: { fontWeight: 'bold' } }, authorName)
        );
    }
    a screenshot of the testimonial block frontend, showing the uploaded image and text

    Add color control settings

    Add color control settings

    With the following four changes, we’re adding the ability to create a color panel like the color selectors that appear in other WordPress blocks. We’re saving the settings for a background color and text color for the testimonial block.

    // Step 6: Import the Panel Color Settings
    const { MediaUpload, MediaUploadCheck, PanelColorSettings } = blockEditor;
    
    
    // Step 6: Add Attributes for Background and Text Colors
    backgroundColor: { type: 'string', default: '#ffffff' }, // Background color
    textColor: { type: 'string', default: '#000000' }, // Text color
                
    
    edit: function ({ attributes, setAttributes }) {
        // Step 6: Add Attributes for Background and Text Colors
        const { testimonialText, authorName, authorImage, backgroundColor, textColor } = attributes;
    
    
    // Step 6: Panel for Color Settings
    createElement(PanelColorSettings, {
        title: 'Color Settings',
        initialOpen: true,
        colorSettings: [
            {
                value: backgroundColor,
                onChange: (value) => setAttributes({ backgroundColor: value }),
                label: 'Background Color',
            },
            {
                value: textColor,
                onChange: (value) => setAttributes({ textColor: value }),
                label: 'Text Color',
            }
        ],
    a screenshot of the testimonial block backend, showing the color settings fields

    Move image and color controls to Inspector Panel

    Move image and color controls to Inspector Panel

    Now that we’ve added more controls to our block, it’s starting to look a bit cluttered in the editor. At this point, I think that it’s reasonable to move these settings from the main block editor to the Inspector Panel that shows up on right sidebar when you have a specific block clicked.

    We’re going to move the media upload button and color selectors to the sidebar, while keeping the text fields in the main editor for now. Spoiler: we’re going to move those later as well to tidy up our block view even more.

    edit: function ({ attributes, setAttributes }) {
        const { testimonialText, authorName, authorImage, backgroundColor, textColor } = attributes;
    
        // Step 7: Move Settings into Inspector Controls
        return (
            createElement(Fragment,
                null,
                // InspectorControls Adds Settings in the Sidebar
                createElement(InspectorControls,
                    null,
                    // PanelBody for Testimonial Settings
                    createElement(PanelBody,
                        { title: 'Testimonial Settings' },
                        // Media Upload for Author Image
                        createElement(MediaUploadCheck, {},
                            createElement(MediaUpload, {
                                onSelect: (media) => setAttributes({ authorImage: media.url }),
                                allowedTypes: ['image'],
                                value: authorImage,
                                render: ({ open }) => createElement(Button, { onClick: open, isPrimary: true }, authorImage ? 'Change Author Image' : 'Upload Author Image')
                            })
                        )
                    ),
                    // Panel for Color Settings
                    createElement(PanelColorSettings, {
                        title: 'Color Settings',
                        initialOpen: true,
                        colorSettings: [
                            {
                                value: backgroundColor,
                                onChange: (value) => setAttributes({ backgroundColor: value }),
                                label: 'Background Color',
                            },
                            {
                                value: textColor,
                                onChange: (value) => setAttributes({ textColor: value }),
                                label: 'Text Color',
                            }
                        ],
                    })
                ),
    
                // Step 8: Make div to Display Testimonial in Editor
                createElement('div',
                    null,
                    // Display Uploaded Image in Editor
                    authorImage && createElement('img', { src: authorImage, alt: 'Author Image' }),
                    // Add TextControl for Testimonial Text
                    createElement(TextControl, {
                        label: 'Testimonial Text',
                        value: testimonialText,
                        onChange: (value) => setAttributes({ testimonialText: value }),
                        placeholder: 'Enter the testimonial text…'
                    }),
                    // Add TextControl for Author Name
                    createElement(TextControl, {
                        label: 'Author Name',
                        value: authorName,
                        onChange: (value) => setAttributes({ authorName: value }),
                        placeholder: 'Enter the author’s name…'
                    })
                )
            )
        );
    },
    a screenshot of the testimonial block backend, showing the media upload button and color settings fields moved into the inspector panel sidebar

    Display color changes in editor

    Display color changes in editor

    Now that we’ve moved the color and media settings to the sidebar, we can add some attributes to the div in the editor. Instead of an attribute set of null as it was before, we’re adding a JSON array that includes styles, and a class name.

    This will make inline style changes that will update when a new color is selected for either the text or background.

    // Step 9: Display Color Changes in Editor
    {
        style: {
            color: textColor,
            backgroundColor: backgroundColor
        },
        className: 'custom-testimonial-block'
    },
    a screenshot of the testimonial block backend, showing custom colors set

    Display color changes on frontend

    Display color changes on frontend

    This should look basically the same as the previous step. We’re making the save function return a div that has some style attributes and a class name. The class name we’ll be using when we do more styling at the end.

    // Step 10: Display Color Changes on Frontend
    const { testimonialText, authorName, authorImage, backgroundColor, textColor } = attributes;
    return createElement('div',
        {
            style: {
                color: textColor,
                backgroundColor: backgroundColor
            },
            className: 'custom-testimonial-block'
        },
    a screenshot of the testimonial block frontend, showing custom colors set

    Move text controls to Inspector Panel

    Move text controls to Inspector Panel

    I had an idea that I’d be moving the text controls to the Inspector Panel in the sidebar as well. While it’s not editable right where it’d be on the page, I think that it looks and acts cleaner this way, with less clutter in the display and all of the things that you’ll actually edit next to one another.

    This step involves moving the controls into the InspectorControls element, as well as creating new elements in the div in the main page editor to display the updated blockquote and paragraph tags.

    // Step 11: Move Text Controls into Inspector Panel
    // Add TextControl for Testimonial Text
    createElement(TextControl, {
        label: 'Testimonial Text',
        value: testimonialText,
        onChange: (value) => setAttributes({ testimonialText: value }),
        placeholder: 'Enter the testimonial text…'
    }),
    // Add TextControl for Author Name
    createElement(TextControl, {
        label: 'Author Name',
        value: authorName,
        onChange: (value) => setAttributes({ authorName: value }),
        placeholder: 'Enter the author’s name…'
    }),
    
    
    // Step 11: Move Text Controls into Inspector Panel
    createElement('blockquote', null, testimonialText),
    createElement('p', { style: { fontWeight: 'bold' } }, authorName)
    a screenshot of the testimonial block backend, showing all editable fields moved to the inspector panel sidebar

    Block Alignment and Styles

    We’re almost at the end! Now that we’ve made it this far, it’s time to add a bit of style to our testimonials. We’re going to do this in two ways: add support to allow you to change the alignment of the testimonial block, and add some custom styles for it.

    Add block alignment support

    Add block alignment support

    We’re adding a new parameter to our block: supports. This will let us use an existing feature in the block editor to control alignment. I’ve set all five core options, to allow us to float the testimonial block, or to make it wide or full width on the page. We set an attribute with whatever is saved to allow it to display properly.

    Unlike with the custom attributes that we created, we don’t need to add this to our edit or save functions.

    // Step 12: Add alignment support
    supports: {
        align: ['left', 'center', 'right', 'wide', 'full'], // Supports alignment options
    },
    attributes: {
        testimonialText: { type: 'string', default: '' }, // Testimonial text
        authorName: { type: 'string', default: '' }, // Author name
        authorImage: { type: 'string', default: '' }, // Author image URL
        backgroundColor: { type: 'string', default: '#ffffff' }, // Background color
        textColor: { type: 'string', default: '#000000' }, // Text color
        blockAlignment: { type: 'string', default: 'none' }, // Block alignment
    },
    a screenshot of the testimonial block backend, showing the block alignment options

    Register block stylesheet

    Register block stylesheet

    Finally touching that PHP file again! The main things of note here are that we are registering the stylesheet that we already created, testimonial-block.css, and telling WordPress where it can be found. We are then adding style_handles to the register_block_type function. This is an array, since there could be more than one stylesheet added.

    You do have the ability to specify stylesheets for the frontend and backend of the site separately, but in our case we’re going to have the same one apply, since it isn’t too hard on this simple block to style to look the same to visitors as it does while editing.

    // Register the block's styles
    wp_register_style(
    	'testimonial-block-style', // Unique stylesheet handle
    	plugins_url( 'testimonial-block.css', __FILE__ ), // URL of where the stylesheet file exists
    	array( 'wp-edit-blocks' ), // Stylesheets that should load before this script
    	TESTIMONIAL_BLOCK_VERSION // Version of the plugin script (optional)
    );
    // Register the block type with the scripts and styles
    register_block_type(
    	// Block namespace and name
    	'workshop/testimonial-block',
    	// Array of arguments for the block
    	array(
    		'editor_script' => 'testimonial-block-script',
    		'style_handles' => array( 'testimonial-block-style' ),
    	)
    );

    Add block styles

    Add block styles

    And now we’re finally using our CSS file!

    Nothing very special of note here. This code:

    • makes a box and adds a border to it (same color as the text color)
    • centers the image and text
    • rounds the image to a circle and adds a border to it as well (same color as the text color)
    • makes the block quote look a bit fancy with a large quotation mark
    • bolds the author name
    .custom-testimonial-block {
        text-align: center;
        padding: 20px;
        border-radius: 20px;
        border: 3px solid;
        font-size: 1em;
    }
    .custom-testimonial-block img {
        border-radius: 50%;
        border: 3px solid;
        background-color: #fff;
    }
    .custom-testimonial-block blockquote {
        font-size: 1.5em;
        padding: 50px;
        font-style: italic;
        position: relative;
    }
    .custom-testimonial-block blockquote::before {
        content: '“';
        font-family: sans-serif;
        font-size: 4em;
        line-height: 1;
        position: absolute;
        left: 10px;
        top: -10px;
    }
    .custom-testimonial-block p {
        font-size: 1em;
        font-weight: bold;
    }

    You probably noticed that the author name was already bolded before. That’s because we originally used this:

    createElement('p', { style: { fontWeight: 'bold' } }, authorName)

    Now we removed the style attributes, to get this:

    createElement('p', null, authorName)

    The main reason that I made this change is just to keep styling consistently in one area, so that we can more easily make changes to it in the future if we want.

    Final Thoughts

    I realize that was a lot to go through at once. I don’t blame you if it takes a few tries (it took more than a few for me!) or requires a few sessions and examples to get it down.

    This is just one way of building a custom block, and not how most that you will see will look. That’s because instead of using the fancy and very helpful @wordpress/create-block tooling, I opted for something that would not require you to learn any build tools, how to use the command line, or having a separation of source and build files.

    From here I want you to go out and create custom blocks that are useful for your own sites, and share them with the world! I’ll be happy to showcase some if you reply with a link to what you end up building.

  • New Kid on the Block: Crafting Custom Blocks – WordCamp Minneapolis 2024

    New Kid on the Block: Crafting Custom Blocks – WordCamp Minneapolis 2024

    david holding the phone and smiling with a room of people at WordCamp Minneapolis 2024

    Attached are my slides and resources for my presentation at WordCamp Minneapolis on 16 August 2024.


    Methods to Create Custom Blocks

    Block Patterns

    Pros: No coding required, No extra plugins needed, Can be repeated or customized
    Cons: Block Editor limitations exist

    Custom HTML Block

    Pros: No extra plugins needed, Custom code for your needs, Can include JavaScript and CSS
    Cons: Code is not contained/scoped

    Advanced Custom Fields

    Pros: Custom settings/options/data, Saves block development time
    Cons: Requires custom coding, Requires Pro Plugin

    Block Variations

    Pros: Good for tweaking existing blocks
    Cons: Limited functionality changes

    Backend of the editor showing a Block Variation of a Media & Text block

    Custom Blocks

    Pros: Custom everything!, Made to fit your exact needs
    Cons: Getting started coding is hard, Build tools and guides change


    Resources Linked

  • Day 19: #WP20 From Blogs to Blocks

    Prompt 19/20 Blog: If you could have one wish for WordPress granted, what would it be?

    https://make.wordpress.org/marketing/2023/05/26/day-19-wp20-from-blogs-to-blocks/

    This is a tough prompt! There are so many things that I would like to do with WordPress that haven’t been done yet.

    I suppose the one wish that I have is for the good parts of our community and general vibe to be able to transfer to a general consciousness of how the internet and work should work.

    For instance, a lot of WordPress agencies do four day workweeks, and Automattic has been remote from the start. I would love more jobs to work this way, and free people from a lot of busywork and commuting that is doing no one any good.

    We also value group contributions in a way that a lot of other organizations do not. More can be done with a diversity of voices and experiences. It would be great if more spaces embrace this ethos.

    Sure, I could provide some specific code ideas, but I’d rather change mindsets, and the code will follow.

  • Day 18: #WP20 From Blogs to Blocks

    Prompt 18/20 Blog: Download the WordPress Mobile app and post a post from the app about your experience posting from the app.

    https://make.wordpress.org/marketing/2023/05/25/day-18-wp20-from-blogs-to-blocks/

    I don’t think that I’ve ever actually used the WordPress mobile app to write before.

    I’ve been writing my post drafts in Notion lately. Not because I don’t like writing in WordPress itself. That’s where I compose all of my weekly newsletters after all.

    No, the main reason that I use an external writing app is because I want somewhere that I can easily search all of my notes and writing, not just things on this one site. I’ve considered in the past funneling multiple sites and other sources into one searchable database, but that hasn’t come to fruition yet. I would want to automate it and just haven’t found something that fits all of my wants, though I think that DEVONthink might be a workable solution if I ever get around to fully setting it up.

    The mobile WordPress app certainly feels quite usable, but I’m not much for using my phone for computing most of the time. Even formatting and grabbing links to paste in was much easier to do on my laptop and I cheated by editing this draft there after writing. That seems more like a me issue than an app issue though.

  • Day 17: #WP20 From Blogs to Blocks

    Prompt 17/20 Blog: Tell us about your first or favorite contribution to WordPress. If you haven’t officially contributed yet, tell us what are you hoping to contribute in the future.

    https://make.wordpress.org/marketing/2023/05/24/day-17-wp20-from-blogs-to-blocks/

    I still remember my first core contribution to WordPress, which happened during WordCamp San Francisco 2013.

    At the time I was a Windows user, having only touched Mac computers for a few creative classes in school. Basically, I didn’t know much about the ecosystem. What I did know is that every time I went to a web dev conference it felt like the rooms were 90% Mac users, with the rest split between Linux and Windows laptop toters.

    In my brilliance, I purchased a Macbook about two days before WordCamp San Francisco, just enough time to get the basics with it and download some apps.

    During the event I found out that the Automattic lounge was going to be hosting a WCSF Dev Day after the main event, where core contributors would be teaching how to contribute code, as well as talking through projects that they were working on, and coding together. I was excited to learn more, and eagerly attended the event.

    Through several hours I was able to get help in solving an issue with a core theme issue that I’d discovered while putting together a site for our local WordPress Meetup. I found a solution that I worked, and got help from some extremely patient contributors. Not only in learning how to make a diff patch and work with trac, but basic things like how to actually get coding and uploading files with a Mac. Truly saintly folks, who I remember to this day.

    Ticket #24896 is my first of very few core code contributions, but I’ve found many different ways to contribute since then.

  • Day 16: #WP20 From Blogs to Blocks

    Prompt 16/20 Blog: Tell us your hopes (or fears) for the future of AI in WordPress.

    https://make.wordpress.org/marketing/2023/05/23/day-16-wp20-from-blogs-to-blocks/

    I am hopeful that WordPress will incorporate AI in a meaningful way. Let me adjust that: I am hopeful that the WordPress Community will incorporate AI in ways that will improve the ecosystem for everybody.

    From what I’ve seen so far, users of generative AI LLMs, such as ChatGPT, have been able to get impressive results in starting out new projects. Yesterday I mentioned that something that helps me with WordPress are tools that make it easier to write code. I see text based LLMs as a way to make this work easier. Similar to how I use a code generator to make it quicker to make custom themes and plugins, these tools can help to reduce time on repetitive work, saving yourself for more complex coding that they don’t yet handle well.

    The fear that I have around LLM AI is just a lot of garbage. Garbage posts generated to generate clicks. Garbage artwork assets created to make a quick buck. Garbage code written and then sold by people who can’t properly support it since they don’t have an understanding of how it is actually working.

    I think that overall the positives will outweigh the negatives when it comes to the use of AI with WordPress. My confidence is because I know that our communities are resilient and will work around the shortcomings of AI to use them to their full potential.

  • Day 15: #WP20 From Blogs to Blocks

    Prompt 15/20 Blog: Share a WordPress tip or trick that has made your life easier.

    https://make.wordpress.org/marketing/2023/05/22/day-15-wp20-from-blogs-to-blocks/

    Tools that help me to write code for WordPress are among those that I’ve found most valuable. Basically, anything that will let me build out sites and plugins faster.

    For instance, https://generatewp.com/ lets you generate code for portions of WordPress that can get repetitive. I use it to generate the code to make post types, taxonomies, queries, and more.

    Tomorrow’s prompt is about AI in WordPress, so I’ll save discussing that beyond saying that it can help speed up general development.

  • Day 14: #WP20 From Blogs to Blocks

    Prompt 14/20 Blog: Share a “Two Truths and a Lie” about your experience with WordPress.

    https://make.wordpress.org/marketing/2023/05/21/day-14-wp20-from-blogs-to-blocks/

    I’m gonna go the romance route on this! Because everything comes back to queer smooching with me 😜🏳️‍🌈

    1. I have been involved in the WordPress community longer than I have been with any of my romantic partners.
    2. I got to know one of my partners via WordPress before becoming romantically involved with them.
    3. I met my best friend via the WordPress community.

    Ok, now take a moment to choose the lie before scrolling down. Ready?


    1. True. Our local Meetup started in October 2011, and I didn’t start dating my husband until late 2012.
    2. True. My partner and I were actually supposed to meet in person for the first time at a WordCamp in March 2020, but it ws cancelled a week or so beforehand due to the pandemic.
    3. False. My best friend Lisa may be actve at WordCamps and the Meetup, but that’s because she’s the best and is always there to help!
  • Day 13: #WP20 From Blogs to Blocks

    Prompt 13/20 Blog: What is your favorite website built in WordPress right now (yours or anyone else’s)?

    https://make.wordpress.org/marketing/2023/05/20/day-13-wp20-from-blogs-to-blocks/

    I know that this whole blogging experience is about celebrating WordPress, and this may feel a bit self-serving in that regard, but the Make WordPress website is a great website built with WordPress to highlight. Built with the free P2, which WordPress.com now offers as a paid product, P2 shows that you can have a robust community right within WordPress.

    The Make WordPress site has a lot of detailed information for the organization of the WordPress contributor community. It’s also where the community organizes to work on the project itself. All major decisions and recaps of conversations that take place elsewhere are posted to the site. Much of the discussion takes places in comments on the site.

    This means that you can follow along with the decision making process and ongoing tasks and roadmap for WordPress from one place, with everything written out. This is also part of the drive from community members to keep everything transparent in decision making and planning. With a useful resource like this, anything that looks like behind the curtain dealmaking is bristled at.

  • Day 12: #WP20 From Blogs to Blocks

    Prompt 12/20 Blog: What is your favorite plugin in the WordPress Plugins Directory?

    https://make.wordpress.org/marketing/2023/05/19/day-12-wp20-from-blogs-to-blocks/

    There are so many WordPress plugins that I love, but admittedly many of them are paid plugins, not available on the repo. I mentioned on Day 8 that Gravity Forms is one of those plugins, which has saved me time and given me access to things that I’d never be able to do on my own repeatedly. Advanced Custom Fields is another one that has made modifying the WordPress experience more accessible. Plus, there are all of the one-off plugins that I’ve written for myself and clients that do useful things but are too specific to release as-is for public consumption.

    When it comes to plugins that you can get right from the WordPress Plugin Directory, I think that I’m going to go with GiveWP. I’ve used it before, both for myself and for clients, and have been happy with the ease of use, versatility, and friendliness of their support staff when I needed help.

    More important, GiveWP is a plugin that does something substantially meaningful for the site owner. It provides a relatively easy way to host your own crowdfunding campaigns. For many users, the plugin can both make more customized donation pages and terms as compared to centralized crowdfunding/donation sites. It also means that you can have fewer fees to pay elsewhere, sending more money directly to your organization or cause.

    This is just another way that the WordPress community can open new avenues to empower people to control their own spaces on the web. We need more like this!

  • Day 11: #WP20 From Blogs to Blocks

    Day 11: #WP20 From Blogs to Blocks

    Prompt 11/20 Blog: WordPress was launched 20 years ago on May 27, 2003. Share a memory, a picture, or tell us a story about where you were in 2003. (If you weren’t born yet, tell us that too.)

    https://make.wordpress.org/marketing/2023/05/18/day-11-wp20-from-blogs-to-blocks/

    On 27 May 2003 I was about to make a move. Right now I live near Orlando, Florida, and I’ve been here since June 2003. A week prior though, when WordPress first officially launched, I was still in Kansas, still in high school, and still more socially inept and awkward than I am now. And I was closeted to everybody, desperately trying to hide a shameful secret.

    Moving was not an uncommon experience for me, though I didn’t know a the time that it was going to be my last major move for a good long while. It’s exciting to see new places, but it also means big changes. For me I was ready for a change, as I didn’t have much in the way of interpersonal attachments to worry about, just one good friend and lots of bad memories to let go of (see socially inept and awkward above).

    I went to a new school, made some new friends, learned more about myself, and finally came out to some people around me, to mixed results. I found a group of queers that I overall gelled with, and ended up staying in Florida for college, where I found even more connections that have altered my life permanently for the better.

    a landscape photo of david and Lisa talking, both walking away from the camera in a prairie field toward a lake surrounded by trees

    Oh, I was also building websites already! Sure, they were super basic, both with the technology of the time and my skill level, but they were fun to craft by hand. I learned a bit of Perl and CGI for interactivity, but they were mainly pure HTML with lots of graphics and cringeworthy text. I wasn’t yet using JavaScript or PHP, but thankfully I dipped my toes into both before finding a CMS.

    It took me five more years to find WordPress, and three more years after that to discover the WordPress Community. But those stories have plenty of other days to be covered.

🌙 ☀️