# Wordpress Patterns

> >-

- **Type:** Skill
- **Install:** `agentstack add skill-iwritec0de-wp-dev-wordpress-patterns`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [iwritec0de](https://agentstack.voostack.com/s/iwritec0de)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [iwritec0de](https://github.com/iwritec0de)
- **Source:** https://github.com/iwritec0de/wp-dev/tree/main/skills/wordpress-patterns

## Install

```sh
agentstack add skill-iwritec0de-wp-dev-wordpress-patterns
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# WordPress Development Patterns

This skill covers common WordPress development patterns including Custom Post Types, taxonomies, meta boxes, REST API endpoints, Settings API, cron, transients, and enqueue patterns.

## Custom Post Types

```php
add_action( 'init', 'myplugin_register_post_types' );

function myplugin_register_post_types(): void {
    $labels = array(
        'name'               => _x( 'Events', 'post type general name', 'myplugin' ),
        'singular_name'      => _x( 'Event', 'post type singular name', 'myplugin' ),
        'menu_name'          => _x( 'Events', 'admin menu', 'myplugin' ),
        'add_new'            => _x( 'Add New', 'event', 'myplugin' ),
        'add_new_item'       => __( 'Add New Event', 'myplugin' ),
        'edit_item'          => __( 'Edit Event', 'myplugin' ),
        'new_item'           => __( 'New Event', 'myplugin' ),
        'view_item'          => __( 'View Event', 'myplugin' ),
        'search_items'       => __( 'Search Events', 'myplugin' ),
        'not_found'          => __( 'No events found.', 'myplugin' ),
        'not_found_in_trash' => __( 'No events found in Trash.', 'myplugin' ),
    );

    $args = array(
        'labels'              => $labels,
        'public'              => true,
        'publicly_queryable'  => true,
        'show_ui'             => true,
        'show_in_menu'        => true,
        'show_in_rest'        => true,   // Required for Gutenberg
        'query_var'           => true,
        'rewrite'             => array( 'slug' => 'events' ),
        'capability_type'     => 'post',
        'has_archive'         => true,
        'hierarchical'        => false,
        'menu_position'       => 20,
        'menu_icon'           => 'dashicons-calendar-alt',
        'supports'            => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
    );

    register_post_type( 'myplugin_event', $args );
}
```

## Custom Taxonomies

```php
add_action( 'init', 'myplugin_register_taxonomies' );

function myplugin_register_taxonomies(): void {
    $labels = array(
        'name'              => _x( 'Event Types', 'taxonomy general name', 'myplugin' ),
        'singular_name'     => _x( 'Event Type', 'taxonomy singular name', 'myplugin' ),
        'search_items'      => __( 'Search Event Types', 'myplugin' ),
        'all_items'         => __( 'All Event Types', 'myplugin' ),
        'edit_item'         => __( 'Edit Event Type', 'myplugin' ),
        'update_item'       => __( 'Update Event Type', 'myplugin' ),
        'add_new_item'      => __( 'Add New Event Type', 'myplugin' ),
        'new_item_name'     => __( 'New Event Type Name', 'myplugin' ),
        'menu_name'         => __( 'Event Types', 'myplugin' ),
    );

    register_taxonomy( 'myplugin_event_type', array( 'myplugin_event' ), array(
        'hierarchical'      => true,
        'labels'            => $labels,
        'show_ui'           => true,
        'show_admin_column' => true,
        'show_in_rest'      => true,
        'query_var'         => true,
        'rewrite'           => array( 'slug' => 'event-type' ),
    ) );
}
```

## Meta Boxes

```php
add_action( 'add_meta_boxes', 'myplugin_add_meta_boxes' );
add_action( 'save_post_myplugin_event', 'myplugin_save_meta_box' );

function myplugin_add_meta_boxes(): void {
    add_meta_box(
        'myplugin_event_details',
        __( 'Event Details', 'myplugin' ),
        'myplugin_render_meta_box',
        'myplugin_event',
        'normal',
        'high'
    );
}

function myplugin_render_meta_box( WP_Post $post ): void {
    wp_nonce_field( 'myplugin_save_event_details', 'myplugin_event_nonce' );

    $date = get_post_meta( $post->ID, '_myplugin_event_date', true );
    $location = get_post_meta( $post->ID, '_myplugin_event_location', true );
    ?>
    
        
        ">
    
    
        
        " class="widefat">
    
     'string',
        'sanitize_callback' => 'sanitize_text_field',
        'default'           => '',
    ) );

    add_settings_section(
        'myplugin_general_section',
        __( 'General Settings', 'myplugin' ),
        'myplugin_general_section_cb',
        'myplugin-settings'
    );

    add_settings_field(
        'myplugin_api_key',
        __( 'API Key', 'myplugin' ),
        'myplugin_api_key_field_cb',
        'myplugin-settings',
        'myplugin_general_section'
    );
}

function myplugin_general_section_cb(): void {
    echo '' . esc_html__( 'Configure your plugin settings.', 'myplugin' ) . '';
}

function myplugin_api_key_field_cb(): void {
    $value = get_option( 'myplugin_api_key', '' );
    echo '';
}

function myplugin_render_settings_page(): void {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }
    ?>
    
        
        
            
        
    
     WP_REST_Server::READABLE,
            'callback'            => 'myplugin_rest_get_events',
            'permission_callback' => '__return_true', // Public endpoint
            'args'                => array(
                'per_page' => array(
                    'default'           => 10,
                    'sanitize_callback' => 'absint',
                    'validate_callback' => function ( $value ): bool {
                        return $value > 0 && $value  WP_REST_Server::CREATABLE,
            'callback'            => 'myplugin_rest_create_event',
            'permission_callback' => function (): bool {
                return current_user_can( 'publish_posts' );
            },
            'args'                => array(
                'title' => array(
                    'required'          => true,
                    'sanitize_callback' => 'sanitize_text_field',
                ),
            ),
        ),
    ) );

    register_rest_route( 'myplugin/v1', '/events/(?P\d+)', array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => 'myplugin_rest_get_event',
        'permission_callback' => '__return_true',
        'args'                => array(
            'id' => array(
                'sanitize_callback' => 'absint',
            ),
        ),
    ) );
}

function myplugin_rest_get_events( WP_REST_Request $request ): WP_REST_Response {
    $per_page = $request->get_param( 'per_page' );

    $query = new WP_Query( array(
        'post_type'      => 'myplugin_event',
        'posts_per_page' => $per_page,
        'post_status'    => 'publish',
    ) );

    $events = array_map( function ( WP_Post $post ): array {
        return array(
            'id'    => $post->ID,
            'title' => $post->post_title,
            'date'  => get_post_meta( $post->ID, '_myplugin_event_date', true ),
        );
    }, $query->posts );

    return new WP_REST_Response( $events, 200 );
}
```

## Cron / Scheduled Events

```php
// Schedule on activation:
register_activation_hook( __FILE__, 'myplugin_activate_cron' );
register_deactivation_hook( __FILE__, 'myplugin_deactivate_cron' );

function myplugin_activate_cron(): void {
    if ( ! wp_next_scheduled( 'myplugin_daily_cleanup' ) ) {
        wp_schedule_event( time(), 'daily', 'myplugin_daily_cleanup' );
    }
}

function myplugin_deactivate_cron(): void {
    wp_clear_scheduled_hook( 'myplugin_daily_cleanup' );
}

add_action( 'myplugin_daily_cleanup', 'myplugin_run_cleanup' );

function myplugin_run_cleanup(): void {
    // Cleanup logic here.
}

// Custom interval:
add_filter( 'cron_schedules', 'myplugin_add_cron_interval' );

function myplugin_add_cron_interval( array $schedules ): array {
    $schedules['myplugin_fifteen_minutes'] = array(
        'interval' => 900,
        'display'  => esc_html__( 'Every 15 Minutes', 'myplugin' ),
    );
    return $schedules;
}
```

## Transients (Caching)

```php
function myplugin_get_api_data(): array {
    $data = get_transient( 'myplugin_api_data' );

    if ( false === $data ) {
        $response = wp_remote_get( 'https://api.example.com/data' );

        if ( is_wp_error( $response ) ) {
            return array();
        }

        $data = json_decode( wp_remote_retrieve_body( $response ), true );
        set_transient( 'myplugin_api_data', $data, HOUR_IN_SECONDS );
    }

    return $data;
}

// Invalidate when settings change:
add_action( 'update_option_myplugin_api_key', function (): void {
    delete_transient( 'myplugin_api_data' );
} );
```

## Enqueue Scripts & Styles

```php
add_action( 'wp_enqueue_scripts', 'myplugin_enqueue_public' );
add_action( 'admin_enqueue_scripts', 'myplugin_enqueue_admin' );

function myplugin_enqueue_public(): void {
    wp_enqueue_style(
        'myplugin-public',
        plugin_dir_url( __FILE__ ) . 'public/css/style.css',
        array(),
        MYPLUGIN_VERSION
    );

    wp_enqueue_script(
        'myplugin-public',
        plugin_dir_url( __FILE__ ) . 'public/js/script.js',
        array( 'jquery' ),
        MYPLUGIN_VERSION,
        true // Load in footer
    );

    wp_localize_script( 'myplugin-public', 'myPluginData', array(
        'ajaxUrl' => admin_url( 'admin-ajax.php' ),
        'nonce'   => wp_create_nonce( 'myplugin_public_nonce' ),
    ) );
}

function myplugin_enqueue_admin( string $hook ): void {
    // Only load on our admin pages:
    if ( 'settings_page_myplugin-settings' !== $hook ) {
        return;
    }

    wp_enqueue_style(
        'myplugin-admin',
        plugin_dir_url( __FILE__ ) . 'admin/css/admin.css',
        array(),
        MYPLUGIN_VERSION
    );
}
```

## Admin Notices

```php
add_action( 'admin_notices', 'myplugin_admin_notice' );

function myplugin_admin_notice(): void {
    if ( get_option( 'myplugin_api_key' ) ) {
        return;
    }

    $settings_url = admin_url( 'options-general.php?page=myplugin-settings' );
    ?>
    
        
            Configure it here.', 'myplugin' ),
                    array( 'a' => array( 'href' => array() ) )
                ),
                esc_url( $settings_url )
            );
            ?>
        
    
     $title,
        'post_type'   => 'myplugin_event',
        'post_status' => 'draft',
    ] );

    if ( is_wp_error( $post_id ) ) {
        wp_send_json_error( $post_id->get_error_message() );
    }

    wp_send_json_success( [ 'post_id' => $post_id ] );
}
```

### Public AJAX (No Login Required)

```php
// Register for both logged-in and logged-out users
add_action( 'wp_ajax_myplugin_search', 'myplugin_ajax_search' );
add_action( 'wp_ajax_nopriv_myplugin_search', 'myplugin_ajax_search' );

function myplugin_ajax_search(): void {
    check_ajax_referer( 'myplugin_public_nonce', 'nonce' );

    $query = sanitize_text_field( wp_unslash( $_GET['q'] ?? '' ) );

    $results = new WP_Query( [
        'post_type'      => 'myplugin_event',
        'posts_per_page' => 10,
        's'              => $query,
        'post_status'    => 'publish',
    ] );

    $items = array_map( fn( WP_Post $post ): array => [
        'id'    => $post->ID,
        'title' => $post->post_title,
        'url'   => get_permalink( $post ),
    ], $results->posts );

    wp_send_json_success( $items );
}
```

### Enqueuing with AJAX Support

```php
add_action( 'wp_enqueue_scripts', 'myplugin_enqueue_ajax' );

function myplugin_enqueue_ajax(): void {
    wp_enqueue_script(
        'myplugin-ajax',
        plugin_dir_url( __FILE__ ) . 'public/js/ajax.js',
        [],
        MYPLUGIN_VERSION,
        true
    );

    wp_localize_script( 'myplugin-ajax', 'myPluginAjax', [
        'url'   => admin_url( 'admin-ajax.php' ),
        'nonce' => wp_create_nonce( 'myplugin_public_nonce' ),
    ] );
}
```

### JavaScript AJAX Call

```js
// Using fetch (modern)
async function saveData( title ) {
    const formData = new FormData();
    formData.append( 'action', 'myplugin_save_data' );
    formData.append( 'nonce', myPluginAjax.nonce );
    formData.append( 'title', title );

    const response = await fetch( myPluginAjax.url, {
        method: 'POST',
        body: formData,
    } );

    const result = await response.json();
    if ( result.success ) {
        console.log( 'Saved:', result.data.post_id );
    } else {
        console.error( 'Error:', result.data );
    }
}
```

### AJAX Security Checklist

| Requirement | Implementation |
|-------------|---------------|
| Nonce | `wp_create_nonce()` + `check_ajax_referer()` |
| Capability check | `current_user_can()` after nonce verification |
| Input sanitization | `sanitize_text_field( wp_unslash( ... ) )` |
| Response format | `wp_send_json_success()` / `wp_send_json_error()` |
| Public endpoint | Register both `wp_ajax_` and `wp_ajax_nopriv_` |
| Admin-only endpoint | Register only `wp_ajax_` (no `nopriv`) |

For Gutenberg block development patterns, see `references/gutenberg-patterns.md`.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [iwritec0de](https://github.com/iwritec0de)
- **Source:** [iwritec0de/wp-dev](https://github.com/iwritec0de/wp-dev)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-iwritec0de-wp-dev-wordpress-patterns
- Seller: https://agentstack.voostack.com/s/iwritec0de
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
