# How I published my first WordPress.org plugin with Cursor, Git, and AI

- Link: https://matthummel.com/first-wordpress-org-plugin-tocguide-ai/
- Published: 2026-09-23T20:05:18+00:00
- Author: Matthew Hummel

Today I published my first plugin on [WordPress.org](https://wordpress.org/plugins/tocguide/):**
TOCguide**. It is a Gutenberg Table of Contents block with an optional Reading Guide.
No accounts, no tracking, no outside APIs. The listing is live at version 1.6.2.

![TOCguide plugin banner from the WordPress.org plugin directory](https://matthummel.
com/wp-content/uploads/2026/09/TOCguide-WordPress.org-banner.png)

The WordPress.org directory banner for TOCguide.

## Why this took AI to finish

I am a dad of twins. I also have a full-time job and a freelance WordPress side 
gig. Evenings and weekends are short. Shipping a Plugin Directory product the old
way — solo coding every item on your to-do list, every PHPCS pass, every readme 
tweak, every packaging step — would have sat on a list for years. My time is limited,
and I want to protect my work-life balance.

I used AI tools on purpose: **Cursor** (including cloud agents on the repo), **Grok
Bot** for site and content work around matthummel.com, and normal **Git + GitHub
Actions** so the machine checks stayed honest. I am not saying AI replaces judgment.
I am saying it compressed weeks of typing and rework into hours I actually had.

People are right to be careful with AI. Used poorly, it invents APIs, ships insecure
PHP, and fights the WordPress.org guidelines. Used with rules, reviews, and CI, 
it can raise daily output without lowering the bar. This post is my notes from the
first time I took a plugin all the way to the directory. Feedback and pushback are
welcome in the comments.

## What TOCguide is

TOCguide is a single-purpose block plugin. Display name **TOCguide**. Slug, folder,
text domain, shortcode, and CSS prefix are all `tocguide`. That one identity mattered
for WordPress.org guideline 17 and for long-term support.

Docs live on GitHub Pages: [matthummel-pa.github.io/tocguide](https://matthummel-pa.github.io/tocguide/).
Source: [github.com/matthummel-pa/tocguide](https://github.com/matthummel-pa/tocguide).

![Front-end Table of Contents with optional Reading Guide (previews, density, read
time)](https://matthummel.com/wp-content/uploads/2026/09/TOCguide-block-in-the-editor.
png)

Front-end Table of Contents with optional Reading Guide (previews, density, read
time).

![Settings → TOCguide: auto-insert, design tokens, study tools, accessibility](https://
matthummel.com/wp-content/uploads/2026/09/TOCguide-front-end-table-of-contents.png)

Settings → TOCguide: auto-insert, design tokens, study tools, and accessibility.

![Block sidebar in the editor (heading levels, layout, Reading Guide)](https://matthummel.
com/wp-content/uploads/2026/09/TOCguide-Reading-Guide-mode.png)

Block sidebar in the editor: heading levels, layout, and Reading Guide.

## The setup: Cursor, Git, CI, WordPress

### Cursor rules and cloud agents

The repo is set up so an agent does not guess WordPress policy. Under `.cursor/rules/`
I keep always-on rules for block coding, brand typography, and the WordPress.org
Plugin Directory FAQ plus the 18 guidelines. A `CLAUDE.md` file states the product
intent in plain language: one focused block, dynamic render, helpers in `includes/`,
never declare functions in `src/render.php`, freemium path without crippling the
free plugin.

Cursor cloud agents handled large slices of work as pull requests — packaging for
WordPress.org, naming and slug alignment, visual styling passes, and review fixes.
I still read every PR. The agent drafts. I decide what merges.

### Git and GitHub Actions

Main stays green with a CI workflow that runs on push and pull request: Node from`.
nvmrc`, `npm ci`, JS and CSS lint, `npm run build`, PHP lint, and PHPCS via Composer.
Tags like `v1.6.2` fire a Release workflow that builds the plugin zip with `@wordpress/
scripts` `plugin-zip` and attaches it to a GitHub Release. That zip is what goes
through SVN to the directory after review.

    ```wp-block-code
    name: Release

    on:
      push:
        tags: ['v*.*.*']

    jobs:
      zip:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v7
          - uses: actions/setup-node@v7
            with:
              node-version-file: .nvmrc
              cache: npm
          - run: npm ci
          - run: npm run build
          - run: npm run plugin-zip
          # attaches tocguide.zip to the GitHub Release for that tag
    ```

Exact file: `.github/workflows/release.yml` in the repo. CI twin is `.github/workflows/
ci.yml`.

### Block architecture

TOCguide is a dynamic block: `block.json` (apiVersion 3), `save.js` returns null,
and `src/render.php` prints the nav. Heading maps and markup live in `TOCguide_Headings`.
That split keeps render thin and PHPCS happier.

    ```wp-block-code
    {
      "apiVersion": 3,
      "name": "tocguide/table-of-contents",
      "title": "Table of Contents",
      "textdomain": "tocguide",
      "styles": [
        { "name": "default", "label": "Default", "isDefault": true },
        { "name": "minimal", "label": "Minimal" },
        { "name": "boxed", "label": "Boxed" },
        { "name": "underline", "label": "Underline" },
        { "name": "card", "label": "Card" }
      ],
      "editorScript": "file:./index.js",
      "viewScript": "file:./view.js",
      "render": "file:./render.php"
    }
    ```

    ```wp-block-code
    <?php
    /**
     * Server-side render for the Table of Contents block.
     * Do not declare functions here — this file is included on every render.
     */
    if ( ! defined( 'ABSPATH' ) ) {
    	exit;
    }

    $tocguide_post_id = 0;
    if ( isset( $block ) && $block instanceof WP_Block && ! empty( $block->context['postId'] ) ) {
    	$tocguide_post_id = (int) $block->context['postId'];
    }
    if ( ! $tocguide_post_id ) {
    	$tocguide_post_id = (int) get_the_ID();
    }
    if ( ! $tocguide_post_id ) {
    	return;
    }

    echo TOCguide_Headings::render_nav( $attributes, $tocguide_post_id, true );
    ```

Bootstrap is ordinary WordPress: headers, constants, class requires, singleton `
tocguide()->boot()`.

    ```wp-block-code
    define( 'TOCGUIDE_VERSION', '1.6.2' );
    define( 'TOCGUIDE_FILE', __FILE__ );
    define( 'TOCGUIDE_DIR', plugin_dir_path( __FILE__ ) );

    require_once TOCGUIDE_DIR . 'includes/class-tocguide-settings.php';
    require_once TOCGUIDE_DIR . 'includes/class-tocguide-headings.php';
    require_once TOCGUIDE_DIR . 'includes/class-tocguide-plugin.php';

    function tocguide() {
    	return TOCguide_Plugin::instance();
    }

    tocguide()->boot();
    ```

![Docs and Support tab in wp-admin linking to the documentation site](https://matthummel.
com/wp-content/uploads/2026/09/TOCguide-style-presets.png)

Docs & Support tab in wp-admin, with links to the documentation site.

### Where Grok Bot fits

Cursor owns the plugin code. Grok Bot owns a different lane for me: matthummel.com
drafts, Rank Math, media, and turning repo facts into readable posts like this one.
Same person reviewing both. Different tools for code vs. site content. That split
keeps AI from rewriting production PHP because a blog draft asked for a metaphor.

## What the work actually looked like

 * **Product core:** dynamic TOC block, settings, shortcode, auto-insert, heading
   ID injection with `WP_HTML_Tag_Processor`.
 * **Reading Guide and study tools:** server-side previews and read time, optional
   localStorage features, builder heading parsers.
 * **Directory readiness:** Plugin Check cleanup, readme parser limits, trademark-
   safe tags, no front-end “powered by,” text domain literal `tocguide`.
 * **Naming pass:** one slug everywhere after earlier display-name confusion — re-
   insert blocks after the 1.5.0 identity change.
 * **Design polish:** theme-style conflicts (list counters printing “0.”), exclude-
   theme-styles mode, settings tabs with live preview (1.6.x).
 * **Release path:** tag → zip → SVN assets (banner, icon, screenshots) → directory
   listing.

None of that is “prompt once and ship.” It is many short sessions: agent proposes,
CI fails or Plugin Check complains, I fix the rule or the code, repeat. AI sped 
the loop. It did not remove the loop.

## An honest take on AI

What helped:

 * Written rules in the repo so agents follow Gutenberg and WordPress.org constraints
   instead of inventing patterns.
 * CI as a second reviewer that never gets tired of PHPCS or lint.
 * Cloud agents for packaging and repetitive compliance edits while I was with the
   kids or on client work.

What still needs a human:

 * Product taste (what belongs in free vs later).
 * Security and escaping reviews.
 * Reading the official guidelines yourself before you argue with a reviewer.
 * Saying no when a suggestion would phone home, load a CDN script, or lock features
   behind a paywall on .org.

I am not claiming AI is magic or that every developer should use the same stack.
I am claiming that for a busy parent shipping a first directory plugin, the time
cost used to be the blocker — and tooling that respects WordPress standards can 
change that. If your experience differs, I want to hear it. I go deeper on the full
setup in [my AI workflow for WordPress development on a Mac](https://matthummel.com/ai-workflow-for-wordpress-development/),
and break down each tool in [5 ways my AI WordPress workflow speeds up development](https://matthummel.com/5-ways-my-new-ai-wordpress-workflow-actually-speeds-up-development-and-what-it-doesn8217t/).

## Try it and talk back

Install [TOCguide from WordPress.org](https://wordpress.org/plugins/tocguide/), 
or grab a release zip from [GitHub Releases](https://github.com/matthummel-pa/tocguide/releases).
Docs and support notes are on the [docs site](https://matthummel-pa.github.io/tocguide/).
Issues and ideas: [GitHub Issues](https://github.com/matthummel-pa/tocguide/issues).

Since this launch, a table of contents block has been planned for WordPress core.
Here is [what that means for TOCguide](https://matthummel.com/wordpress-table-of-contents-block/).

If you build plugins with AI, or you refuse to, leave a comment. What worked, what
broke review, what you would never trust an agent with — I read them. Same for agencies
looking for quiet WordPress help in the background: the [Hire](https://matthummel.com/hire/)
page is the short version of how I work.

— Matt

---

## Want more posts like this?

I keep the address on this site. I do not send it to a newsletter service.

 Email

I write about modern WordPress development, AI tools, and building plugins. Follow
along on [DEV.to](https://dev.to/matthummeldev) or [GitHub](https://github.com/matthummel-pa),
or subscribe with the [RSS feed](https://matthummel.com/feed/).
