Category: WordPress

  • PHP_CS in Neovim

    I recently switched to only Neovim as my editor of choice and I hit a few issues with formatting PHP code to follow the WordPress coding standards. I didn’t find a simple guide to follow that worked for my case so I decided to write one which I can refer to in the future 🙂

    My existing setup:

    • Neovim as editor
    • lazy.nvim as a package manager
    • macOS with brew as package manager
    • php v8.3.3 (maybe 5.4+ is required for this to work, but I haven’t tested it.)

    With that, here is everything needed to make it work:

    Composer & packages

    If not installed, install composer, which we will need to install globally the phpcs package: brew install composer

    Make sure it all works by running composer.

    Install phpcs globally by following the guide on https://github.com/squizlabs/PHP_CodeSniffer. When the setup is done, phpcs will run on each PHP file with a PHP coding standard we provide. If desired, you can set it up to run on a command like <leader>pcf (for php code fix) or <leader>pcc (for php code check maybe).

    Make sure phpcs and phpcbf are available globally in your system as commands. So add them to PATH. Example:

    export PATH="/Users/alex/vendor/bin:$PATH". Don’t forget to source bashrc or zshrc or whatever you use.

    Install WordPress coding standards:

    https://github.com/WordPress/WordPress-Coding-Standards – Follow the guide for installation as a global installation. The package we will be using is WordPress but there is no need to do anything more than just installing it right now. We will set it up in neovim later.

    A time to say this:

    • PHPCS – Lints, shows issues. Works live as you edit files.
    • PHPCBF – Fixes issues. can be run pre-commit or as you save your file.

    Test if everything works so far:

    Create a PHP file and write some code that is not formatted by the WordPress coding standards. Example:

    <?php
    
    $a = 5;
    $aa = 5; // We want the equals to align.
    
    // Docblock must be set
    function($a) // spacing for ( $a) and { on same line
    {
    }

    To test it, in your terminal run phpcs --standard=WordPress file.php

    If it all works, you should see output with all errors found like this:

    FILE: /Users/alex/Development/Projects/php/test.php
    -------------------------------------------------------------------------------------------
    FOUND 4 ERRORS AFFECTING 4 LINES
    -------------------------------------------------------------------------------------------
      1 | ERROR | Missing file doc comment
      6 | ERROR | Inline comments must end in full-stops, exclamation marks, or question marks
      8 | ERROR | Inline comments must end in full-stops, exclamation marks, or question marks
     10 | ERROR | PHP syntax error: syntax error, unexpected end of file
    -------------------------------------------------------------------------------------------
    
    Time: 76ms; Memory: 10MB

    This is the linting. Now let’s try to auto-fix the errors. `phpcbf --standard=WordPress file.php`

    PHPCBF RESULT SUMMARY
    ----------------------------------------------------------------------
    FILE                                                  FIXED  REMAINING
    ----------------------------------------------------------------------
    /Users/alex/Development/Projects/php/test.php         5      4
    ----------------------------------------------------------------------
    A TOTAL OF 5 ERRORS WERE FIXED IN 1 FILE
    ----------------------------------------------------------------------
    
    Time: 271ms; Memory: 12MB
    
    

    5 errors fixed! 🎉 If you run cat test.php or just view the file you should see it like this:

    <?php
    
    $a  = 5;
    $aa = 5; // We want the equals to align.
    
    // Docblock must be set
    function ( $a ) {
    	// spacing for ( $a) and { on same line
    }

    So much better! Of course, there are issues phpcbf can’t fix, like the doc block comments. This is left to the developer.

    Setup phpcs in Neovim

    You’ve likely already had PHPCS working, but we had to go through it just in case. Or just to make sure it’s set correctly in your terminal.

    First, let’s install praem90/nvim-phpcsf. With lazy.nvim it’s quite easy, all I did was to add the new “phpcs.lua” file in my /lazy folder:

    return {
        {
            "praem90/nvim-phpcsf",
            config = function()
            end
        },
    }

    Restart nvim to have lazy.nvim install nvim-phpcsf. Next, from the docs we see that we need to setup some global variables to point where phpcs is located:

    return {
        -- PHPCS installation. 
        {
            "praem90/nvim-phpcsf",
            config = function()
                vim.g.nvim_phpcs_config_phpcs_path = 'phpcs'
                vim.g.nvim_phpcs_config_phpcbf_path = 'phpcbf'
                vim.g.nvim_phpcs_config_phpcs_standard = 'WordPress' -- or path to your ruleset phpcs.xml
            end
        },
    }

    See the last line – the standard is set to “WordPress”. If you work on something else this is the place you want to setup your standards. I haven’t yet needed to change it so I don’t have a ready solution. It is possible that phpcs will automatically read from the config file of your project, but again, not tested.

    Now, to test it out, open again your test.php file using nvim and run the following command: lua require'phpcs'.cbf() You should see the file getting fixed.

    Troubleshooting

    1. If you encounter an error for missing JSON implementation/module/include, you will need to get it in your lua config unforunately. See the issue here: https://github.com/praem90/nvim-phpcsf/issues/4. I had the same issue and this fixed it for me. Read your error message about the places it searches for the JSON file and pick one; you can wget the file in it. Restart and it should work.

    Optional – format on save

    You can setup a command to run PHPCS or PHPCBF whenever needed. For my setup, I have it “on save”, but might change in the future if it gets in the way with generating too large PRs.

    The auto-format setup follows after the global variables. Also, this is the full phpcs.lua file I have, nothing is removed.

    return {
        -- PHPCS installation. 
        -- https://github.com/WordPress/WordPress-Coding-Standards?tab=readme-ov-file#installation
        {
            "praem90/nvim-phpcsf",
            config = function()
                vim.api.nvim_create_augroup("PHPCSGroup", {clear = true})
    
                vim.g.nvim_phpcs_config_phpcs_path = 'phpcs'
                vim.g.nvim_phpcs_config_phpcbf_path = 'phpcbf'
                vim.g.nvim_phpcs_config_phpcs_standard = 'WordPress' -- or path to your ruleset phpcs.xml
    
                -- Setup auto formatting for php files using phpcs
                vim.api.nvim_create_autocmd({"BufWritePost", "BufReadPost", "InsertLeave"}, {
                    group = "PHPCSGroup",
                    pattern = "*.php",
                    command = "lua require'phpcs'.cs()",
                })
                vim.api.nvim_create_autocmd("BufWritePost", {
                    group = "PHPCSGroup",
                    pattern = "*.php",
                    command = "lua require'phpcs'.cbf()",
                })
    
                vim.keymap.set("n", "<leader>lp", function() require("phpcs").cbf() end, {
                    silent = true,
                    noremap = true,
                    desc = "PHP Fix"
                })
            end
        },
    }
    

    I have commented “what does this do?” as I didn’t really look into it or have much of Neovim knowledge 🙂 But I kept it there as I believe there is some organizational thing going on with the groups. Might not be needed though.

    What’s important – on the correct event as described from the package (BufWritePost), we run CBF to format our file. On file changes, we use PHPCS to lint it and show errors.

    Here is a screenshot from my editor on a mostly formatted test.php file:

    So PHPCBF did the alignment and spacing and all, but didn’t touch the dot at the end or adding a Docblock for my function definition.

    I hope this helped!

  • Set custom pattern in core/query picker

    Full code example:

    /**
     * WordPress dependencies
     */
    import { __ } from '@wordpress/i18n';
    
    wp.domReady(() => {
    	// See all variations in https://raw.githubusercontent.com/WordPress/gutenberg/trunk/packages/block-library/src/query/variations.js
    	wp.blocks.unregisterBlockVariation('core/query', 'posts-list');
    	wp.blocks.unregisterBlockVariation('core/query', 'title-excerpt');
    	wp.blocks.unregisterBlockVariation('core/query', 'title-date');
    	wp.blocks.unregisterBlockVariation('core/query', 'title-date-excerpt');
    	wp.blocks.unregisterBlockVariation('core/query', 'image-date-title');
    
    	wp.blocks.registerBlockVariation('core/query', {
    		name: 'post-title',
    		title: __('Post Title', 'name'),
    		icon: (
    			<svg
    				viewBox="0 0 24 24"
    				xmlns="http://www.w3.org/2000/svg"
    				width="48"
    				height="48"
    				aria-hidden="true"
    				focusable="false"
    			>
    				<path d="M4 14.5h16V16H4zM4 18.5h9V20H4zM4 4h3c2 0 3 .86 3 2.583 0 .891-.253 1.554-.76 1.988-.505.435-1.24.652-2.204.652H5.542V12H4V4zm2.855 4c.53 0 .924-.114 1.18-.343.266-.228.398-.579.398-1.051 0-.473-.132-.82-.397-1.04-.265-.229-.67-.343-1.217-.343H5.542V8h1.313z" />
    			</svg>
    		),
    		attributes: {
    			query: {
    				perPage: 3,
    				pages: 0,
    				offset: 0,
    				postType: 'post',
    				order: 'desc',
    				orderBy: 'date',
    				author: '',
    				search: '',
    				exclude: [],
    				sticky: '',
    				inherit: false,
    			},
    		},
    		innerBlocks: [['core/post-template', {}, [['core/post-title']]]],
    		scope: ['block'],
    	});
    });
    

    The code has two parts:

    1. Remove all default WP-provided patterns for the query loop (if you don’t want them)
    2. Addition of the new pattern. The blocks are in innerBlocks.

    The wp.domReady is needed for the removal of the pre-exiting patterns in the query loop.

  • Setup theme.json with custom colors for WordPress 5.8

    This post is more of a “research” note I had while looking into the theme.json file for themes on WordPress 5.8. You can read the introduction post here: Introducing theme.json in WordPress 5.8 – Make WordPress Core or the documentation here: Global Settings & Styles (theme.json) | Block Editor Handbook | WordPress Developer Resources.

    What is the theme.json? You can think of it as the style guideline a developer can set for a theme. This file will define what colors the editors will have access to, what font sizes, what type of values can be written and what options different build-in blocks will support.

    (more…)