Blog Series
- Part 1 - The Build
- Part 2 - SEO URLS
- Part 3 Comments with Disqus
- Part 4 Categories
- Part 5 Sidebar, Categories and Archives
- Part 6 Pagination
- Part 7 Tags
- Part 8 Tags Sidebar
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.
Demo: https://demos.dcblog.dev/simpleblog-tags/
admin demo: https://dcblog.dev/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_seo 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_seo 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 allow 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_seo 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_seo.postID, blog_posts_seo.postTitle, blog_posts_seo.postSlug, blog_posts_seo.postDesc, blog_posts_seo.postTags, blog_posts_seo.postDate
FROM
blog_posts_seo,
blog_post_cats
WHERE
blog_posts_seo.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_seo 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_seo 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.