Skip to main content

Course Progress

Loading...

Session 8: Introduction to jQuery

Duration: 45 minutes
Module 1: Modern JavaScript & jQuery

Learning Objectives

  • Understand JavaScript fundamentals
  • Add interactivity to web pages
  • Manipulate page elements dynamically
  • Handle user interactions

Session Overview

Welcome to our session on jQuery! Today, we'll explore jQuery - a powerful JavaScript library that simplifies DOM manipulation and event handling. By the end of this session, you'll understand how jQuery can enhance your WordPress development skills and make your code more efficient.

jQuery Architecture Overview JavaScript jQuery Write less, do more DOM Manipulation Event Handling AJAX Calls Animations WordPress Integration • Select elements • Modify content • Traverse DOM • HTTP requests • Load data • Submit forms • Admin panel • Themes • Plugins

What is jQuery?

jQuery is a fast, small, and feature-rich JavaScript library created by John Resig in 2006. Its motto is "Write less, do more" - which perfectly captures its purpose. jQuery simplifies:

  • HTML document traversal and manipulation
  • Event handling
  • Animation
  • AJAX interactions

The Swiss Army Knife Analogy

Think of jQuery as a Swiss Army knife for JavaScript. While you can accomplish everything with vanilla JavaScript (like having individual tools), jQuery packages the most common operations into a compact, efficient library (like having all tools in one pocket-sized device).

Vanilla JavaScript jQuery $ Write less, do more

Why Use jQuery?

Even in 2025, jQuery remains relevant for several reasons:

  • WordPress Core: WordPress itself uses jQuery extensively, making it essential knowledge for WordPress developers
  • Cross-browser compatibility: jQuery handles browser differences for you
  • Simplified syntax: Accomplish complex tasks with fewer lines of code
  • Vast plugin ecosystem: Thousands of ready-to-use components
  • Gentle learning curve: Easy to learn, especially if you already know some JavaScript

Real-World Example: WordPress Admin

Next time you're in the WordPress admin panel, open your browser's developer tools and type jQuery in the console. You'll see jQuery is loaded and used extensively throughout the admin interface for things like:

  • Collapsible metaboxes
  • Media uploader
  • AJAX-based saving of options
  • Drag-and-drop interfaces

Getting Started with jQuery

Including jQuery in Your Project

Before using jQuery, you need to include it in your HTML document. There are several ways to do this:

Method 1: Download and Include Locally

<!-- In the head section -->
<script src="js/jquery-3.7.1.min.js"></script>

Method 2: Use a CDN (Content Delivery Network)

<!-- Using Google's CDN -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<!-- Or using jQuery's CDN -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

Method 3: Using npm (for modern build systems)

// Install jQuery
npm install jquery

// Import in your JavaScript file
import $ from 'jquery';

WordPress-Specific Inclusion

In WordPress, you typically don't manually include jQuery. Instead, you enqueue it using WordPress's built-in functions:

// In your theme's functions.php or plugin file
function enqueue_jquery() {
    wp_enqueue_script('jquery');
}
add_action('wp_enqueue_scripts', 'enqueue_jquery');

This ensures jQuery is loaded correctly and prevents duplications if other plugins also require jQuery.

Core jQuery Concepts

The $ Symbol

The dollar sign ($) is a shorthand alias for the jQuery object. It's used to access jQuery's functionality:

// These are equivalent:
jQuery(document).ready(function() {
    // Code here
});

$(document).ready(function() {
    // Code here
});

// Modern shorthand:
$(function() {
    // Code here
});

The Megaphone Analogy

Think of the jQuery $ as a special megaphone that lets you communicate with and control HTML elements. When you wrap an element with $(), you're essentially picking up this megaphone to give commands to that specific element or group of elements.

$("#element") <div id="element">

Selectors: Finding Elements

jQuery uses CSS-style selectors to find elements in the DOM. This is one of its most powerful features:

// Select by ID
$("#header") // Finds the element with id="header"

// Select by class
$(".nav-item") // Finds all elements with class="nav-item"

// Select by tag name
$("p") // Finds all paragraph elements

// Combined selectors
$("ul.menu li") // Finds all list items inside ul with class="menu"

// Attribute selectors
$("a[target='_blank']") // Finds links that open in new tabs

// Pseudo selectors
$("tr:odd") // Finds odd-numbered table rows

Vanilla JS vs. jQuery Comparison

Task Vanilla JavaScript jQuery
Get element by ID document.getElementById("header") $("#header")
Get elements by class document.getElementsByClassName("nav-item") $(".nav-item")
Query selector document.querySelector("ul.menu li") $("ul.menu li")
Query all selectors document.querySelectorAll("tr:nth-child(odd)") $("tr:odd")

The Document Ready Event

The document ready event ensures your jQuery code runs after the DOM is fully loaded but before all images and other resources are loaded:

// Traditional syntax
$(document).ready(function() {
    // Code runs when DOM is ready
});

// Shorthand syntax
$(function() {
    // Same as above
});

The Party Analogy

Think of your webpage as a party. The $(document).ready() function is like saying "Start the party once all the guests (DOM elements) have arrived, but don't wait for them to hang up their coats and get settled (images and other resources to load)." If you want to wait until everything is completely ready, you'd use $(window).on('load', function() { ... }), which is like saying "Start the party once everyone is completely settled in."

DOM Manipulation with jQuery

jQuery shines when it comes to manipulating the DOM. Let's explore the most common operations:

Getting and Setting Content

// Get text content
let headerText = $("#header").text();

// Set text content
$("#header").text("New Header Text");

// Get HTML content
let contentHTML = $("#content").html();

// Set HTML content
$("#content").html("<strong>New bold content</strong>");

// Get form values
let username = $("input[name='username']").val();

// Set form values
$("input[name='username']").val("JohnDoe");

Modifying Attributes and Properties

// Get an attribute
let linkURL = $("a.main-link").attr("href");

// Set an attribute
$("a.main-link").attr("href", "https://example.com");

// Set multiple attributes
$("img.profile").attr({
    src: "profile.jpg",
    alt: "Profile picture",
    width: 100
});

// Remove an attribute
$("a.temp-link").removeAttr("href");

Working with CSS Classes

// Add a class
$("nav li").addClass("active");

// Remove a class
$("nav li.old-item").removeClass("old-item");

// Toggle a class (add if not present, remove if present)
$(".accordion-item").toggleClass("expanded");

// Check if an element has a class
if ($("#signup-btn").hasClass("disabled")) {
    // Do something
}

Modifying CSS Styles

// Get a CSS property
let bgColor = $("#header").css("background-color");

// Set a CSS property
$("#header").css("background-color", "#f0f0f0");

// Set multiple CSS properties
$(".highlight").css({
    backgroundColor: "#ffff00",
    fontWeight: "bold",
    padding: "5px"
});

Creating and Manipulating Elements

// Create a new element
let newDiv = $("<div>", {
    class: "alert",
    text: "This is an alert message!"
});

// Append element to the end inside a container
$("#notifications").append(newDiv);

// Prepend element to the beginning inside a container
$("#notifications").prepend(newDiv);

// Insert before an element
newDiv.insertBefore("#main-content");

// Insert after an element
newDiv.insertAfter("#header");

// Remove an element
$(".temp-notice").remove();

// Empty an element (remove all its children)
$("#comments").empty();

// Clone an element
let duplicateElement = $(".template-item").clone();

Real-World Example: Dynamic Content Loading

In WordPress, you might use jQuery to dynamically load content into a page without refreshing. Here's how you might update a product preview panel:

// When a product thumbnail is clicked
$(".product-thumbnail").on("click", function() {
    // Get the product ID from a data attribute
    let productId = $(this).data("product-id");
    
    // Update the preview panel with new content
    $("#product-preview")
        .empty() // Clear existing content
        .append("<div class='loading'>Loading...</div>");
        
    // In a real application, you'd fetch the product data via AJAX here
    // For example purposes, we'll simulate it with setTimeout
    setTimeout(function() {
        $("#product-preview")
            .empty()
            .append("<h3>Product " + productId + "</h3>")
            .append("<p>This is the product description for product " + productId + "</p>")
            .append("<button class='add-to-cart'>Add to Cart</button>");
    }, 500);
});

Event Handling with jQuery

jQuery provides a simplified, cross-browser compatible way to handle events:

Basic Event Handling

// Click event
$("#submit-btn").click(function() {
    alert("Button clicked!");
});

// More modern approach with on()
$("#submit-btn").on("click", function() {
    alert("Button clicked!");
});

// Mouseover event
$(".hover-item").on("mouseover", function() {
    $(this).addClass("hovered");
});

// Mouseout event
$(".hover-item").on("mouseout", function() {
    $(this).removeClass("hovered");
});

// Form submission
$("#contact-form").on("submit", function(event) {
    // Prevent the default form submission
    event.preventDefault();
    
    // Validate and process the form
    // ...
});

Event Delegation

Event delegation allows you to attach a single event handler to a parent element that will fire for all descendants matching a selector, now or in the future:

// Without event delegation - only works for existing elements
$(".delete-btn").on("click", function() {
    $(this).closest("li").remove();
});

// With event delegation - works for dynamically added elements too
$("#task-list").on("click", ".delete-btn", function() {
    $(this).closest("li").remove();
});

The Office Manager Analogy

Event delegation is like having an office manager (parent element) who watches the door and directs visitors (events) to the right employee (child element), even if that employee was just hired today. Instead of training every employee to watch for visitors themselves, you have one person responsible for routing them correctly.

Event Delegation Flow User Click Parent Element #task-list Is click on .delete-btn? Yes No Handle the event Ignore the event

Common Events in Web Development

Event Type Description Example Usage
click When an element is clicked Button actions, menu toggles
submit When a form is submitted Form validation, AJAX form submission
change When an input's value changes Dynamic form behavior, real-time validation
keyup/keydown When a key is pressed/released Keyboard shortcuts, character counting
mouseover/mouseout When mouse enters/leaves an element Hover effects, tooltips
focus/blur When an element gains/loses focus Form field highlighting, showing help text
resize When the browser window is resized Responsive adjustments, layout recalculations
scroll When the user scrolls Infinite scrolling, sticky headers, lazy loading

Real-World Example: WordPress Admin Settings

In WordPress admin panels, jQuery is often used to create dynamic settings that change based on user selections:

// When the display type changes, show/hide relevant options
$("#display-type").on("change", function() {
    let displayType = $(this).val();
    
    // Hide all option groups first
    $(".option-group").hide();
    
    // Show only the relevant option group
    $("#" + displayType + "-options").show();
    
    // If grid is selected, show the columns option
    if (displayType === "grid") {
        $("#columns-option").show();
    }
});

jQuery Animations and Effects

jQuery provides easy-to-use methods for creating animations and effects:

Basic Effects

// Show and hide elements
$("#panel").hide(); // Instantly hide
$("#panel").show(); // Instantly show

// With animation duration (in milliseconds)
$("#panel").hide(500); // Fade out in 500ms
$("#panel").show(500); // Fade in in 500ms

// Toggle visibility
$("#panel").toggle(300); // Toggle with animation

// Sliding effects
$("#details").slideDown(400); // Slide down to reveal
$("#details").slideUp(400);   // Slide up to hide
$("#details").slideToggle(400); // Toggle sliding

// Fading effects
$("#notification").fadeIn(300);  // Fade in
$("#notification").fadeOut(300); // Fade out
$("#notification").fadeTo(300, 0.5); // Fade to specific opacity

Custom Animations

// Animate specific CSS properties
$("#box").animate({
    width: "80%",
    opacity: 0.8,
    fontSize: "24px",
    marginLeft: "50px"
}, 1000); // Duration in milliseconds

// With callback function (runs after animation completes)
$("#box").animate({ width: "80%" }, 1000, function() {
    // Animation finished
    $(this).addClass("animated");
});

// Animation with easing (requires jQuery UI or easing plugin)
$("#box").animate({ width: "80%" }, {
    duration: 1000,
    easing: "easeOutBounce",
    complete: function() {
        // Animation finished
    }
});

Real-World Example: WordPress Notice Dismissal

jQuery animations are often used in WordPress for UI feedback. Here's how you might implement a dismissible admin notice:

// When the dismiss button is clicked
$(".notice-dismiss").on("click", function() {
    // Find the parent notice
    let $notice = $(this).closest(".notice");
    
    // Animate the dismissal
    $notice.animate({
        opacity: 0,
        height: 0,
        paddingTop: 0,
        paddingBottom: 0,
        marginTop: 0,
        marginBottom: 0
    }, 300, function() {
        // After animation completes, remove the notice
        $(this).remove();
        
        // Send AJAX request to remember the dismissal
        $.ajax({
            url: ajaxurl, // WordPress AJAX URL
            type: 'POST',
            data: {
                action: 'dismiss_admin_notice',
                notice_id: $notice.data('notice-id'),
                nonce: $notice.data('nonce')
            }
        });
    });
});

AJAX with jQuery

jQuery simplifies AJAX (Asynchronous JavaScript and XML) requests, making it easy to fetch data without page reloads:

The Restaurant Waiter Analogy

Think of AJAX like a restaurant waiter. When you want to order more food (request more data), you don't leave the restaurant and come back (reload the page). Instead, the waiter (AJAX) takes your order to the kitchen (server) and brings back just what you asked for, while you continue enjoying your meal (using the website).

Basic AJAX Request

// Simple GET request
$.ajax({
    url: "api/data.json",
    type: "GET",
    dataType: "json",
    success: function(data) {
        // Handle the successful response
        console.log("Data received:", data);
    },
    error: function(xhr, status, error) {
        // Handle errors
        console.error("Error:", error);
    }
});

// Shorthand method for GET requests
$.get("api/data.json", function(data) {
    console.log("Data received:", data);
});

POST Requests

// POST request with data
$.ajax({
    url: "api/save-data",
    type: "POST",
    data: {
        name: "John Doe",
        email: "john@example.com"
    },
    success: function(response) {
        console.log("Data saved:", response);
    },
    error: function(xhr, status, error) {
        console.error("Error saving data:", error);
    }
});

// Shorthand method for POST requests
$.post("api/save-data", {
    name: "John Doe",
    email: "john@example.com"
}, function(response) {
    console.log("Data saved:", response);
});

AJAX with JSON

// Get and parse JSON data
$.getJSON("api/data.json", function(data) {
    // data is already parsed as a JavaScript object
    console.log("User name:", data.name);
});

AJAX in WordPress

WordPress has its own AJAX system that jQuery can work with:

In your WordPress PHP file:

// Add this in functions.php or your plugin file
function my_ajax_handler() {
    // Check nonce for security
    check_ajax_referer('my_ajax_nonce', 'security');
    
    // Process the request
    $name = sanitize_text_field($_POST['name']);
    
    // Do something with the data
    // ...
    
    // Send response back
    wp_send_json_success([
        'message' => 'Data processed successfully',
        'name' => $name
    ]);
    
    // Always exit at the end
    wp_die();
}

// Hook for logged-in users
add_action('wp_ajax_my_custom_action', 'my_ajax_handler');

// Hook for non-logged-in users (if needed)
add_action('wp_ajax_nopriv_my_custom_action', 'my_ajax_handler');

// Localize script to pass AJAX URL and nonce to JavaScript
function enqueue_my_scripts() {
    wp_enqueue_script('my-script', get_template_directory_uri() . '/js/script.js', ['jquery'], '1.0', true);
    
    wp_localize_script('my-script', 'myAjax', [
        'ajaxurl' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('my_ajax_nonce')
    ]);
}
add_action('wp_enqueue_scripts', 'enqueue_my_scripts');

In your JavaScript file:

// Using the WordPress AJAX URL and nonce
$("#submit-form").on("click", function() {
    $.ajax({
        url: myAjax.ajaxurl,
        type: 'POST',
        data: {
            action: 'my_custom_action', // Must match the action in PHP
            security: myAjax.nonce,      // Nonce for security
            name: $("#name-field").val() // Your data
        },
        success: function(response) {
            if (response.success) {
                alert(response.data.message);
            } else {
                alert('Error processing request');
            }
        }
    });
});

Real-World Example: Load More Posts

A common use of AJAX in WordPress is to implement "Load More" functionality for posts:

// In WordPress PHP:
function load_more_posts() {
    $page = $_POST['page'];
    $category = $_POST['category'];
    
    $args = array(
        'post_type' => 'post',
        'posts_per_page' => 5,
        'paged' => $page,
        'category_name' => $category
    );
    
    $query = new WP_Query($args);
    $response = array();
    
    if ($query->have_posts()) {
        ob_start();
        while ($query->have_posts()) {
            $query->the_post();
            get_template_part('template-parts/content', 'post');
        }
        $response['html'] = ob_get_clean();
        $response['has_more'] = $page < $query->max_num_pages;
    } else {
        $response['html'] = '';
        $response['has_more'] = false;
    }
    
    wp_send_json_success($response);
    wp_die();
}
add_action('wp_ajax_load_more_posts', 'load_more_posts');
add_action('wp_ajax_nopriv_load_more_posts', 'load_more_posts');

// In JavaScript:
let currentPage = 1;

$("#load-more-btn").on("click", function() {
    let $button = $(this);
    let category = $button.data("category");
    
    $button.text("Loading...");
    
    $.ajax({
        url: myAjax.ajaxurl,
        type: 'POST',
        data: {
            action: 'load_more_posts',
            page: currentPage + 1,
            category: category
        },
        success: function(response) {
            if (response.success) {
                // Append new posts
                $("#posts-container").append(response.data.html);
                
                // Update page counter
                currentPage++;
                
                // Show/hide the button based on whether more posts exist
                if (!response.data.has_more) {
                    $button.hide();
                } else {
                    $button.text("Load More");
                }
            }
        }
    });
});

Practical Tips and Best Practices

jQuery Performance Tips

  • Cache jQuery objects: Store frequently used selections in variables
  • Use specific selectors: Target elements precisely to avoid unnecessary DOM traversal
  • Delegate events: Use event delegation for dynamically created elements
  • Chain methods: Use method chaining to reduce code and improve performance
  • Use document fragments: Build complex DOM structures off-document before inserting

Bad Practice:

// Multiple DOM queries for the same element
$("#sidebar").css("background-color", "#f0f0f0");
$("#sidebar").addClass("active");
$("#sidebar").find("h2").text("New Title");

// Inefficient selectors
$("div div div a"); // Too generic and slow

// Adding elements one by one
for (let i = 0; i < 100; i++) {
    $("#list").append("<li>Item " + i + "</li>");
}

Good Practice:

// Cache jQuery objects
let $sidebar = $("#sidebar");
$sidebar.css("background-color", "#f0f0f0")
        .addClass("active")
        .find("h2").text("New Title");

// Specific selectors
$("#sidebar .content-links a"); // More specific and faster

// Building elements efficiently
let items = [];
for (let i = 0; i < 100; i++) {
    items.push("<li>Item " + i + "</li>");
}
$("#list").append(items.join(""));

Working with jQuery in WordPress

  • Use wp_enqueue_script: Always enqueue jQuery properly, don't hardcode script tags
  • Namespace your functions: Avoid conflicts with other plugins
  • Use noConflict mode: When working with other libraries that might use $
  • Check jQuery version: Be aware of which version WordPress is loading
  • Use WordPress hooks: Leverage the WordPress AJAX system instead of direct requests

jQuery noConflict Mode:

// In WordPress, jQuery is already in noConflict mode
// Instead of $ you can use jQuery
jQuery(document).ready(function($) {
    // Inside this function, you can use $ as normal
    $("#element").addClass("active");
});

// Or assign jQuery to a different variable
var $j = jQuery.noConflict();
$j("#element").addClass("active");

jQuery Alternatives and Modern JavaScript

While jQuery remains important for WordPress development, it's good to be aware of modern alternatives:

Vanilla JavaScript Improvements

Modern JavaScript (ES6+) has improved DOM manipulation capabilities:

jQuery Modern Vanilla JavaScript
$("#id") document.getElementById("id")
$(".class") document.querySelectorAll(".class")
$el.addClass("active") el.classList.add("active")
$el.on("click", handler) el.addEventListener("click", handler)
$.ajax({ url: "api" }) fetch("api").then(res => res.json())

Modern Frontend Frameworks

For complex applications, modern frameworks offer advantages over jQuery:

  • React: Component-based architecture, virtual DOM for performance
  • Vue.js: Progressive framework with easy integration path
  • Alpine.js: Lightweight framework for simple interactivity (sometimes used with WordPress)

When to Use jQuery in 2025

  • WordPress development: WordPress core still relies heavily on jQuery
  • Legacy project maintenance: When working with existing jQuery codebases
  • Quick prototyping: jQuery's simplicity makes it good for rapid development
  • Simple websites: For basic interactivity without the overhead of a framework
  • Cross-browser compatibility: jQuery handles browser differences well

Hands-on Exercise: Building a WordPress Custom Admin Widget

Let's apply what we've learned by creating a simple dashboard widget that uses jQuery:

PHP Code (plugin or functions.php):

// Register the dashboard widget
function notes_dashboard_widget() {
    wp_add_dashboard_widget(
        'quick_notes_widget',
        'Quick Notes',
        'render_notes_widget'
    );
}
add_action('wp_dashboard_setup', 'notes_dashboard_widget');

// Render the widget content
function render_notes_widget() {
    // Get saved notes
    $notes = get_option('quick_notes', []);
    
    // Output the widget HTML
    ?>
    <div id="quick-notes-widget">
        <ul id="notes-list">
            <?php foreach ($notes as $index => $note): ?>
                <li>
                    <span class="note-text"><?php echo esc_html($note); ?></span>
                    <button class="delete-note" data-index="<?php echo $index; ?>">×</button>
                </li>
            <?php endforeach; ?>
        </ul>
        
        <div class="add-note-form">
            <textarea id="new-note" placeholder="Add a quick note..."></textarea>
            <button id="add-note-btn" class="button button-primary">Add Note</button>
            <span class="spinner"></span>
        </div>
    </div>
    <?php
}

// Enqueue the JavaScript
function enqueue_notes_widget_script() {
    // Only on dashboard page
    if (get_current_screen()->base !== 'dashboard') {
        return;
    }
    
    wp_enqueue_script(
        'notes-widget-js',
        get_template_directory_uri() . '/js/notes-widget.js',
        ['jquery'],
        '1.0',
        true
    );
    
    wp_localize_script('notes-widget-js', 'notesWidget', [
        'ajaxurl' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('notes_widget_nonce')
    ]);
}
add_action('admin_enqueue_scripts', 'enqueue_notes_widget_script');

// AJAX handler for adding notes
function ajax_add_note() {
    check_ajax_referer('notes_widget_nonce', 'nonce');
    
    // Check permissions
    if (!current_user_can('edit_posts')) {
        wp_send_json_error('Permission denied');
    }
    
    $note = sanitize_textarea_field($_POST['note']);
    if (empty($note)) {
        wp_send_json_error('Note cannot be empty');
    }
    
    // Get existing notes and add the new one
    $notes = get_option('quick_notes', []);
    $notes[] = $note;
    
    // Save the updated notes
    update_option('quick_notes', $notes);
    
    // Return the index of the new note
    wp_send_json_success([
        'index' => count($notes) - 1,
        'note' => $note
    ]);
}
add_action('wp_ajax_add_note', 'ajax_add_note');

// AJAX handler for deleting notes
function ajax_delete_note() {
    check_ajax_referer('notes_widget_nonce', 'nonce');
    
    // Check permissions
    if (!current_user_can('edit_posts')) {
        wp_send_json_error('Permission denied');
    }
    
    $index = intval($_POST['index']);
    
    // Get existing notes and remove the specified one
    $notes = get_option('quick_notes', []);
    
    if (isset($notes[$index])) {
        unset($notes[$index]);
        $notes = array_values($notes); // Reindex the array
        update_option('quick_notes', $notes);
        wp_send_json_success();
    } else {
        wp_send_json_error('Note not found');
    }
}
add_action('wp_ajax_delete_note', 'ajax_delete_note');

JavaScript (notes-widget.js):

jQuery(document).ready(function($) {
    // Add a new note
    $("#add-note-btn").on("click", function() {
        let $button = $(this);
        let $spinner = $button.next(".spinner");
        let noteText = $("#new-note").val().trim();
        
        if (!noteText) {
            alert("Please enter a note");
            return;
        }
        
        // Disable button and show spinner
        $button.prop("disabled", true);
        $spinner.css("visibility", "visible");
        
        // Send AJAX request
        $.ajax({
            url: notesWidget.ajaxurl,
            type: "POST",
            data: {
                action: "add_note",
                nonce: notesWidget.nonce,
                note: noteText
            },
            success: function(response) {
                if (response.success) {
                    // Add the new note to the list
                    let newNote = $("<li>")
                        .append($("<span>").addClass("note-text").text(response.data.note))
                        .append($("<button>").addClass("delete-note").attr("data-index", response.data.index).text("×"));
                    
                    $("#notes-list").append(newNote);
                    
                    // Clear the textarea
                    $("#new-note").val("");
                } else {
                    alert("Error: " + response.data);
                }
            },
            error: function() {
                alert("An error occurred while saving the note");
            },
            complete: function() {
                // Re-enable button and hide spinner
                $button.prop("disabled", false);
                $spinner.css("visibility", "hidden");
            }
        });
    });
    
    // Delete a note (using event delegation)
    $("#notes-list").on("click", ".delete-note", function() {
        let $button = $(this);
        let $item = $button.closest("li");
        let index = $button.data("index");
        
        // Confirm deletion
        if (!confirm("Are you sure you want to delete this note?")) {
            return;
        }
        
        // Fade out the item
        $item.fadeOut(300);
        
        // Send AJAX request
        $.ajax({
            url: notesWidget.ajaxurl,
            type: "POST",
            data: {
                action: "delete_note",
                nonce: notesWidget.nonce,
                index: index
            },
            success: function(response) {
                if (response.success) {
                    // Remove the item from DOM completely after fade
                    $item.remove();
                } else {
                    // Show the item again if there was an error
                    $item.fadeIn(300);
                    alert("Error: " + response.data);
                }
            },
            error: function() {
                // Show the item again if there was an error
                $item.fadeIn(300);
                alert("An error occurred while deleting the note");
            }
        });
    });
});

CSS (Optional):

#quick-notes-widget {
    padding: 0 8px;
}

#notes-list {
    margin: 0 -8px;
    max-height: 200px;
    overflow-y: auto;
}

#notes-list li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px;
    margin-bottom: 5px;
    background: #f9f9f9;
    border-left: 3px solid #0073aa;
}

#notes-list .note-text {
    flex: 1;
}

.delete-note {
    background: none;
    border: none;
    color: #a00;
    cursor: pointer;
    font-size: 18px;
    padding: 0 5px;
}

.delete-note:hover {
    color: #dc3232;
}

#new-note {
    width: 100%;
    margin: 10px 0;
    min-height: 60px;
}

.add-note-form {
    margin-top: 15px;
    position: relative;
}

.add-note-form .spinner {
    float: none;
    margin-top: 4px;
}

Understanding the Code

This example demonstrates several jQuery concepts:

  • Event Handling: Click events for add and delete buttons
  • DOM Manipulation: Adding and removing notes from the list
  • Event Delegation: The delete button events work for dynamically added notes
  • AJAX: Sending requests to WordPress AJAX handlers
  • Animation: Using fadeOut for visual feedback during deletion

Additional Resources

Documentation and Tutorials

Useful jQuery Plugins for WordPress

  • jQuery UI: UI widgets and interactions
  • DataTables: Advanced table sorting and filtering
  • Select2: Enhanced select boxes
  • jQuery Validation: Form validation
  • Tooltipster: Customizable tooltips

Homework Assignment

To practice your jQuery skills, complete the following tasks:

  1. Refactor the JavaScript code from your Module 1 project using jQuery
  2. Implement at least three different jQuery effects or animations
  3. Create a form with jQuery validation
  4. Use jQuery AJAX to load content dynamically
  5. Challenge: Create a custom jQuery plugin that adds a specific functionality to your site

Submit your completed code before the next session for review.