iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Exercises

Six WordPress exercises that exercise hooks, REST, security, and performance.

Six WordPress drills

EXAMPLE
# ============================================================
# Drill 1 — Add a custom field to a Customs Post Type
# ============================================================
# TASK: store + display a 'reading_time' int on posts of type 'article'.
#
# ANSWER:
add_action('add_meta_boxes', function () {
    add_meta_box('reading_time', 'Reading Time', function ($post) {
        wp_nonce_field('rt_save', 'rt_nonce');
        $v = get_post_meta($post->ID, '_reading_time', true);
        echo '<input type="number" name="reading_time" value="' . esc_attr($v) . '" min="1">';
    }, 'article', 'side');
});

add_action('save_post_article', function ($post_id) {
    if (!isset($_POST['rt_nonce']) || !wp_verify_nonce($_POST['rt_nonce'], 'rt_save')) return;
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_post', $post_id)) return;
    update_post_meta($post_id, '_reading_time', absint($_POST['reading_time'] ?? 0));
});

# ============================================================
# Drill 2 — Expose the field in the REST API
# ============================================================
# ANSWER:
add_action('rest_api_init', function () {
    register_rest_field('article', 'reading_time', [
        'get_callback' => fn($o) => (int) get_post_meta($o['id'], '_reading_time', true),
        'schema' => ['type' => 'integer'],
    ]);
});

# ============================================================
# Drill 3 — Custom REST endpoint with capability check
# ============================================================
# ANSWER:
add_action('rest_api_init', function () {
    register_rest_route('shop/v1', '/refund', [
        'methods'  => 'POST',
        'callback' => 'shop_refund_handler',
        'permission_callback' => fn() => current_user_can('manage_woocommerce'),
        'args' => [
            'order_id' => ['required' => true, 'type' => 'integer', 'sanitize_callback' => 'absint'],
            'amount'   => ['required' => true, 'type' => 'integer', 'validate_callback' => fn($v) => is_int($v) && $v > 0],
        ],
    ]);
});

# ============================================================
# Drill 4 — Cache an expensive query with transients
# ============================================================
# ANSWER:
function get_popular_products() {
    $cached = get_transient('popular_products');
    if ($cached !== false) return $cached;
    $products = wc_get_products(['orderby' => 'popularity', 'limit' => 12]);
    set_transient('popular_products', $products, 60 * 60);
    return $products;
}

# Bust on product save:
add_action('save_post_product', fn() => delete_transient('popular_products'));

# ============================================================
# Drill 5 — Disable XML-RPC if unused
# ============================================================
# ANSWER:
add_filter('xmlrpc_enabled', '__return_false');

# Also block at the .htaccess level
# <Files xmlrpc.php>
#   Require all denied
# </Files>

# ============================================================
# Drill 6 — Defer non-critical scripts for performance
# ============================================================
# ANSWER:
add_filter('script_loader_tag', function ($tag, $handle) {
    $defer = ['analytics', 'chat-widget'];
    if (in_array($handle, $defer)) {
        return str_replace(' src=', ' defer src=', $tag);
    }
    return $tag;
}, 10, 2);

# ============================================================
# Bonus — what makes a plugin update SAFE?
# ============================================================
# ANSWER:
# 1) Staging site that mirrors prod (same theme, plugins, version)
# 2) Test on staging first
# 3) Database backup BEFORE the update
# 4) Roll back plan (WP-Rollback plugin OR restore the backup)
# 5) Monitor error logs + Crashlytics-style tools after the update

# ============================================================
# Scoring
# 6 / 6 -> production-ready WP dev
# 4 / 6 -> revisit wordpress/cheatsheet
# < 4   -> read the Plugin Handbook + Security cheat sheet

Why it matters

Always sanitise on input, escape on output, verify nonces on writes, and capability-check on REST endpoints. Those four habits cover most WordPress security wins. Get them into the teams reflexes and the next CVE in your dependencies stops being a stomach-drop moment.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Fill in: add_____ ('init', 'my_init');
Try it Yourself »

Discussion

Loading…