This wasn’t a good session.
Aside: Cleaning up Meta.ai’s code
I griped about the code formatting, so I asked it to help me out:
write a composer config script that will: delete backups that end in ~; run PHP code beautifier with the WordPress format on all the PHP files
"scripts": {
"cleanup": [
"find . -type f -name '*~' -delete",
"phpcbf --standard=WordPress --extensions=php --ignore=vendor ."
]
}
Refactoring Continues
I continued with the refactoring, and it did a good job breaking out the shortcodes. I haven’t tested it, but it looks pretty good.
I asked for help doing the HTML with a templating system, and tried Twig and BladeOne. So far, so good.
Then I went into no-persons-land: I asked it to refactor out the custom post type (CPT). It did a half assed job. I kept asking for more encapsulation, and then it started spewing out erroneous code.
I turned to Gemini, and it also did a half assed job, but when I asked for more encapsulation, it did better.
A CPT is an extension of a regular Post. It’s like a Post or Page, but adds additional “meta boxes” or custom meta fields.
What I wanted in the encapsulation was to bring together a lot of different things:
- The custom meta would be hidden in the class.
- Each instance of a custom post would be an object.
- The object would have methods to access the meta, or public properties for each meta, or getters and setters, for the metas.
- Each CPT would have a consistent interface.
- Utility functions could help with displaying metas, validating metas, searching for posts (via WP_Query).
Conceptually, a CPT is like a database schema. A custom post is database record.
The advantage of using a CPT instead of a database, is that you get all the publishing infrastructure that WP provides, “for free”. If your “database” is write-once-read-many, implementing it with CPTs might make sense.
I feel like this area of inquiry with the LLMs is doomed, because I think most CPTs are made using tools like ACF.
There might be better possibilities with the CMB2 library, a code-based CPT system. The CMB2 ecosystem is similar to the ACF ecosystem.
Manual Refactoring
In the end, I had to start a manual refactoring, because the LLM wasn’t doing it right.
I can’t really fault the LLM. WordPress plugin coding is a lot of boilerplate, and things get wired up by various names with naming conventions, and pieced together by registering callbacks. It’s kind of like “much magic and spaghetti code”.
The plugin’s main file now looks like this. Only 48 lines. It’s not working, though.
<?php
/**
* Plugin Name: Correction Feedback Plugin
* Description: A very basic plugin example.
* Version: 1.0
* Author: Your Name
*
* @package johnk/plugin
*/
require_once '../vendor/autoload.php';
/**
* Admin notice error shown when permalinks are off.
*/
function correction_permalink_notice() {
?>
<div class="notice notice-error">
<p><?php esc_html_e( 'The Correction Plugin requires using permalinks. Please enable permalinks in your WordPress settings.', 'textdomain' ); ?></p>
</div>
<?php
}
function correction_init() {
global $wp_rewrite;
if ( ! $wp_rewrite->using_permalinks() ) {
add_action( 'admin_notices', 'correction_permalink_notice' );
exit();
}
$recaptcha = new ReCaptcha();
$correction_link_shortcode = new Correction\CorrectionLinkShortcode();
$correction_form_shortcode = new Correction\CorrectionFormShortcode( $recaptcha );
add_shortcode( 'correction_link', array( $correction_link_shortcode, 'render' ) );
add_shortcode( 'correction_form', array( $correction_form_shortcode, 'render' ) );
add_action( 'init', 'Correction\CorrectionPostType::register' );
// Should wrap the admin stuff in a conditional.
$recaptcha_admin = new Admin\ReCaptchaAdmin( $recaptcha );
$correction_admin = new Admin\CorrectionAdmin( $recaptcha_admin );
add_action( 'admin_init', array( $correction_admin, 'register' ) );
}
register_activation_hook( __FILE__, 'Correction\CorrectionPlugin::activate' );
register_deactivation_hook( __FILE__, 'Correction\CorrectionPlugin::deactivate' );
add_action( 'init', 'correction_init', 5 );
Composer Autoloader
I decided to follow the conventions described in How to use Composer Autoload for WordPress.
- Classes are in ‘include’, and admin parts are in ‘admin’.
- I don’t follow the convention to omit ‘Admin’ from the admin class names.1
I added this to my composer.json.
"autoload": {
"psr-4": {
"JTK\\": "includes/",
"JTK\\Admin\\": "admin/"
}
}
So my plugin root, plugin/, contains: admin/, includes/, plugin.php
Then did a composer dump-autoload
to recompile the autoloader.
The directory tree looks like this:
├── admin
│ └── Correction
├── includes
│ └── Correction
└── vendor
...
1 I’m dubious about this organizing convention. I’m just following it because it’s out there, and I figure: it might be understood by LLMs (meaning the LLM maker has copied the page for it’s training); it feels like WP, to separate out the admin files.