Category: Geekery

  • WordPress Just Gave My AI Assistant a Brain Upgrade (Agent Skills Changed My Workflow Again)

    Last month I wrote about how Claude changed everything for me with custom Gutenberg blocks. I thought I had reached peak workflow. Cursor + Claude, my `.cursor/rules` file, my master prompt template. I was shipping blocks in 15 minutes instead of 6 hours.

    Then WordPress itself dropped something that made half of my “secret sauce” obsolete — in the best possible way.

    Enter: Agent Skills for WordPress

    The WordPress project quietly released an official repo called [agent-skills](https://github.com/WordPress/agent-skills). The tagline says it all:

    “Teach AI coding assistants how to build WordPress the right way.”

    Agent Skills are portable bundles of instructions, checklists, and scripts that AI assistants — Claude, Copilot, Codex, Cursor, whatever you use — read *before* they touch your WordPress code. Instead of the model guessing from its training data (which is often 2 years out of date), it follows documented, contributor-reviewed procedures.

    If you read my last post, you’ll remember my Step 1 was writing my own rules file: “Always use apiVersion 3, prefer render.php, follow WordPress Coding Standards, proper escaping and i18n…”

    That’s exactly what these skills are. Except written from official Gutenberg and WordPress documentation, reviewed by WordPress contributors, and way, way more thorough than my little rules file.

    Why This Matters (The Problem Nobody Talks About)

    AI assistants are amazing, but if you’ve done serious WordPress work with them, you’ve hit these walls:

    1. Outdated patterns. Ask for a theme and you might get a classic PHP theme when you wanted a block theme with `theme.json`. Ask for a block and sometimes you get apiVersion 2 or — the horror — a shortcode.
    2. Missing security. Escaping, sanitization, nonces, capability checks. The AI *knows* about them but doesn’t always apply them unless you nag.
    3. The dreaded “Invalid block” error. If you’ve ever changed a block’s markup and broken every existing instance on a client’s site because you skipped deprecations… you know the pain. This one has bitten me twice.
    4. Ignoring your existing tooling. The AI happily reinvents your build setup instead of using what’s already in the repo.

    Agent Skills solve all four. There’s literally a skill dedicated to block deprecations.

    What’s in the Box

    The repo currently ships 15 skills. Some highlights:

    wp-block-development — everything I was manually prompting for: `block.json`, attributes, rendering, and yes, deprecations
    wp-block-themes — `theme.json`, templates, patterns, style variations
    wp-plugin-development — plugin architecture, hooks, Settings API, security
    wp-interactivity-api — remember in my last post when I told Claude “make the carousel use the new Interactivity API”? Now there’s a whole skill teaching it the `data-wp-*` directives properly
    wp-rest-api, wp-performance, wp-wpcli-and-ops, wp-phpstan, wp-playground, and more

    There’s even a wordpress-router skill that classifies your repo and routes the AI to the right workflow, and wp-project-triage that auto-detects your project type, tooling, and versions. So the AI stops assuming and starts checking.

    Installing It (Took Me 3 Minutes)

    I installed globally so every project gets the skills:


    git clone https://github.com/WordPress/agent-skills.git
    cd agent-skills
    shared/scripts/skillpack-build.mjs --clean
    shared/scripts/skillpack-install.mjs --global

    That drops everything into `~/.claude/skills/` where Claude Code auto-discovers them. Cursor users, there’s a `–targets=cursor-global` option that installs to `~/.cursor/skills/`.

    For client repos, you can install per-project and even pick specific skills:

    node shared/scripts/skillpack-install.mjs --dest=../client-site --targets=claude,cursor --skills=wp-block-development,wp-block-themes

    It supports Codex and VS Code / GitHub Copilot targets too. Whatever your assistant, it’s covered.

    The Before/After Test

    I did an experiment. Same prompt, same model, two fresh plugin folders — one with skills installed, one without.

    The prompt: “Create a native Gutenberg block called Team Grid. 2–4 columns, photo, name, role, social links. Then change the markup structure of the name field.”

    Without skills: Great block (Claude is still Claude). But when I asked for the markup change, it just… changed it. Any existing instance would have thrown “Invalid block” in the editor.

    With skills: It generated the block, and when I asked for the markup change, it *automatically wrote a deprecation entry* with the old save function and a migration. Unprompted. It also ran through a verification checklist at the end — escaping, i18n, accessibility — like a senior dev reviewing its own PR.

    That deprecation thing alone would have saved me an embarrassing client call back in May.

    My Updated Workflow (June ? July 2026)

    So here’s what changed from last month’s post:

    1. Write my own `.cursor/rules` with WordPress standards ? Install agent-skills once, globally
    2. Master prompt template? still useful, but now shorter. I describe the “what”, the skills handle the “how”.
    3. Iterate in chat? unchanged, still magic

    My prompts have gotten lazier and my output has gotten better. That’s the dream, right?

    Honest Limitations (Again, Not Selling You Anything)

    – It’s v1. The skills were AI-generated from official docs, then reviewed and edited by WordPress contributors, and they’re upfront about that. Expect rough edges and improvements over time.
    – It targets WordPress 6.9+ — if you’re maintaining older client sites, the guidance may not always fit.
    – You still need to test in a real WordPress environment. Skills make the AI dramatically more reliable, not infallible.
    – And you still need to understand WordPress basics. This is still “super-code,” not “no-code.”

    The Bigger Picture

    What excites me most isn’t even the skills themselves. It’s that **WordPress, the project, is officially treating AI assistants as first-class citizens of the ecosystem**. The repo is GPL, community contributions are welcome, and most skills are just Markdown — you don’t need to be a coding wizard to improve them. If you’ve got hard-won WordPress expertise, this is a genuinely great way to give back.

    Last month I said Claude changed what a solo developer can ship. This month, WordPress made sure your AI ships it the right way.

    Go install it. Your future self — the one who doesn’t get the “Invalid block” support email — will thank you.

    Enjoy (properly skilled) vibe coding!

  • I hated building Custom Gutenberg blocks… Until Claude changed everything

    For years I built client sites the “normal” way. Need a custom testimonial section? I would either: Use a page builder (and hate the bloat), Write a shortcode (and feel dirty), Or attempt a real native Gutenberg block… and spend 4–6 hours fighting block.json, React hooks, InnerBlocks, responsive attributes, and PHP render_callback just to get something that didn’t break on save.

    I wanted native blocks — fast, lightweight, fully accessible, with proper block.json registration, clean React edit components, and optional server-side rendering in PHP. But the boilerplate was brutal. Then, in late April 2026, everything changed.

    The Day I Discovered Cursor + Claude 4 Sonnet

    I saw a short X thread from a developer I respect saying: “I just built a 7-feature pricing table block with toggle, schema markup, and animated counters in 11 minutes using Cursor + Claude 4 Sonnet. I’m never going back.”

    I was skeptical. I’d tried Grok, ChatGPT, Copilot, and even the new WordPress Telex experiment. They were ok, not that impressive.

    But I downloaded Cursor (the AI-first code editor), pointed it at a fresh plugin folder, and switched the model to Claude 4 Sonnet.

    My first prompt was deliberately simple: Create a production-ready native Gutenberg block called Feature Grid. Use modern block.json. Support 3–6 columns, icon (Dashicon or SVG), heading, description, optional button. Add color controls for background, text, and accent. Make it fully responsive (1-col mobile, 2-col tablet, 3-col desktop).

    42 seconds later Cursor had created the block.json

    It even included proper wp.i18n, escaping, accessibility attributes, and a clean InnerBlocks wrapper. I was speechless.

    The Blocks I’ve Built Since Then (Any Layout I Can Imagine)

    Once I saw what was possible, I went crazy. Here are some of the blocks I’ve shipped to real client sites in the last 10 days:

    1. Testimonial Carousel with Star Ratings + Autoplay

    Drag-and-drop testimonials
    5-star rating system (stored as attribute)
    Autoplay + pause on hover + navigation arrows
    Schema.org markup generated in render.php
    Fully responsive + swipe on mobile
    Time taken: 14 minutes (including 3 iterations)

    2. Pricing Table with Monthly/Annual Toggle

    React state for toggle
    Animated price change
    Highlighted “Most Popular” column
    Custom color controls + hover effects
    Server-side rendered for SEO
    Time taken: 19 minutes

    3. Interactive FAQ Accordion with JSON-LD Schema

    Smooth CSS animations
    Open multiple / single mode toggle
    Auto-generates proper FAQ schema
    Searchable (client-side filter)
    Time taken: 12 minutes

    4. Masonry-Style Image Gallery with Lightbox

    Drag multiple images
    Masonry layout via CSS Grid + JS
    Click opens native lightbox (no extra library)
    Caption + alt text editing inside the block
    Time taken: 17 minutes

    5. Feature Comparison Table (like the ones on Notion / Linear)

    Add/remove rows & columns dynamically
    Check/cross icons with color
    Mobile-responsive (cards on mobile)
    Time taken: 23 minutes

    Every single one of these is 100% native Gutenberg, and it works perfectly in the Site Editor, Full Site Editing, and classic themes.

    How I Prompt Claude 4 in Cursor (The Secret Sauce)

    I now use a consistent workflow that gives me near-perfect results every time:

    Step 1 – Project Rules (I created a .cursor/rules file)

    Always use apiVersion: 3 and modern block.json schema
    - Prefer render.php for dynamic content when possible
    - Follow WordPress Coding Standards strictly
    - Include proper escaping, sanitization, and i18n
    - Make every block fully accessible (ARIA, keyboard nav, color contrast)
    - Output complete, ready-to-build folder structure

    Step 2 – The Master Prompt Template

    You are an expert WordPress Gutenberg block developer.
    Create a production-ready native block called [Block Name].

    Requirements:
    1. [list every feature, control, layout behavior]
    2. Use block.json with apiVersion 3
    3. Full responsive design (mobile-first)
    4. Color, typography, and spacing controls
    5. Accessibility best practices
    6. Clean, commented code

    I then iterate in Cursor’s chat sidebar:
    – Add InnerBlocks support so users can put buttons inside each card
    – Make the carousel use the new Interactivity API instead of vanilla JS
    – Add a ‘Show on mobile only’ toggle attribute

    Claude 4 Sonnet or Opus handles context across multiple files better than any model I’ve tried. It remembers what we already built and suggests smart improvements. Which is awesome. Now life gets easier, specially web developers who struggles to use Gutenberg. Hahaha!

    Now I spend that time on design and user experience instead of boilerplate. The best part? I’m actually learning faster. Claude explains why it chose certain patterns (I used useBlockProps with className merging because…). I’ve leveled up my own Gutenberg skills dramatically in just two weeks.

    Honest Limitations (Because I’m Not Selling You Anything)

    You still need to test in a real WordPress environment (Claude is amazing but not perfect with every edge case of the Site Editor). Complex blocks sometimes need 2–3 follow-up prompts. And sometimes, the JSON output is broken, because AIs are not perfect, they also make mistakes like their human creators. You should understand the basics of Gutenberg. This is not “no-code” development. It’s “super-code”, development. These limitations are tiny compared to the 80–90% time savings.

    My Honest Recommendation as of June 2026. If you are a WordPress developer who has ever thought:

    “I wish I could just describe the block I want and have it appear…”

    Then stop everything and install Cursor + switch to Claude 4 Sonnet today. It’s not just faster. It fundamentally changed what I believe is possible for a solo developer to ship. I went from avoiding custom blocks to actively suggesting them to clients because now they are fun instead of painful.

    Enjoy vibe coding!

  • Too many new features in WP 6.9

    I recently upgraded my blog to 6.9 and I love how WP progressed over the years. Back then I just use this for blogging, but now, it’s everything. You can even create apps, dashboards, booking systems, and everything you can think of using WP. Now, you can even leave comments like using Figma.

    The drag and drop editor Gutenberg that was so bad back then, really improved this 2026.

    I’m still using Classic Editor btw, but I’m gonna switch again and will just use the default Gutenberg editor moving forward. So far so gooooood!

    Also, I recently discovered vibe coding, and you can actually deploy professionally built websites and blog, that’s already headless in just a few seconds. Worst case scenario is minutes. lol! Now everyone is a web / app developer!

    Anyway, I know this guy who is bragging too much about he deployed this and that, and made this and that, with zero coding knowledge. Now this guy deployed a CRM where the company is actually using. One day, there’s an issue about it and he cannot fix it, nor the AI. I think it’s server related issue or some capacity as the code is not that optimized. It frequently goes down. He can’t fix it, AI can’t fix it, and it went down. He has zero clue how to fix it, so he resigned.

    Lesson here is, don’t overly rely on AI. Even a simple CSS issue, AI overcomplicates it, even if it’s just a simple one line fix.

    Gotta learn the basics, instead of just telling the artificial intelligence everything what you want.

    A solid foundation in basics is better than zero foundation at all.

    Stay humble. Stay foolish. Stay Hungry. Thank you Steve Jobs!

  • Clean Login custom user meta fields WP snippet

    I just made extra fields in my user registration and made it appear in the clean login [edit-profile] shortcode. Here’s a wp snippet that you can modify to do the same. I registered two custom user meta fields via formidable forms, but I can only view it if I display the form in the frontend. Formidable Forms lack the confirm email functionality when you change the email address in the web form, so I used clean login to achieve a frontend edit profile with e-mail confirmation.

    Below is an example snippet to add more fields in your clean login edit profile page.

    <?php
    // Add custom user meta fields to the Clean Login edit form
    add_action( 'clean_login_edit_profile_fields', function( $user_id ) {
        $contact   = get_user_meta( $user_id, 'contact', true );
        $territory = get_user_meta( $user_id, 'territory', true );
        ?>
        <p>
            <label for="contact"><?php _e( 'Contact', 'clean-login' ); ?></label><br>
            <input type="text" name="contact" id="contact" value="<?php echo esc_attr( $contact ); ?>" />
        </p>
        <p>
            <label for="territory"><?php _e( 'Territory', 'clean-login' ); ?></label><br>
            <input type="text" name="territory" id="territory" value="<?php echo esc_attr( $territory ); ?>" />
        </p>
        <?php
    });
    
    // Save the custom fields when user updates profile
    add_action( 'clean_login_save_profile_fields', function( $user_id ) {
        if ( isset( $_POST['contact'] ) ) {
            update_user_meta( $user_id, 'contact', sanitize_text_field( $_POST['contact'] ) );
        }
        if ( isset( $_POST['territory'] ) ) {
            update_user_meta( $user_id, 'territory', sanitize_text_field( $_POST['territory'] ) );
        }
    });
    
  • Formidable: Adding Dynamic Link to Parent Values in a View with Child (Repeater) as the Source.

    There are instances that you need to add a dynamic link to a Formidable Form view when your data source is the child table, instead of the parent table. Here’s a javascript snippet that will do the magic.


    function load_jquery() {
    wp_enqueue_script("jquery");
    }
    add_action('wp_enqueue_scripts', 'load_jquery');

    function custom_href_shortcode_fix() { ?>

    To ensure the modification of links applies to all pages of a jQuery DataTable and not just the first, we must utilize DataTables' callback functions to reapply our changes after every table draw (which occurs on pagination, searching, or ordering). Because DataTables rebuilds the elements in the table when you paginate or change the data view, changes made to the DOM are lost after the initial page load. Here's how you can adapt your JavaScript to handle this situation:

    1. First, ensure DataTables is loaded and initialized on your table. I'm going to assume you've done that as part of your setup since you mentioned you're working with jQuery DataTables.

    2. Modify your `custom_href_shortcode_fix` function to use DataTables' `drawCallback` option to reapply custom link configurations after every draw.

    Here's an example update for your code:


    function custom_href_shortcode_fix() { ?>

    A few key points:

    - Ensure you have your DataTables initialized in the script where you're implementing the `drawCallback`. Replace `'#yourTableId'` with the actual ID of the table you are using.
    - The `drawCallback` option is used here to specify a function that is called whenever the table is drawn on the page, including when the page is changed, sorted, or filtered.
    - We've included the initial application of the link modification logic outside of the `drawCallback` as well to ensure it's applied when the page first loads, before any DataTable actions may trigger a redraw.

    Make sure you replace the specific selectors and IDs (`'#yourTableId'` and `'a.dynamic-href'`) with ones that match your HTML structure and requirements.

    What if you encounter the error Cannot reinitialise DataTable?

    The error message "Cannot reinitialise DataTable" typically indicates that DataTables has been initialized on an element more than once. This is a common issue when attempting to apply DataTables configurations dynamically or when the page's state changes without proper cleanup.

    Given the context of your setup, where you might not control the initial initialization of the DataTables (especially in WordPress environments where plugins or themes might automatically apply DataTables to certain elements), we need to approach this with a method that checks if a DataTable instance already exists on an element and only apply modifications without reinitializing.

    Let's adjust your code to handle this scenario. Since you're working with a class selector and you might not be able to directly control the DataTable initialization process, you can use the `$.fn.dataTable.isDataTable()` function to check if an element is already initialized as a DataTable. Here's how you could modify your script:


    function custom_href_shortcode_fix() { ?>

    Additional adjustments:

    1. I wrapped the DataTable initialization in a check using `$.fn.dataTable.isDataTable()` to prevent reinitializing an already initialized DataTable.

    2. I kept the original logic for applying the hyperlink modifications outside the initialization block, which means it will run on page load for all matching elements immediately.

    3. I added an event listener `draw.dt` to the table, which DataTables triggers after each draw. This is useful if your tables are being modified or interacted with dynamically after the initial page loads. This ensures that your `href` modifications are reapplied after actions like pagination, searching, or sorting.

    Please ensure you replace `.yourTableClass` and `'a.dynamic-href'` with the actual selectors used in your project.

  • WordPress 6.4 first impressions!

    WordPress 6.4 was released today and here are my first impressions. It’s cool and it’s fast and I love the modern Twenty Twenty four theme! Other features include the following.

    User Experience Improvements: WordPress tends to focus on refining the user experience with each update. My first impressions might include appreciation for a more streamlined interface, smoother navigation within the dashboard, and enhancements to the site-building experience provided by the block editor (Gutenberg).

    Block Editor Enhancements: With every release, the Gutenberg block editor usually receives new features or improvements. I might notice new blocks, block patterns, or improved handling of media elements within the editor that further simplify the content creation process.

    Performance Enhancements: WordPress developers continuously work to optimize the script loading and database queries for a faster experience. Thus, my first impressions could include faster page load times and more efficient backend performance.

    Full-Site Editing Features: Since the incorporation of full-site editing (FSE) functionality, users expect robust enhancements in this area. Any improvements to the site editor, template creation, and global styles would stand out as significant to me.

    Accessibility: Given WordPress’s commitment to making the web accessible to everyone, I might be impressed by newly introduced features or improvements that make the CMS more accessible for users with disabilities.

    Default Theme – Twenty Twenty-Four: Typically included with a new major WordPress release is a default theme that showcases the latest features. I would be eager to see the aesthetics and functionality of the Twenty Twenty-Four theme, expecting a design that is both modern and optimized for a wide range of use cases.

    Developer Tools and Hooks: As a developer, I might look for new APIs, hooks, or enhanced coding tools that allow for more extensive customizations and integrations, enabling developers to build more robust themes and plugins.

    Can’t wait to explore the rest of the new features in 6.4.

  • Top 3 useful AI tools for your daily needs

    1. Google assistant: Google assistant is a virtual assistant developed by Google that allows you to interact with your Android or iOS device using natural language voice commands and provides information and services based on the user’s request. It can be used for various tasks such as setting reminders, managing calendar events, making phone calls, playing music, and more.

    2. Siri: Siri is an AI-based virtual assistant developed by Apple Inc. It allows users to interact with their iOS devices using natural language voice commands. Siri can be used to set reminders, check the weather, and get directions.

    3. Alexa: Alexa is an AI-based virtual assistant developed by Amazon. It can be used to play music, control lights and other smart home devices, set alarms and reminders, and more. Alexa is also integrated with many third-party services, allowing users to have access to a wide range of services.

  • WooCommerce: Add a product to cart automatically based on another product’s variation ID

    If you want to add a product to your cart based on another product’s ID or variation or a configurable product, then this code snippet might help. Was searching how to do this until I found one in Stack Overflow. The function is based on the first code example on this website post:
    https://www.tychesoftwares.com/how-to-automatically-add-a-product-to-your-woocommerce-cart-in-3-different-scenarios/

    Basically, that code adds a specific product to cart based on the item’s category. So If added a product from category XYZ, then another item, a free one or not, will also be added to your woocommerce cart automatically.

    But what if you want to add a product based on the options selected on a configurable product / variable product. Then the code below will help do exactly what you need

    function bv_atc() {
    if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
    foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
    $a = array(10,20,30);
    $b = array(40,50,60);

    if( in_array( $values['variation_id'], $a ) ) {
    WC()->cart->add_to_cart(1);
    } else if ( in_array( $values['variation_id'], $b ) ) {
    WC()->cart->add_to_cart(2);
    } else {
    //if you want to do something else like adding a random item, do it here.
    }
    }
    }
    add_action( 'woocommerce_add_to_cart', 'bv_atc', 10, 2 );

    Just add the code snippet to your functions.php and replace the values in the array. In my array I have two sets of items. Each item will add a different product to cart.

    Just add more if conditions if you have other items that you want to be added to your cart based on the selected variations of a specific product.

    Credits to Shaikh at Stackoverflow:
    https://stackoverflow.com/questions/68077784/check-if-this-variation-id-exists-in-cart-then-add-another-item-to-cart