Build a PHP minimal Blog


When I was about to create this new fancy blog for my website, I was wondering what would be the easiest way to implement it without losing much time programming. Moments later, I was doing the same thing I always do when something could be just straight forward. Using an existing framework? Would you say...
... 🤦‍♂️

Noup! I created my own ultra-minimal framework to handle it. But that is great because now I can blog in my blog about the blog! 🤯
If that makes any sense at all.





</>  Source Code github.com/daniruiz/PHP-blog
daniruiz/PHP-blog is licensed under the MIT License



Let's start defining what we need

First of all, I refused to mess around with any database. But on the other hand, I wanted to separate the title (so that I can use it for a custom URL), store the writing date, and have everything separated and well ordered. So I decided to store each post in separate files within the same directory, using their names to save the corresponding date and title.

Utilizing this method, this post, for example, would be stored as:
20191028-Build a PHP minimal Blog.html

To handle it, I defined a Post class with two main methods (from_url and get_posts) as described below:

class Post {
    const POSTS_CONTENT_DIR = 'posts/'; // Posts directory
    const NUM_PREVIEW_PARAGRAPHS = 4; // Number of elements for the post preview

    public $title;
    public $content;
    public $preview;
    public $date_time;
    public $date_string;
    
    
    private function __construct ($file) {
        // Configure Post data from file
    }
    
    public static function from_url ($url) {
        // * Get title pattern from $url
        // * Find closest matching post
        // * Use newest post as a fallback, instead of 404
        // * Generate and return corresponding post object
    }
    
    public static function get_posts () {
        // * Get list of posts from the directory specified in POSTS_CONTENT_DIR
        // * Return an array containing each corresponding Post instance
    }
}

Getting into the code

/blog.php

This file is used only to print the correspondent post, according to the URL. Once the Post object is defined, the only thing left to do is writing the information with the desired design.

<?php
    include 'php/Post.php';
    $POST = Post::from_url($_SERVER['REQUEST_URI']);
?>

<article>
    <h1><?php echo $POST->title ?></h1>
    <time datetime="<?php echo $POST->date_time ?>">
        <?php echo $POST->date_string ?>
    </time>
    <br>
    <?php echo $POST->content ?>
</article>

Last but not least, configure the server to use the blog.php script for all URLs like /blog/.... Modifying the .htaccess file, you can achieve it by adding the following lines:

/.htaccess

    RewriteEngine On
    RewriteBase /

    RewriteRule ^blog blog.php

/index.php

This file shows a list of the latest blogs, previewing them with their main starting paragraphs. Its functionality is almost identical to blog.php but iterating through the post array given by Post::get_posts()

<?php
    include 'php/Post.php';
    $POSTS = Post::get_posts();
?>

<?php foreach ($POSTS as $post) { ?>
    <article>
        <a href="/blog/<?php echo $post->title ?>">
            <h1><?php echo $post->title ?></h1>
        </a>
        <time datetime="<?php echo $post->date_time ?>">
            <?php echo $post->date_string ?>
        </time>
        <br>
        <?php echo $post->preview; ?>
        <a class="read-more-button" href="/blog/<?php echo $post->title ?>">
            Read more ↦
        </a>
    </article>
    <hr/>
<?php } ?>

/php/Post.php

Finally, here is the Post class complete code, just in case you want to take a look:

class Post {
    const POSTS_CONTENT_DIR = 'posts/';
    const NUM_PREVIEW_PARAGRAPHS = 4;

    public $title;
    public $content;
    public $preview;
    public $date_time;
    public $date_string;

    private function __construct ($file) {
        preg_match('/^(\d{8})-(.+)\.html$/', $file, $matches);
        $this->content = mb_convert_encoding(
                file_get_contents(self::POSTS_CONTENT_DIR . $file),
                'HTML-ENTITIES', 'UTF-8');
        $document = new DOMDocument();
        $document->loadHTML("<body>{$this->content}</body>");
        $children = $document->getElementsByTagName('body')->item(0)->childNodes;

        $paragraphs = 0;
        foreach ($children as $child) {
            $this->preview .= $document->saveHTML($child);
            if (get_class($child) !== 'DOMText') $paragraphs++;
            if ($paragraphs === self::NUM_PREVIEW_PARAGRAPHS) break;
        }
        list(, $rawDate, $this->title) = $matches;
        $date = new DateTime($rawDate);
        $this->date_time = $date->format('Y-m-d');
        $this->date_string = $date->format('F j, Y');
    }

    public static function from_url ($url) {
        $title_pattern = urldecode(basename($url));
        $post_files = glob(self::POSTS_CONTENT_DIR . '????????-*.html');
        $file = array_pop($post_files);
        foreach ($post_files as $post_file)
            if (preg_match("/\d{8}-.*$title_pattern.*.html/i", $post_file))
                $file = $post_file;
        return new self(basename($file));
    }

    public static function get_posts () {
        return array_map(function ($post_file) {
            return new self(basename($post_file));
        }, array_reverse(glob(self::POSTS_CONTENT_DIR . '????????-*.html')));
    }
}

Projects

Flat Remix cover

Flat Remix ICON theme

Flat Remix GNOME theme

Flat Remix GNOME theme

Flat Remix GTK theme

Flat Remix GTK theme

Flat Remix KDE themes

Flat Remix KDE themes

Flat Remix css library

Flat Remix CSS Library

Neural network with genetic algorithms in Unity3d

Neural network with genetic algorithms

~/.dotfiles

~/.dotfiles

Ethenis Framework logo

Ethenis Framework

Color Fixer logo

Color Fixer


Consider supporting my work with a Donation 😉