Claude Code Plugins

Community-maintained marketplace

Feedback

Core WordPress plugin development fundamentals including file structure, security patterns (sanitize, escape, nonces, capabilities), hooks system (actions/filters), database operations with wpdb, and coding standards. Use when creating plugins, implementing security, or working with core WordPress APIs.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name wordpress-core
description Core WordPress plugin development fundamentals including file structure, security patterns (sanitize, escape, nonces, capabilities), hooks system (actions/filters), database operations with wpdb, and coding standards. Use when creating plugins, implementing security, or working with core WordPress APIs.

WordPress Core Development Skill

Core WordPress plugin development knowledge. Focus on fundamentals, security, and standard patterns.

Target: WordPress 6.8+

WordPress Plugin File Structure

Standard organization for WordPress plugins:

plugin-name/
├── plugin-name.php              # Main plugin file (header, activation)
├── uninstall.php                # Uninstall cleanup (optional)
├── includes/
│   ├── class-plugin-name.php    # Main plugin class
│   ├── class-activator.php      # Activation logic
│   └── class-deactivator.php    # Deactivation logic
├── admin/
│   ├── class-admin.php          # Admin-specific functionality
│   ├── css/
│   ├── js/
│   └── partials/                # Admin view templates
├── public/
│   ├── class-public.php         # Public-facing functionality
│   ├── css/
│   ├── js/
│   └── partials/                # Public view templates
└── languages/                   # Translation files

Key Principles:

  • Main plugin file contains header and initialization only
  • Separate admin and public functionality
  • Use classes for organization (recommended)
  • Follow WordPress naming conventions (lowercase, hyphens)

Plugin Header Format

Every plugin must have a header in the main file:

<?php
/**
 * Plugin Name:       Your Plugin Name
 * Plugin URI:        https://example.com/plugin-name
 * Description:       Brief description of what the plugin does
 * Version:           1.0.0
 * Author:            Your Name
 * Author URI:        https://example.com
 * License:           GPL-2.0+
 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain:       plugin-name
 * Domain Path:       /languages
 */

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
	die;
}

Required Fields: Plugin Name Recommended: Description, Version, Author, License, Text Domain

Security Principles (CRITICAL)

WordPress security follows three golden rules:

1. Sanitize Input (Trust Nothing)

Always sanitize data coming from users:

// Text input
$clean_text = sanitize_text_field( $_POST['user_input'] );

// Email
$clean_email = sanitize_email( $_POST['email'] );

// URL
$clean_url = esc_url_raw( $_POST['url'] );

// Integer
$clean_id = absint( $_POST['post_id'] );

// Array of text fields
$clean_array = array_map( 'sanitize_text_field', $_POST['items'] );

Common Functions:

  • sanitize_text_field() - Strips tags, scripts
  • sanitize_email() - Validates email format
  • sanitize_key() - Lowercase alphanumeric, dashes, underscores
  • sanitize_title() - Creates slug-safe string
  • esc_url_raw() - Database-safe URL
  • absint() - Absolute integer (positive only)
  • intval() - Integer conversion

2. Escape Output (Never Trust Data)

Always escape data when outputting to HTML:

// HTML content
echo esc_html( $user_data );

// HTML attributes
echo '<input value="' . esc_attr( $value ) . '">';

// URLs
echo '<a href="' . esc_url( $link ) . '">Link</a>';

// JavaScript
echo '<script>var data = ' . wp_json_encode( $data ) . ';</script>';

// Textarea
echo '<textarea>' . esc_textarea( $content ) . '</textarea>';

Common Functions:

  • esc_html() - Escapes HTML (converts < > & " ')
  • esc_attr() - Escapes HTML attributes
  • esc_url() - Escapes URLs for output
  • esc_js() - Escapes JavaScript strings
  • esc_textarea() - Escapes textarea content
  • wp_kses_post() - Allows safe HTML (like posts)

3. Nonces (Verify Intent)

Use nonces to prevent CSRF attacks:

// Creating a nonce (in form)
wp_nonce_field( 'my_action_name', 'my_nonce_field' );

// Verifying a nonce (on submission)
if ( ! isset( $_POST['my_nonce_field'] ) ||
     ! wp_verify_nonce( $_POST['my_nonce_field'], 'my_action_name' ) ) {
	die( 'Security check failed' );
}

// URL nonces
$url = wp_nonce_url( 'admin.php?action=delete&id=123', 'delete_item_123' );

// Verify URL nonce
if ( ! isset( $_GET['_wpnonce'] ) ||
     ! wp_verify_nonce( $_GET['_wpnonce'], 'delete_item_123' ) ) {
	die( 'Security check failed' );
}

4. Capability Checks (Authorization)

Verify user has permission:

// Check if user can perform action
if ( ! current_user_can( 'manage_options' ) ) {
	wp_die( 'You do not have sufficient permissions' );
}

// Common capabilities
current_user_can( 'edit_posts' );
current_user_can( 'publish_pages' );
current_user_can( 'edit_others_posts' );

Security Checklist:

  • All user input sanitized
  • All output escaped
  • Nonces verify form submissions
  • Capability checks on all admin actions
  • Direct file access prevented (defined( 'WPINC' ))

Hooks System (Actions and Filters)

WordPress uses hooks to allow plugins to modify behavior.

Actions (Do Something)

Execute code at specific points:

// Add an action
add_action( 'init', 'my_function' );
add_action( 'wp_enqueue_scripts', 'my_enqueue_function' );
add_action( 'admin_menu', 'my_menu_function' );

// Custom action (for your plugin)
do_action( 'my_plugin_custom_action', $param1, $param2 );

Common Action Hooks:

  • init - WordPress initialized, user authenticated
  • admin_init - Admin area initialized
  • admin_menu - Time to add admin menu items
  • wp_enqueue_scripts - Enqueue public scripts/styles
  • admin_enqueue_scripts - Enqueue admin scripts/styles
  • wp_head - Output to <head> section
  • wp_footer - Output before </body>
  • save_post - Post is being saved
  • admin_notices - Display admin notices

Filters (Modify Data)

Modify values before they're used:

// Add a filter
add_filter( 'the_content', 'my_content_filter' );
add_filter( 'the_title', 'my_title_filter', 10, 2 );

function my_content_filter( $content ) {
	// Modify and return content
	return $content . '<p>Added text</p>';
}

// Custom filter (for your plugin)
$value = apply_filters( 'my_plugin_custom_filter', $value, $arg1, $arg2 );

Common Filter Hooks:

  • the_content - Post content
  • the_title - Post title
  • the_excerpt - Post excerpt
  • wp_mail - Email parameters
  • upload_mimes - Allowed upload types
  • login_redirect - Where to redirect after login

Priority and Arguments:

// Priority: 10 is default, lower runs earlier
add_filter( 'the_title', 'my_filter', 5 ); // Runs early

// Accept multiple arguments
add_filter( 'the_title', 'my_filter', 10, 2 );
function my_filter( $title, $post_id ) {
	return $title;
}

Database Interactions (wpdb)

Use $wpdb global for database queries.

Basic Queries

global $wpdb;

// Get single value
$count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts}" );

// Get single row
$post = $wpdb->get_row( "SELECT * FROM {$wpdb->posts} WHERE ID = 1" );

// Get multiple rows
$posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} WHERE post_status = 'publish'" );

// Get column
$titles = $wpdb->get_col( "SELECT post_title FROM {$wpdb->posts}" );

Prepared Statements (ALWAYS)

Never use string concatenation with user input:

// WRONG - SQL Injection vulnerability
$wpdb->get_results( "SELECT * FROM {$wpdb->posts} WHERE ID = {$_GET['id']}" );

// CORRECT - Prepared statement
$id = absint( $_GET['id'] );
$wpdb->get_results( $wpdb->prepare(
	"SELECT * FROM {$wpdb->posts} WHERE ID = %d",
	$id
) );

// Multiple placeholders
$wpdb->get_results( $wpdb->prepare(
	"SELECT * FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s",
	$post_type,
	$status
) );

Placeholders:

  • %s - String
  • %d - Integer
  • %f - Float

Insert/Update/Delete

// Insert
$wpdb->insert(
	$wpdb->prefix . 'my_table',
	array(
		'column1' => 'value1',
		'column2' => 123
	),
	array( '%s', '%d' ) // Format
);

// Update
$wpdb->update(
	$wpdb->prefix . 'my_table',
	array( 'column1' => 'new_value' ), // Data
	array( 'ID' => 123 ),               // Where
	array( '%s' ),                      // Data format
	array( '%d' )                       // Where format
);

// Delete
$wpdb->delete(
	$wpdb->prefix . 'my_table',
	array( 'ID' => 123 ),
	array( '%d' )
);

Table Prefix: Always use $wpdb->prefix for custom tables

WordPress Coding Standards

Follow WordPress PHP coding standards:

Naming Conventions:

  • Functions: lowercase_with_underscores()
  • Classes: Class_Name_With_Underscores
  • Constants: UPPERCASE_WITH_UNDERSCORES
  • Files: lowercase-with-hyphens.php

Indentation: Tabs (not spaces)

Bracing:

if ( condition ) {
	// Code
}

Spacing:

// Always space after control structures
if ( condition ) {
	// Code
}

// Space around operators
$x = $y + $z;

// No space inside parentheses for function calls
my_function( $arg1, $arg2 );

Yoda Conditions (constants on left):

if ( 'yes' === $value ) {
	// Prevents accidental assignment
}

Helper Functions

Plugin paths:

plugin_dir_path( __FILE__ ); // /path/to/wp-content/plugins/my-plugin/
plugin_dir_url( __FILE__ );  // https://example.com/wp-content/plugins/my-plugin/
plugin_basename( __FILE__ ); // my-plugin/my-plugin.php

Get options:

get_option( 'option_name', 'default_value' );
update_option( 'option_name', $new_value );
delete_option( 'option_name' );

Post meta:

get_post_meta( $post_id, 'meta_key', true ); // Single value
update_post_meta( $post_id, 'meta_key', $value );
delete_post_meta( $post_id, 'meta_key' );

Transients (temporary cached data):

set_transient( 'my_transient', $value, 3600 ); // 1 hour
$value = get_transient( 'my_transient' );
delete_transient( 'my_transient' );

Progressive Disclosure

For advanced topics, see:

Related Skills

  • wordpress-blocks - Block development, Block Hooks API, Interactivity API
  • wordpress-modern - Performance optimization, modern WP 6.8 features

Best Practices Summary

  1. Security First: Sanitize input, escape output, verify nonces, check capabilities
  2. Use WordPress APIs: Don't reinvent the wheel, use built-in functions
  3. Follow Standards: WordPress coding standards for consistency
  4. Prepare Statements: Always use $wpdb->prepare() for queries
  5. Prefix Everything: Avoid naming conflicts with unique prefixes
  6. Test: Test activation, deactivation, different user roles
  7. Document: Comment complex logic, use PHPDoc blocks