In today’s web development landscape, dominated by complex JavaScript frameworks and extensive build tools, it’s easy to forget the powerful simplicity of the classic web stack. For years, jQuery, paired with a server-side language like PHP and a relational database like MySQL, was the undisputed king of dynamic web applications. While the ecosystem has evolved with giants like React, Vue.js, and Angular, the core principles of fetching, displaying, and managing data remain the same. This article revisits this classic approach to demonstrate how to build a robust, efficient, and maintainable news portal application. We’ll explore how jQuery’s elegant simplicity for DOM manipulation and AJAX, combined with the raw power of SQL for data management, still offers a compelling solution for many projects.

The Foundation: Database Schema and Core Queries

Before writing a single line of JavaScript, a successful news application needs a solid data foundation. The structure of your database dictates how efficiently you can store, retrieve, and relate information. For our news portal, we’ll need to store articles, categorize them, and associate them with authors. A well-designed relational database schema is paramount for performance and scalability.

Designing the News Schema

Let’s design a simple but effective schema with three main tables: articles, categories, and a pivot table article_categories to handle a many-to-many relationship (since one article can belong to multiple categories). This structure provides flexibility and avoids data redundancy.

-- Table for storing news articles
CREATE TABLE articles (
    article_id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    slug VARCHAR(255) NOT NULL UNIQUE,
    content TEXT NOT NULL,
    author_id INT,
    publish_date DATETIME DEFAULT CURRENT_TIMESTAMP,
    status ENUM('draft', 'published', 'archived') DEFAULT 'draft',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Table for categorizing articles
CREATE TABLE categories (
    category_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL UNIQUE,
    slug VARCHAR(100) NOT NULL UNIQUE,
    description VARCHAR(255)
);

-- Pivot table to link articles and categories (many-to-many)
CREATE TABLE article_categories (
    article_id INT,
    category_id INT,
    PRIMARY KEY (article_id, category_id),
    FOREIGN KEY (article_id) REFERENCES articles(article_id) ON DELETE CASCADE,
    FOREIGN KEY (category_id) REFERENCES categories(category_id) ON DELETE CASCADE
);

Querying for the Homepage Feed

With the schema in place, the most common operation will be fetching the latest published articles for the homepage. This query needs to be fast and efficient. We’ll join the tables to get the article details along with their associated categories. Notice the use of WHERE status = 'published' and ORDER BY publish_date DESC to ensure we only get relevant, recent content.

SELECT
    a.article_id,
    a.title,
    a.slug,
    LEFT(a.content, 200) AS excerpt, -- Create a short excerpt
    a.publish_date,
    GROUP_CONCAT(c.name SEPARATOR ', ') AS categories
FROM
    articles a
LEFT JOIN
    article_categories ac ON a.article_id = ac.article_id
LEFT JOIN
    categories c ON ac.category_id = c.category_id
WHERE
    a.status = 'published'
GROUP BY
    a.article_id
ORDER BY
    a.publish_date DESC
LIMIT 20;

Pro Tip: For a high-traffic news site, performance is key. To optimize this query, you should add indexes to frequently queried columns. An index on articles.publish_date and articles.status would dramatically speed up the filtering and sorting process.

MySQL database schema - Database schema in MySQL | Download Scientific Diagram
MySQL database schema – Database schema in MySQL | Download Scientific Diagram
-- Add indexes to improve query performance
CREATE INDEX idx_articles_status_publish_date ON articles(status, publish_date DESC);
CREATE INDEX idx_article_categories_category_id ON article_categories(category_id);

Bringing News to the Frontend with jQuery AJAX

Once the backend is ready to serve data (e.g., via a PHP script that executes our SQL query and returns JSON), we can use jQuery to fetch this data and display it on the page without a full reload. This is where jQuery’s famous $.ajax() method shines. It simplifies the process of making asynchronous HTTP requests, which is the cornerstone of any dynamic web application, whether it’s a simple jQuery News site or a complex portal built with modern tools like Next.js News or Nuxt.js News.

Fetching Articles Asynchronously

Let’s assume we have a backend endpoint at /api/get-articles.php that returns a JSON array of articles based on the query above. We can write a simple jQuery script to call this endpoint when the page loads and then pass the data to another function to render it.

// Wait for the document to be fully loaded
$(document).ready(function() {
    
    // Function to render articles to the DOM
    function renderArticles(articles) {
        const articlesContainer = $('#articles-container');
        articlesContainer.empty(); // Clear existing content

        if (!articles || articles.length === 0) {
            articlesContainer.html('<p>No articles found.</p>');
            return;
        }

        $.each(articles, function(index, article) {
            const articleHtml = `
                <div class="article-card">
                    <h3><a href="/articles/${article.slug}">${article.title}</a></h3>
                    <p class="excerpt">${article.excerpt}...</p>
                    <div class="meta">
                        <span class="date">Published on: ${new Date(article.publish_date).toLocaleDateString()}</span>
                        <span class="categories">Categories: ${article.categories || 'N/A'}</span>
                    </div>
                </div>
            `;
            articlesContainer.append(articleHtml);
        });
    }

    // Fetch articles using AJAX
    function fetchArticles() {
        $.ajax({
            url: '/api/get-articles.php',
            method: 'GET',
            dataType: 'json',
            beforeSend: function() {
                // Show a loading spinner
                $('#articles-container').html('<p>Loading news...</p>');
            },
            success: function(response) {
                // On success, render the articles
                if (response.status === 'success') {
                    renderArticles(response.data);
                } else {
                    $('#articles-container').html('<p>Error: ' + response.message + '</p>');
                }
            },
            error: function(jqXHR, textStatus, errorThrown) {
                // Handle network or server errors
                console.error("AJAX Error:", textStatus, errorThrown);
                $('#articles-container').html('<p>Could not connect to the server. Please try again later.</p>');
            }
        });
    }

    // Initial fetch on page load
    fetchArticles();
});

This snippet demonstrates several best practices: separating data fetching from rendering, handling loading and error states, and using jQuery’s utility functions like $.each() for iteration. This clear separation of concerns makes the code easier to read and maintain.

Dynamic Content and User Interaction

A static list of articles is a good start, but a real news portal needs interactivity. Features like infinite scrolling or a “Load More” button provide a much better user experience than traditional pagination. With jQuery, implementing this is straightforward. We can extend our previous script to handle loading subsequent pages of articles.

Implementing a “Load More” Button

news website wireframe - Newspaper website wireframe
news website wireframe – Newspaper website wireframe

We’ll add a button to our HTML and an event listener in our jQuery code. Each time the button is clicked, we’ll request the next page of articles from our API. The backend will need to be updated to accept a page parameter. This pattern is fundamental and is seen in everything from a Backbone.js News app to a modern Svelte News implementation.

// This code would be added inside the $(document).ready() function from the previous example

let currentPage = 1;
const articlesPerPage = 20;

// Update the fetchArticles function to accept a page number
function fetchArticles(page = 1) {
    const articlesContainer = $('#articles-container');
    const loadMoreBtn = $('#load-more-btn');

    $.ajax({
        url: '/api/get-articles.php',
        method: 'GET',
        dataType: 'json',
        data: { 
            page: page,
            limit: articlesPerPage 
        },
        beforeSend: function() {
            loadMoreBtn.text('Loading...').prop('disabled', true);
        },
        success: function(response) {
            if (response.status === 'success' && response.data.length > 0) {
                // On the first page, we replace content. On subsequent pages, we append.
                if (page === 1) {
                    articlesContainer.empty();
                }
                // We can reuse our renderArticles function, but we need to modify it to append instead of replace.
                // For this example, let's just append directly.
                appendArticles(response.data);

                // If fewer articles than the limit are returned, we've reached the end.
                if (response.data.length < articlesPerPage) {
                    loadMoreBtn.hide();
                } else {
                    loadMoreBtn.show();
                }
            } else {
                // No more articles to load
                loadMoreBtn.hide();
                if (page === 1) {
                     articlesContainer.html('<p>No articles found.</p>');
                }
            }
        },
        error: function() {
            articlesContainer.append('<p class="error">Failed to load more articles.</p>');
        },
        complete: function() {
            loadMoreBtn.text('Load More').prop('disabled', false);
        }
    });
}

// A simple function to append articles
function appendArticles(articles) {
    const articlesContainer = $('#articles-container');
    $.each(articles, function(index, article) {
        const articleHtml = `<!-- ... same HTML structure as before ... -->`;
        articlesContainer.append(articleHtml);
    });
}


// Event listener for the "Load More" button
$('#load-more-btn').on('click', function() {
    currentPage++;
    fetchArticles(currentPage);
});

// Initial fetch
fetchArticles(currentPage);

Ensuring Data Integrity with Transactions

While fetching data is a read operation, writing data requires more care. When a journalist publishes a new article, several database operations need to happen: the article itself must be inserted into the articles table, and its corresponding categories must be linked in the article_categories table. If one of these operations fails, we could end up with inconsistent data—an article with no categories, for example. This is where SQL transactions are essential. A transaction ensures that a series of operations are treated as a single, atomic unit. Either all operations succeed, or they all fail and the database is rolled back to its previous state.

Publishing an Article Atomically

The following SQL snippet (which would be executed by your server-side code, e.g., PHP) demonstrates how to wrap the process of creating an article and linking its categories within a transaction. This guarantees data integrity. This principle is universal, whether you’re using a backend like Express.js News, NestJS News, or a full-stack framework like RedwoodJS News.

news website wireframe - Newspaper website wireframe by Ziya Fenn on Dribbble
news website wireframe – Newspaper website wireframe by Ziya Fenn on Dribbble
-- Start the transaction
START TRANSACTION;

-- Use placeholders for actual values (e.g., ?, ?, ?) in a real application
-- to prevent SQL injection.
-- Assume we have the article data and an array of category IDs [1, 3]

-- 1. Insert the new article
INSERT INTO articles (title, slug, content, author_id, status)
VALUES ('New Breakthrough in AI', 'new-breakthrough-in-ai', '...', 1, 'published');

-- 2. Get the ID of the article we just inserted
SET @last_article_id = LAST_INSERT_ID();

-- 3. Insert the category links into the pivot table
-- This would typically be done in a loop in the application code
INSERT INTO article_categories (article_id, category_id) VALUES (@last_article_id, 1);
INSERT INTO article_categories (article_id, category_id) VALUES (@last_article_id, 3);

-- If all commands were successful, commit the transaction to make the changes permanent
COMMIT;

-- If any command failed, the application logic should issue a ROLLBACK
-- ROLLBACK;

By using a transaction, you ensure that the news platform’s data remains consistent and reliable, which is critical for any content management system. This robust backend logic provides a stable foundation for any frontend, from one built with jQuery News to more modern ones using libraries like Lit News or even 3D visualizations with Three.js News.

Conclusion: The Enduring Value of Simplicity

While the modern web development ecosystem offers incredibly powerful tools like Vite, Webpack, TypeScript, and frameworks such as React and Vue.js, there is an undeniable elegance and efficiency in the classic jQuery and SQL stack. For projects like a news portal, where the primary goal is to display dynamic content from a database, this combination is often more than sufficient. It minimizes dependencies, reduces build complexity, and offers excellent performance when backed by a well-designed database schema.

By understanding the fundamentals of SQL transactions, efficient querying, and asynchronous data fetching with jQuery, developers can build fast, reliable, and easy-to-maintain web applications. The principles explored here—structuring data, fetching it efficiently, rendering it dynamically, and ensuring its integrity—are timeless. They are just as relevant for a developer building a SolidJS News app with Bun News on the backend as they were for the pioneers of the dynamic web a decade ago.