Topics to categorize posts
I'm not only going to write about my php framework. I want to write about other things as well, but I still want it to be easy to find and follow posts on a specific topic. We have tags but they do not really do the trick. So today we are going to implement a topic to the site.
First of all we set up the database table. Which in this case is really simple.
// Add table topic
CREATE TABLE IF NOT EXISTS `topic` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=1;
// Add relation to topic in post
ALTER TABLE `post` ADD `topic_id` INT NOT NULL AFTER `title`, ADD INDEX (`topic_id`);
After adding a set of topics and inserting them into my posts I want to update the menu so that I get a filter on top where I can filter on topic when selecting posts. But first we need to create a Topic class.
// classes/Topic.php
<?php
class Topic extends Db {
public $table = 'topic';
}
Now I have rewritten the post_menu.php in order to add the topic at the top of the menu.
// views/post/post_menu.php
<div>
<div id="menu_topic">
<div id="topic_0" class="topic_button">All</div>
<?php
// Show all my topics
$topic = new Topic();
$tList = $topic->fetchArray();
foreach($tList as $item) {
?>
<div id="topic_<?php echo $item->id; ?>" class="topic_button"><?php echo $item->name; ?></div>
<?php
}
?>
</div>
<?php
// Show all my posts
$post = new Post();
$pList = $post->fetchArray('WHERE publish < '' . date('Y-m-d H:i:s') . '' ORDER BY publish DESC LIMIT 20');
foreach($pList as $item) {
?>
<a href="<?php echo $item->linkTitle(); ?>-<?php echo $item->id; ?>" class="topic_<?php echo $item->topicId; ?> post_link">
<div class="sub_menu_title"><?php echo $item->title; ?></div>
<div class="sub_menu_info"><?php echo $item->tags; ?> - <?php echo $item->posted; ?></div>
</a>
<?php
}
?>
</div>
// css/main.css
#menu_topic {
display: flex;
flex-wrap: wrap;
line-height: 50px;
justify-content: flex-start;
align-content: flex-start;
margin: 0px !important;
padding: 0px !important;
margin-left: 0px !important;
padding-left: 25px !important;
padding-right: 25px !important;
margin-right: 0px !important;
padding-top: 0px !important;
padding-bottom: 0px !important;
}
.topic_button {
cursor: pointer;
padding-left: 10px;
padding-right: 10px;
}
.topic_button:hover {
background: #GreyNormal;
}
// js/main.js
// Topic menu
var topicBtn = document.getElementsByClassName('topic_button');
var i = 0;
while (i < topicBtn.length) {
addListener(topicBtn[i], 'click', topic_click);
i++;
}
function topic_click(e) {
// if id == 0 then show all else hide all
var postLink = document.getElementsByClassName('post_link');
var i = 0;
while (i < postLink.length) {
if (e.target.id === 'topic_0' || hasClass(postLink[i], e.target.id)) {
postLink[i].style.display = null;
} else {
postLink[i].style.display = 'none';
}
i++;
}
};
As you can see the code contains a function called hasClass. So I just going to add three functions that handles classes in the top of my js Framework part.
// js/main.js
// Manage classes in html elements
function hasClass(ele,cls) {
return !!ele.className.match(new RegExp('(s|^)'+cls+'(s|$)'));
}
function addClass(ele,cls) {
if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp('(s|^)'+cls+'(s|$)');
ele.className=ele.className.replace(reg,' ');
}
}
I also want to make it easier to follow the posts on a specific topic. So on each post I'm going to add a link to the previous and the next post on that specific topic. First I need to write some code that actually find the related topics. Then I'll add them as links in the bottom of the post.
// classes/post.php
function getPrev() {
$qry = 'SELECT id, title '
. 'FROM post '
. 'WHERE topic_id=' . $this->topicId . ' '
. ' AND id<' . $this->id . ' '
. 'ORDER BY id DESC '
. 'LIMIT 1';
$res = Db::query($qry);
$row = Db::fetch_array($res);
$obj = new Post();
$obj->id = $row['id'];
$obj->title = $row['title'];
return $obj;
}
function getNext() {
$qry = 'SELECT id, title '
. 'FROM post '
. 'WHERE topic_id=' . $this->topicId . ' '
. ' AND id>' . $this->id . ' '
. 'ORDER BY id '
. 'LIMIT 1';
$res = Db::query($qry);
$row = Db::fetch_array($res);
$obj = new Post();
$obj->id = $row['id'];
$obj->title = $row['title'];
return $obj;
}
Then I'll just add the links in the post item page.
// view/post/item.php
<div class="navigation">
<?php
$prev = $obj->getPrev();
$next = $obj->getNext();
?>
<a <?php if ((int)$prev->id > 0) { ?>
href="<?php echo $prev->linkTitle(); ?>-<?php echo $prev->id; ?>"<?php } ?>
><?php if ((int)$prev->id > 0) { ?><< <?php echo $prev->title; ?><?php } ?></a>
<a <?php if ((int)$next->id > 0) { ?>
href="<?php echo $next->linkTitle(); ?>-<?php echo $next->id; ?>"<?php } ?>
><?php if ((int)$next->id > 0) { ?><?php echo $next->title; ?> >><?php } ?></a>
</div>
// css/main.css
.navigation {
display: flex;
justify-content: space-between;
padding-left: 30px;
padding-right: 30px;
}
- framework, php, categories, software