Jamie Balfour

Welcome to my personal website.

Find out more about me, my personal projects, reviews, courses and much more here.

DASHThe all-in-one content management system

Setup difficulty: moderate
DASH

You can read more about DASH and why you would want it.

DASH

DASH, or DASH: Adaptable, Secure, High-performance is the content management system designed from the ground up without all the chrome.

You can find my DASH powered blog on my blog, but also with my articles and reviews as well.

You can see DASH 2.0 in action on my test blog found here.

DASH is an open-source blogging system that I have developed. Its purpose is to encourage the users to integrate a blog into their own website and keep their own styles. This is something that other blogging systems like WordPress struggle with.

A 280 post DASH blog only weighs in at 0.43MB of MySQL storage whereas a single page WordPress website comes in at a whopping 2.43MB. This is just a small point to make since no real strategies for analysing the difference here have been used, they have simply been compared at the point of installation and inserting 1 post into WordPress and 280 posts into DASH. DASH is a small application, currently it is currently sitting at 8010 total lines of PHP code.

The DASH project prides itself on simplicity and compactness by developing a lightweight content management mechanism that has been designed from the ground up with simple concepts in a framework that makes it efficient and well-designed.

To get started with DASH, all that is needed is a pre-existing website. DASH leaves all the styling to you, this means it fits on any website.

DASH also provides a tool called DASH Boost, which is a very efficient template parser that can make building a blog or content management system much easier.

DASH 2.0

Part of my commitment to DASH is the constant updating of features to ensure both stability and security. As part of this, I need to ensure that DASH 2.0 is developed very coherently.

As of the first versions of DASH, my code is very coherently written but unfortunately is not written in an object-oriented manner. My plan is to move to a more object based system.

DASH 2.0 aims to turn DASH from its current static singleton design to a more object-oriented, inheritance-based content manager. It also aims to allow multiple blogs or contents with one installation as the current one does but with more ease.

Further to this, DASH 2.0 intends to make installation even easier.

First update - DASH 2.0 is ready to go

Coupled with a back-end dashboard from DASH version 1.0, DASH 2.0 is ready to go!

The new DASH 2.0 features a hugely improved front-end that uses an object-oriented design to make it easier to switch blogs and to develop it how you want. DASH 2.0 introduces the ability to take advantage of DASH Boost - a parser that builds posts from templates. You can define as many templates as you want, store them where ever you want and add in as many variables as you want in DASH 2.0.

As mentioned, DASH 2.0 has no DASH Board yet meaning that you cannot insert, update or delete posts or do anything else you could do with the original DASH installation. However, DASH 2.0 is fully backward-compatible with DASH 1.0. What you can do in the meantime, is continue to use your old DASH 1.0's DASH Board to manage your posts and then use DASH 2.0 as the front-end. I don't expect DASH 2.0 to be like this for very long and imagine that DASH Board 2.0 will be available soon. You can find updates via my Twitter and blog.

My blog, articles and reviews are now using DASH 2.0 to power the front-ends of the content displayed on them! Check them out to see how they are very similar to the old versions of DASH yet are actually much more flexible.

Example of setup

The following is an example of the code used to generate the sample blog that is featured in every installation of DASH 2.0:

PHP
<?php
/*
	This is a demonstration of DASH on the front end
	Feel free to use and modify this code to your own liking
*/
include_once '../dash.php';

//Define these now to be used later on
define("POSTS_PER_PAGE", 10);
define("ASSETS_PATH", '/blog/assets/');
//I would suggest leaving this one since this figures out the root automatically
define("ROOT_BASE_PATH", str_replace($_SERVER['DOCUMENT_ROOT'], "", dirname(__FILE__)));

$page_number = 1;
$qry = "";

//The prefix for this database is Personal_Blog. DASH adds the rest so that it can find the right tables such as Personal_Blog_Posts or Personal_Blog_Categories
$dash = new Dash("blog");

$contentManager = $dash->getContentManager();
$query = $contentManager->createQueryObject();


//Checking to see if the user is searching for posts in a category
if(isset($_GET['qry'])){
	$qry = $_GET['qry'];
  $query->addSearchQuery(htmlentities($_GET['qry']));
}
//Checking to see if the user is searching for posts in a category
if(isset($_GET['category'])){
  $query->addCategoryQuery(htmlentities($_GET['category']));
}
//Checking to see if the user is searching for a specific date
if(isset($_GET['date'])){
  $query->addDateQuery($_GET['date']);
}

//If the user has changed page
if(isset($_GET['page'])){
  $page_number = $_GET['page'];
}

if(!isset($_GET['post'])){
	//If we are not looking at an individual post here
	//All posts or post based on a query
	$posts = $contentManager->fetchPosts($page_number, POSTS_PER_PAGE, true);
	//Read the template
	$template = file_get_contents('templates/blog.html');
} else{
	//The user has requested an individual post
	$post = $contentManager->fetchPostByName($_GET['post'], true);
	//Read the template
	$template = file_get_contents('templates/individual.html');
}



//This section is fairly specific to my website
$page = new Page();
$page->UseMathjax(true);

//If no posts are found
if($contentManager->getPostCount() == 0){
	$page->SetBreadcrumbs(array(ROOT_BASE_PATH => "Blog"));
	$page->PageTitle("<sub>Jamie Balfour's</sub>Articles");
	//On my website I use the GenerateHead function to generate the top part of the website
	$page->GenerateHead();
	//On my website I use the GenerateFoot function to generate the bottom part of the website
	echo 'No posts found that match this criteria.';
	$page->GenerateFoot();
	exit;
}

//Perform all parsing using DASH Boost
$parser = new DashTemplateParser($template);
$template = $parser->parse();

if(!isset($_GET['post'])){
	//If we are not looking at an individual post here
	$page->SetBreadcrumbs(array(ROOT_BASE_PATH => "Dash Demo"));
	$page->PageTitle("<sub>Jamie Balfour's</sub>Personal Blog");
} else{
	//The user has requested an individual post
	$page->SetBreadcrumbs(array(ROOT_BASE_PATH => "Dash Demo", "/posts/".$_GET['post'] => $post->getTitle()));
	$page->PageTitle($post->getTitle());
}

//On my website I use the GenerateHead function to generate the top part of the website
$page->GenerateHead();
//And the GenerateSearch function to generate a search box for my website

if(!isset($_GET['post'])){
	//If we are not looking at an individual post here
  $page_link = ROOT_BASE_PATH .'pages/';
	if(isset($_GET['category'])){
		$page_link = ROOT_BASE_PATH . 'categories/'.$_GET['category'].'/'."pages/";
	}
  if(isset($_GET['qry'])){
		$page_link = ROOT_BASE_PATH . 'search/'.$_GET['qry'].'/'."pages/";
	}
  if(isset($_GET['date'])){
		$page_link = ROOT_BASE_PATH . 'date/'.$_GET['date'].'/'."pages/";
	}
	$pagination = $contentManager->generateBlogPagination($page_number, POSTS_PER_PAGE, $page_link);
  echo $pagination;
  $type = "article_view";
} else{
  $type = "individual_post";
  $posts = array($post);
}

echo '<div class="dash '.$type.'">';

foreach($posts as $post){

	$assets_path = $contentManager->getPostAssetsPath($post);

	$values = array();
	$values['FRIENDLY_NAME'] = $post->getFriendlyName();
  $values['POST_TITLE'] = $post->getTitle();
  $values['POST_LINK'] = ROOT_BASE_PATH.'posts/'.$post->getFriendlyName();
  $values['POST_DATE'] = $post->getDate();
  $values['POST_DATE_LINK'] = ROOT_BASE_PATH.'date/'.date("Y-m-d", strtotime($post->getDate()));
  $values['POST_DATE_TEXT'] = '<span class="day">'.date("d", strtotime($post->getDate())).'</span><span class="month">'.date("M", strtotime($post->getDate())).'</span><span class="year">'.date("Y", strtotime($post->getDate())).'</span>';
	$values['POST_POSTER_TEXT'] = $contentManager->getUserFromID($post->getPoster())->getUsername();
	$values['POST_CATEGORY_TEXT'] = $contentManager->getCategoryFromID($post->getCategory())->getName();
	$values['POST_CATEGORY'] = $contentManager->getCategoryFromID($post->getCategory())->getName();
	$values['POST_CATEGORY_LINK'] = ROOT_BASE_PATH.'categories/'.urlencode($contentManager->getCategoryFromID($post->getCategory())->getFriendlyName());
  $values['POST_CONTENT'] = str_replace("{ASSETS}", $assets_path, $post->getContent());
	$values['POST_INTRODUCTION'] = htmlentities($post->getIntroduction());
  $values['POST_TAGS'] = $contentManager->generateTagString($post->getTags());
  $values['IS_ADMIN'] = isJamieBalfour();
  $values['IS_HIDDEN_POST'] = $post->isHiddenPost();
  $values['IS_UNAVAILABLE_POST'] = $post->isUnavailablePost();
  $values['IS_LISTED_POST'] = $post->isListedPost();

	if($post->hasBannerImage()){
		$values['POST_IMAGE'] = str_replace("{ASSETS}", $assets_path, $post->getBannerImage());
	}

  echo $parser->traverseAST($template, $values);

}

echo '</div>';


if(!isset($_GET['post'])){
  echo $pagination;
}

//On my website I use the GenerateFoot function to generate the bottom part of the website
$page->GenerateFoot();
?>