More Cursor Programming in WordPress

I just spent about thirty minutes creating a couple of functions. I can’t really say I wrote them; it was almost entirely done by AI. I think it’s a nice example of ways in which Cursor and AI can really shine, so I thought I’d spend a couple minutes walking through how it went.

PeakZebra (the system, not the company) has a SQL table that stores data about each of the other SQL tables that PeakZebra creates and uses. The format (for better or worse, and I suspect it’s probably worse) is that the string you’d hand off to the dbDelta function is stored in its entirety.

The table of tables table

While initially building PeakZebra, this made it easy for me to quickly change the fields in any of the (now rather numerous) tables I use. I’d just jump into a PHP file where each of these strings was added to the pz_table_str table. An example looks like this;

// interaction table
$table_name = $wpdb->prefix . "pz_interaction";

// interaction table
$item = array();
$item['id'] = null;
$item['table_name'] = 'pz_interaction';
$item['field_string'] = "CREATE TABLE $table_name (
  id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  per_id bigint(20) NOT NULL DEFAULT 1,
  summary varchar(255) NOT NULL DEFAULT '',
  details varchar(800) NOT NULL DEFAULT '',
  created varchar(12) NOT NULL DEFAULT '',
  PRIMARY KEY  (id)
) $charset;";

handle_def_record($item);
dbDelta($item['field_string']);

the handle_def_record($item) call writes the string to the definition table. Then dbDelta actually creates the file.

If you’re not familiar with dbDelta, it’s pretty handy. It creates the file you’ve described if it doesn’t exist. But if it does exist, it examines it and adds or deletes fields as needed based on comparing the existing file to your CREATE TABLE string.

I wanted to add a way for users to add fields to tables (and perhaps to create new tables), so I wanted to grab an existing string from the table with the defining strings in it, parse it into the individual fields, and then present a form where new fields could be added (deciding to worry about deleting fields later).

Toward that end, I opened the PHP file of a “table” block I’d recently created and gave Cursor this prompt:

let's add a function called read_table_def that reads the record with the table_name field equal to 'pz_person' and returns the field_string value for that row. 

Cursor gave me this:

// ... existing code ...

function read_table_def() {
    global $wpdb;
    $table_name = 'pz_person';
    
    $result = $wpdb->get_var(
        $wpdb->prepare(
            "SELECT field_string FROM {$wpdb->prefix}pz_table_def WHERE table_name = %s",
            $table_name
        )
    );
    
    return $result;
}

Some things of interest here:

  1. Although it could confer that I was working within WordPress from the file I’d opened, I didn’t explicitly say so.
  2. It figured out and knew enough to know that it would need the $wpdb global.
  3. It wisely uses $wpdb->prepare(), something I’ll admit I’m often to lazy to bother with.

Now, the code it supplied was correct, but I’d screwed up and told it the wrong file name, insofar as I’d forgotten the WordPress database prefix.

Debugging and debugging the debugging

As a result, I asked it to add a bunch of debugging code, which it did, leading me to realize, within ten minutes or so, that I’d screwed up.

At that point, I asked it to add the prefix, and it did:

function read_table_def($table_name) {
    global $wpdb;
    
    // Debug: Print the actual query
    $query = $wpdb->prepare(
        "SELECT field_string FROM wp_pz_table_def WHERE table_name = %s",
        $table_name
    );
    echo "Query: " . $query . "<br>";
    
    // Debug: Print the table contents
    $all_records = $wpdb->get_results("SELECT * FROM wp_pz_table_def");
    echo "All records: <pre>";
    var_dump($all_records);
    echo "</pre><br>";
    
    $result = $wpdb->get_var(
        $wpdb->prepare(
            "SELECT field_string FROM wp_pz_table_def WHERE table_name = %s",
            $table_name
        )
    );
    
    // Debug: Print the result
    echo "Result: ";
    var_dump($result);
    echo "<br>";
    
    return $result;
}

Of course, I didn’t want the prefix hardcoded. An easy fix. I asked Cursor to remove the debug code, which it did. Then I moved on to a function that would take the string and parse it into an array of individual field definitions.

I’ll skip over the details, but once again, I’m fascinated by the things it “figures out” on its own, for example, telling me that it’s making the assumption that the fields are comma delimited, but it’s an easy fix if it’s not right about that.

It’s strangely like working with an actual mental process. It’s probably terrible news for junior programmers, if for no other reason that it pretty much never screws up things like the parameters and formats of arcane system function calls.

Join the waitlist…

PeakZebra is currently in active development. Sign up for the newsletter and be the first to know when PeakZebra reaches early release! Plus occasional previews and progress updates.

Please enable JavaScript in your browser to complete this form.