Demos, Blog, PHP & MySQL, Tutorials

Blog Series


This tutorial is extending the Creating a blog from scratch with PHP with that in mind I will only be covering new pieces of code and not the whole codebase.

(It's worth pointing out this tutorial only exists because one of my readers asked for it. I love to help when I can so if you need a tutorial you can always ask me for it.)

This part will cover adding tags to the posts.

admin demo: https://daveismyname.blog/demos/simpleblog-tags/admin

username: demo
password: demo

The tags will be added into another column of the database table so add another column your database table called postTags that's a varchar data type and uses 255 chars.

Next we need to add the ability to add your tags to the add and edit posts pages within the admin. Open admin/add-post.php

Add this input for the tags:

<p><label>Tags (comma seperated)</label><br />
<input type='text' name='postTags' value='<?php if(isset($error)){ echo $_POST['postTags'];}?>' style="width:400px;"></p>

You can place with anywhere you like within the form tags.

Now update the insert code starting at line 64:

$stmt = $db->prepare('INSERT INTO blog_posts_seo (postTitle,postSlug,postDesc,postCont,postDate,postTags) VALUES (:postTitle, :postSlug, :postDesc, :postCont, :postDate, :postTags)') ;
$stmt->execute(array(
    ':postTitle' => $postTitle,
    ':postSlug' => $postSlug,
    ':postDesc' => $postDesc,
    ':postCont' => $postCont,
    ':postDate' => date('Y-m-d H:i:s'),
    ':postTags' => $postTags
));

This now includes the postTags.

Now open admin/edit-post.php replace the update code on line 69 with this:

$stmt = $db->prepare('UPDATE blog_posts SET postTitle = :postTitle, postSlug = :postSlug, postDesc = :postDesc, postCont = :postCont, postTags = :postTags WHERE postID = :postID') ;
$stmt->execute(array(
    ':postTitle' => $postTitle,
    ':postSlug' => $postSlug,
    ':postDesc' => $postDesc,
    ':postCont' => $postCont,
    ':postID' => $postID,
    ':postTags' => $postTags
));

Next we need to add postTags to the select query on line 118:

$stmt = $db->prepare('SELECT postID, postTitle, postDesc, postCont, postTags FROM blog_posts WHERE postID = :postID') ;

add this input for updating the tags:

<p><label>Tags (comma seperated)</label><br />
<input type='text' name='postTags' value='<?php echo $row['postTags'];?>' style="width:400px;"></p>

Save these 2 files you are now done with the admin. At this point, you can add tags to your posts by placing a comma after each tag in the forms.

Now we need to move to the front end and add the tags to the pages.

Open .htaccess

For the tags to be clickable they need a path to follow. Add this rule on line 4

RewriteRule ^t-(.*)$ tagpost.php?id=$1 [L]

This will allows the url domain.com/t-sometag to work the important part is the (.*) in the pattern above this means when using -t anything after it will be passed as an argument.

the full file looks like this:

RewriteEngine On
RewriteBase /simpleblog/

RewriteRule ^c-(.*)$ catpost.php?id=$1 [L]
RewriteRule ^t-(.*)$ tagpost.php?id=$1 [L]

RewriteCond %{REQUEST_FILENAME} !-d [NC]
RewriteCond %{REQUEST_FILENAME} !-f [NC]
RewriteRule ^(.*)$ viewpost.php?id=$1 [QSA,L]

Now into index.php which is the home page of the blog and add postTags to the select query on line 23:

$stmt = $db->query('SELECT postID, postTitle, postSlug, postDesc, postDate, postTags FROM blog_posts ORDER BY postID DESC');

Now we want to show the tags add this after line 43:

echo '<p>Tagged as: ';
    $links = array();
    $parts = explode(',', $row['postTags']);
    foreach ($parts as $tag)
    {
        $links[] = "<a href='t-".$tag."'>".$tag."</a>";
    }
    echo implode(", ", $links);
echo '</p>';

This will create an array from the postTags where it finds a comma. Each line will be wrapped inside of a link and then printed to the page.

This same process needs to be applied a few more times in the following pages:

Open catpost.php and replace the query on line 37

$stmt = $db->prepare('
    SELECT 
        blog_posts.postID, blog_posts.postTitle, blog_posts.postSlug, blog_posts.postDesc, blog_posts.postTags, blog_posts.postDate 
    FROM 
        blog_posts,
        blog_post_cats
    WHERE
         blog_posts.postID = blog_post_cats.postID
         AND blog_post_cats.catID = :catID
    ORDER BY 
        postID DESC
    ');

Next add this to line 69:

echo '<p>Tagged as: ';
$links = array();
$parts = explode(',', $row['postTags']);
foreach ($parts as $tag)
{
    $links[] = "<a href='t-".$tag."'>".$tag."</a>";
}
echo implode(", ", $links);
echo '</p>';

Next open viewpost.php update the query to include the postTags on line 5

$stmt = $db->prepare('SELECT postID, postTitle, postCont, postDate, postTags FROM blog_posts WHERE postSlug = :postSlug');

Next, add this to line 52

echo '<p>Tagged as: ';
$links = array();
$parts = explode(',', $row['postTags']);
foreach ($parts as $tag)
{
    $links[] = "<a href='t-".$tag."'>".$tag."</a>";
}
echo implode(", ", $links);
echo '</p>';

That's all the existing files updated the last thing to do is create a file called tagpost.php this will be the page to show posts that match a clicked tag.

<?php require('includes/config.php'); ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Blog - <?php echo htmlspecialchars($_GET['id']);?></title>
    <link rel="stylesheet" href="style/normalize.css">
    <link rel="stylesheet" href="style/main.css">
</head>
<body>

	<div id="wrapper">

		<h1>Blog</h1>
		<p>Posts matching tag: <?php echo htmlspecialchars($_GET['id']);?></p>
		<hr />
		<p><a href="./">Blog Index</a></p>

		<div id='main'>

			<?php	
			try {

                $stmt = $db->prepare('SELECT postID, postTitle, postSlug, postDesc, postDate, postTags FROM blog_posts_seo WHERE postTags like :postTags ORDER BY postID DESC');
                $stmt->execute(array(':postTags' => '%'.$_GET['id'].'%'));
				while($row = $stmt->fetch()){
					
					echo '<div>';
						echo '<h1><a href="'.$row['postSlug'].'">'.$row['postTitle'].'</a></h1>';
						echo '<p>Posted on '.date('jS M Y H:i:s', strtotime($row['postDate'])).' in ';

							$stmt2 = $db->prepare('SELECT catTitle, catSlug FROM blog_cats, blog_post_cats WHERE blog_cats.catID = blog_post_cats.catID AND blog_post_cats.postID = :postID');
							$stmt2->execute(array(':postID' => $row['postID']));

							$catRow = $stmt2->fetchAll(PDO::FETCH_ASSOC);

							$links = array();
							foreach ($catRow as $cat)
							{
							    $links[] = "<a href='c-".$cat['catSlug']."'>".$cat['catTitle']."</a>";
							}
							echo implode(", ", $links);

						echo '</p>';
                    echo '<p>Tagged as: ';
                    $links = array();
                    $parts = explode(',', $row['postTags']);
                    foreach ($parts as $tag)
                    {
                        $links[] = "<a href='t-".$tag."'>".$tag."</a>";
                    }
                    echo implode(", ", $links);
                    echo '</p>';
						echo '<p>'.$row['postDesc'].'</p>';				
						echo '<p><a href="'.$row['postSlug'].'">Read More</a></p>';				
					echo '</div>';

				}

			} catch(PDOException $e) {
			    echo $e->getMessage();
			}

			?>

		</div>

		<div id='sidebar'>
			<?php require('sidebar.php'); ?>
		</div>

		<div id='clear'></div>

	</div>


</body>
</html>

The important part of this page is this query:

$stmt = $db->prepare('SELECT postID, postTitle, postSlug, postDesc, postDate, postTags FROM blog_posts WHERE postTags like :postTags ORDER BY postID DESC');
$stmt->execute(array(':postTags' => '%'.$_GET['id'].'%'));

This added the postTags and also does a search where the tag that is clicked on is passed as a search param. The tag is stored inside $_GET['id'] this comes from the .htaccess file.

That completes the needed changes you can now add tags to your posts and be able to see them across your pages and click on them to see matching posts.