Skip to content

Tariqbaloch786/Blog_System

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Blog System

A modern, clean PHP blog system with admin panel, built using PHP (MySQLi) and vanilla JavaScript.

Project Structure

Blog_System/
├── admin/                    # Admin Panel
│   ├── add-article.php       # Create new article
│   ├── comments.php          # Manage article comments
│   ├── edit-article.php      # Edit existing article
│   ├── index.php             # Admin dashboard
│   ├── login.php             # Admin login
│   ├── logout.php            # Admin logout
│   ├── messages.php          # Contact form messages
│   ├── settings.php          # Site settings (About, Contact info)
│   └── upload-image.php      # TinyMCE image upload handler
├── css/
│   ├── admin.css             # Admin panel styles
│   ├── frontend.css          # Frontend styles (main)
│   └── style.css             # Additional styles
├── gif/
│   ├── blog_system_logo.svg  # Site logo
│   └── favicon.ico           # Favicon
├── includes/
│   ├── auth.php              # Admin authentication
│   ├── config.php            # Database & site configuration
│   ├── footer.php            # Shared footer
│   └── header.php            # Shared header
├── js/
│   ├── admin.js              # Admin panel JavaScript
│   └── main.js               # Frontend JavaScript
├── uploads/                  # Uploaded images
├── .htaccess                 # Apache URL rewriting & security
├── 403.php                   # Forbidden error page
├── 404.php                   # Not found error page
├── about.php                 # About page
├── article.php               # Single article view
├── articles.php              # All articles listing (paginated)
├── contact.php               # Contact form page
├── database.sql              # Database schema
├── index.php                 # Homepage
├── most-read.php             # Most viewed articles
└── README.md                 # This file

Installation

Requirements

  • XAMPP (or similar: PHP 7.4+, MySQL 5.7+, Apache with mod_rewrite)
  • Web browser

Setup Steps

  1. Copy files to c:\xampp\htdocs\Blog_System\

  2. Create the database:

    • Open phpMyAdmin
    • Create database: blog_system
    • Import database.sql file
  3. Enable mod_rewrite (for clean URLs):

    • Open C:\xampp\apache\conf\httpd.conf
    • Find #LoadModule rewrite_module modules/mod_rewrite.so
    • Remove the # to uncomment it
    • Ensure AllowOverride All is set for htdocs directory
    • Restart Apache
  4. Configure (optional):

    • Edit includes/config.php to change site name or URL
  5. Access the site:

Features

Frontend

  • Responsive design with mobile navigation
  • Article listing with pagination
  • Single article view with comments
  • Most read articles page
  • About and Contact pages
  • Clean URLs for articles (/article/my-article-slug)
  • SEO-friendly meta tags
  • Creative fonts (Playfair Display + Poppins)

Admin Panel

  • Dashboard with statistics
  • Article CRUD operations
  • TinyMCE rich text editor with image upload
  • Comment moderation (approve/hide/delete)
  • Contact message management
  • Site settings (About page, Contact info)
  • Toggle article visibility

URL Structure

Clean URLs

Articles use clean, SEO-friendly URLs powered by Apache mod_rewrite:

Clean URL Internal
/article/my-post article.php?url=my-post

.htaccess rule:

RewriteEngine On
RewriteBase /Blog_System/

# Clean URLs for articles: /article/slug -> article.php?url=slug
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^article/([^/]+)/?$ article.php?url=$1 [L,QSA]

Article URL Slug

The slug (article_url) is a URL-friendly identifier for each article.

Creation (admin/add-article.php):

// Clean URL (make it URL friendly)
$article_url = preg_replace('/[^a-zA-Z0-9-]/', '-', strtolower($article_url));
$article_url = preg_replace('/-+/', '-', $article_url);  // Remove multiple dashes
$article_url = trim($article_url, '-');  // Remove leading/trailing dashes

Fetching (article.php):

// Get article URL from query string
$article_url = isset($_GET['url']) ? trim($_GET['url']) : '';

// Fetch article by slug
$stmt = mysqli_prepare($conn, "SELECT * FROM articles WHERE article_url = ? AND is_visible = 1");
mysqli_stmt_bind_param($stmt, 's', $article_url);
mysqli_stmt_execute($stmt);

Usage in links:

<a href="article/<?php echo urlencode($article['article_url']); ?>">
    <?php echo htmlspecialchars($article['article_title']); ?>
</a>

How Things Work

Mobile Menu Toggle

The mobile hamburger menu uses JavaScript to toggle a CSS class.

HTML Structure (all pages):

<button class="menu-toggle" onclick="toggleMenu()">
    <span></span><span></span><span></span>
</button>

<ul class="nav-menu" id="navMenu">
    <li><a href="index.php">Home</a></li>
    <!-- more links -->
</ul>

JavaScript (js/main.js):

function toggleMenu() {
    var menu = document.getElementById('navMenu');
    menu.classList.toggle('active');
}

// Close menu when clicking outside
document.addEventListener('click', function(e) {
    var menu = document.getElementById('navMenu');
    var toggle = document.querySelector('.menu-toggle');
    if (menu && toggle) {
        if (!menu.contains(e.target) && !toggle.contains(e.target)) {
            menu.classList.remove('active');
        }
    }
});

Meta Title, Description & Keywords

SEO meta tags are stored per article and rendered in the <head> section.

Database Schema (articles table):

meta_title VARCHAR(255) NOT NULL,
meta_description TEXT,
meta_keywords VARCHAR(255),

Fetching & Rendering (article.php):

// Fetch article (includes meta fields)
$article = mysqli_fetch_assoc($result);

// Set page meta data
$page_title = $article['meta_title'] . ' - ' . SITE_NAME;
$meta_description = $article['meta_description'];
$meta_keywords = $article['meta_keywords'];

HTML Output:

<head>
    <meta name="description" content="<?php echo htmlspecialchars($meta_description); ?>">
    <meta name="keywords" content="<?php echo htmlspecialchars($meta_keywords); ?>">
    <title><?php echo htmlspecialchars($page_title); ?></title>
</head>

Image Handling

Featured Image (Thumbnail):

  • Uploaded via file input in admin
  • Stored in uploads/ folder
  • Filename saved in articles.featured_image column
  • Displayed on article cards (listing pages)

Content Images:

  • Uploaded via TinyMCE editor
  • Handled by admin/upload-image.php
  • Stored in uploads/ folder
  • Embedded in article_description as HTML <img> tags

View Counter

Increment on Page Load (article.php):

// Increment view counter
mysqli_query($conn, "UPDATE articles SET user_views = user_views + 1 WHERE id = " . $article['id']);
$article['user_views']++;  // Update local variable for display

Comments System

Submission Flow:

  1. User submits comment form
  2. Comment saved with is_approved = 0 (pending)
  3. Redirect with success message (PRG pattern)
  4. Admin approves in dashboard
  5. Only approved comments shown on frontend

PRG Pattern (Post-Redirect-Get):

if (mysqli_stmt_execute($stmt)) {
    // Redirect to prevent form resubmission
    header('Location: article/' . urlencode($article_url) . '?comment=success#comments');
    exit;
}

Database Schema

articles

Column Type Description
id INT Primary key
article_url VARCHAR(255) URL slug (unique)
meta_title VARCHAR(255) SEO title
meta_description TEXT SEO description
meta_keywords VARCHAR(255) SEO keywords (comma-separated)
article_title VARCHAR(255) Display title
article_description LONGTEXT Article content (HTML)
featured_image VARCHAR(255) Thumbnail filename
is_visible TINYINT(1) 1=visible, 0=hidden
user_views INT View counter
created_at TIMESTAMP Creation date
updated_at TIMESTAMP Last update date

comments

Column Type Description
id INT Primary key
article_id INT Foreign key to articles
user_name VARCHAR(100) Commenter name
user_email VARCHAR(150) Commenter email (optional)
comment_text TEXT Comment content
is_approved TINYINT(1) 1=approved, 0=pending
created_at TIMESTAMP Submission date

site_settings

Column Type Description
id INT Primary key
setting_key VARCHAR(100) Setting identifier
setting_value LONGTEXT Setting content
updated_at TIMESTAMP Last update date

Settings Keys:

  • about_title - About page title
  • about_content - About page HTML content
  • contact_email - Contact email
  • contact_phone - Contact phone
  • contact_address - Contact address

contact_messages

Column Type Description
id INT Primary key
sender_name VARCHAR(100) Sender name
sender_email VARCHAR(150) Sender email
subject VARCHAR(255) Message subject
message TEXT Message content
is_read TINYINT(1) 1=read, 0=unread
created_at TIMESTAMP Submission date

Configuration

Site Settings (includes/config.php)

// Database
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'blog_system');

// Site
define('SITE_NAME', 'Simple Blog System');
define('SITE_URL', 'http://localhost/Blog_System/');

Security Features

The .htaccess file provides several security measures:

  • Directory listing disabled - Prevents browsing folder contents
  • Protected sensitive files - Blocks access to config.php, auth.php
  • Protected includes folder - Returns 403 for /includes/ requests
  • Hidden files blocked - Files starting with . are inaccessible
  • Backup files blocked - .bak, .sql, .log files blocked
  • Security headers - X-Content-Type-Options, X-Frame-Options, X-XSS-Protection

Typography

The site uses Google Fonts:

  • Playfair Display - Headings (elegant serif)
  • Poppins - Body text (clean sans-serif)

Color Scheme

  • Navbar Background: #3d4354
  • Primary Blue: #2563eb
  • Text Dark: #111827
  • Text Medium: #4b5563
  • Text Light: #6b7280

License

About

PHP Blog System with CI/CD Pipeline (Docker, Jenkins, AWS, Prometheus, Grafana)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published