How To Create an Anchor CMS Theme

Last month, I posted about creating your own Bootstrap theme based on some new ways of doing things and today, I’m going to use that same Bootstrap theme to skin Anchor CMS, a pretty lean sweet content management system. If you don’t know what it is and why you should use it, read my review.

To summarize, it’s basically a content management system built on modern PHP technology meant to serve designers who want to show off their skills per article. It can easily be used as a front-end programming playground but also as a very slick and innovative blog.

The great thing about Anchor is that it can be quickly and easily themed. It follows similar theming conventions as WordPress so it’s not at all difficult jumping into it.

Download Preview

File Structure

First, let’s note the file structure. All themes are in the /themes folder at the root of the site. Let’s create a folder called thought-anchor inside and start our development. Here are the files we’ll be creating:

css/
    app.css
    bootstrap.min.css
    theme.css
fonts/
    ...bootstrap fonts...
img/
    basic-header.jpg
js/
    bootstrap.js
    jquery.js
less/
    ...front-end less files...

404.php
about.txt
article.php
footer.php
function.php
header.php
page.php
posts.php
search.php
sidebar.php

The structure will seem a little familiar; however, you’ll notice readily that there is no index.php and that’s fine. So let me first say that the subfolders are all voluntary. I wanted to keep a LESS version of my theme and compile it into the /css folder along with other files. As you can see, I’m keeping everything very disjointed, again, on purpose.

I won’t be covering the styling nor the javascript, you’re welcome to just copy over my Bootstrap 3 theme repo and add the app.css file for customization.

So, the files:

  • 404.php - Self-explanatory. A basic 404 page template
  • about.txt – Instead of dirtying up our CSS file with theme information, we use this file. Anchor interprets the information in the file and pulls it in. This file will include the theme’s name, description, author’s name, and author’s site.
  • article.php - this is the equivalent of “single.php”. This file is used for a single blog article
  • footer.php - self-explanatory, this is where your footer goes. It gets included from here into all the other files
  • function.php – similar to WordPress, this file can contain any and all custom functions you’d like to use in your theme
  • header.php - header template
  • page.php - single page template
  • posts.php – This is the equivalent of “index.php”. It contains the list of your articles. It’s used for blog pages and category pages
  • search.php - the template file for search results
  • sidebar.php - while not necessary, it’s a file I use to add a sidebar to every page I specify. Easier than copy-pasting, at least to me.

About, Header, and Footer

Let’s start on the basics. Create your theme folder and create the about.txt, header.php, and footer.php files. First, let’s tackle the about file. It’s basically a property:value type file with properties separated by new lines:

Theme Name: Thought Essays
Description: This is AntJanus's Thought Essays Theme
Author Name: Antonin Januska
Author Site: http://antjanus.com

This will ensure that Anchor parses through that info and gives us this in return (in the admin):

thought-essays-appearance

 

Next up, let’s work on the header. I’ve made a few decisions here that many of you may not agree with:

  • I decided to use category names as items for my naviagation
  • I decided to keep my CSS files separated (bootstrap.css, theme.css, and app.css) for easier updates

Alright, let’s see what we can do. First, let’s go over the “head” part:

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title><?php echo page_title('Page can’t be found'); ?> - <?php echo site_name(); ?></title>

  <meta name="description" content="<?php echo site_description(); ?>">
  <link rel="stylesheet" href="<?php echo theme_url('/css/bootstrap.css'); ?>">
  <link rel="stylesheet" href="<?php echo theme_url('/css/theme.css'); ?>">
  <link rel="stylesheet" href="<?php echo theme_url('/css/app.css'); ?>">

  <link rel="alternate" type="application/rss+xml" title="RSS" href="<?php echo rss_url(); ?>">
  <link rel="shortcut icon" href="<?php echo theme_url('img/favicon.png'); ?>">

    <!--[if lt IE 9]>
      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
      <![endif]-->
      <script src="<?php echo theme_url('/js/jquery.js'); ?>"></script>
      <script src="<?php echo theme_url('/js/bootstrap.min.js'); ?>"></script>

      <meta name="viewport" content="width=device-width">
      <meta name="generator" content="Anchor CMS">

      <meta property="og:title" content="<?php echo site_name(); ?>">
      <meta property="og:type" content="website">
      <meta property="og:url" content="<?php echo current_url(); ?>">
      <meta property="og:image" content="<?php echo theme_url('img/og_image.gif'); ?>">
      <meta property="og:site_name" content="<?php echo site_name(); ?>">
      <meta property="og:description" content="<?php echo site_description(); ?>">

      <?php if(customised()): ?>
      <!-- Custom CSS -->
      <style><?php echo article_css(); ?></style>

      <!--  Custom Javascript -->
      <script><?php echo article_js(); ?></script>
    <?php endif; ?>

  </head>

What a wall of code. Most of this stuff should be familiar to you (as far as html goes), so let’s focus on the anchor specific stuff.

<title><?php echo page_title('Page can’t be found'); ?> - <?php echo site_name(); ?></title>

First, the title. Anchor has a few neat functions. One of them is page_title, why? Because it allows you to pass through the default page title for a 404. Anyways, pretty self-explanatory outside of that.

  <link rel="stylesheet" href="<?php echo theme_url('/css/bootstrap.css'); ?>">
  <link rel="stylesheet" href="<?php echo theme_url('/css/theme.css'); ?>">
  <link rel="stylesheet" href="<?php echo theme_url('/css/app.css'); ?>">

We’re linking to our stylesheets. Notice that we have a theme_url function that always refers back to the theme’s root folder. This is pretty useful. Also, why 3 stylesheets? Well, if you read my tutorial on creating modern Bootstrap themes, you’ll find that I talk about separation of CSS. The Bootstrap distribution is pretty vanilla with a couple of variable changes. The theme.css is based off my original Thought Theme. And finally, the “app.css” file refers directly to the anchor implementation. In the future, I’d definitely like to implement some sort of minification to the process.

Anyways, the javascript lines mirror the CSS deal, so let’s move onto opengraph:

      <meta property="og:title" content="<?php echo page_title(); ?>">
      <meta property="og:type" content="website">
      <meta property="og:url" content="<?php echo current_url(); ?>">
      <meta property="og:site_name" content="<?php echo site_name(); ?>">
      <meta property="og:description" content="<?php echo site_description(); ?>">

Taken directly from the Anchor CMS default theme, these little lines of code make it easier for Facebook, Twitter, and Google Plus to figure out what your site is about. Facebook has a bunch of docs available to explain this feature. We’re also introduce to some new Anchor functions. Luckily, I’m sure you can figure these out based on the og properties.

      <?php if(customised()): ?>
      <!-- Custom CSS -->
      <style><?php echo article_css(); ?></style>

      <!--  Custom Javascript -->
      <script><?php echo article_js(); ?></script>
    <?php endif; ?>

Custom CSS and Javascript. This is where Anchor gets interesting. Technically, you could create this feature in WordPress in no time at all but it’s nice that it’s actually built into Anchor. You can customize every article page on the site via custom per-page CSS and JS.

custom-css-js

If you ever fill these two textareas out in the backend, it’ll trigger the customised() function to return true for that article.

Next up, the navigation:

  <body class="<?php echo body_class(); ?>">
    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
          </button>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
            <?php while(categories()): ?>
            <li>
              <a href="<?php echo category_url(); ?>" title="<?php echo category_title(); ?>">
                <?php echo category_title(); ?>
              </a>
            </li>
          <?php endwhile; ?>
        </ul>
      </div>
      <!--/.navbar-collapse -->
    </div>
  </div>
  <div class="jumbotron">
    <div class="container">
      <h1>
        <a href="<?php echo base_url(); ?>"><?php echo site_name(); ?></a>
      </h1>
      <br />
      <h3><?php echo site_description(); ?></h3>
    </div>
  </div>

For navigation, I obviously used categories. But let’s back up a bit. We’ve got some great functions here:

<?php echo body_class();?>
<?php echo base_url();?>

Body class is basically a way to let CSS know what kind of a page you’re on. If you’re on a posts.php page, it’ll say “posts” and if you’re on the home page as well, it’ll say “posts home”. And base_url is exactly what you’d expect it to be.

So to create our menu, we used the following loop:

            <?php while(categories()): ?>
            <li>
              <a href="<?php echo category_url(); ?>" title="<?php echo category_title(); ?>">
                <?php echo category_title(); ?>
              </a>
            </li>
          <?php endwhile; ?>

The categories function should always be accessible to you when templating. When calling it, you can easily just do a while and use its title and url properties to create a menu or a sidebar widget. To finish off our header, I added a jumbotron with the site’s name and description. The result so far:

thought-essay-headerSo what about our measly footer? This one’s the easiest:

<div class="container">
<hr />
<p>
    Created by <a href="http://antjanus.com">AntJanus</a>
</p>
</div>
  </body>

</html>

Let’s move onto the next part, our posts.php page.

Posts.php

Posts.php is used to create a list of our content. It’s the “index.php” of WordPress. Here’s how it will look like:

anchor-postsAnd it’s quite simple. First, let’s include the header file:

<?php theme_include('header'); ?>

This will make sure we have our header included on every posts page, and let’s get started with the loop.

<div class="container" id="content">
  <div class="row">
    <div class="col-md-2 visible-md visible-lg">
     &nbsp;
   </div>
   <div class="col-md-7">
    <?php if(has_posts()):
    while(posts()): ?>
    <article class="post">
      <h2>
        <a href="<?php echo article_url(); ?>" title="<?php echo article_title(); ?>"><?php echo article_title(); ?></a>
      </h2>
      <small class="meta">
        <?php echo article_author();?> | <time datetime="<?php echo date(DATE_W3C, article_time()); ?>"><?php echo article_date();?></time>
      </small><br />
      <?php echo article_description();?>
    </article>
    <hr />
  <?php endwhile; ?>

Notice that the “if” loop is still opened, I’ll address that (and close it) after I go over this part. Again, same deal as WordPress. We have a has_posts() function that checks if posts are present, then we start the while() loop on posts. I haven’t found a “query_loops” alternative in anchor yet, meaning that the posts loop will only work on the posts and category pages. Next, we have a few (self explanatory) functions:

  • article_url() gives you an article’s url
  • article_title() for the title
  • article_author() for the author
  • article_date() for the date. I’m also using the date function for the <time> tag. Checkout what it does and it’s importance.
  • article_description() for its short description

You’ll be entering all of this information per article on the back-end. Checkout the docs to see more of the article related functions. I’m using bootstrap 3′s regular styling so don’t mind some of the “class=”posts”” and “meta” classes, they’re not actually being styled.

So what happens when you have more than the default number of posts? You’ll have to get pagination. Luckily, anchor has that built in:

?php if(has_pagination()): ?>
  <nav class="pagination">
      <?php echo posts_prev(); ?>
      <?php echo posts_next(); ?>
  </nav>
<?php endif; ?>

Add this right below the previous code and you’ll get a simple “<- Previous” “Next ->” links at the bottom of the posts.

previous

So, one more thing. Let’s close the loop and finish up the page.

<?php else: ?>
  <p>Looks like you have some writing to do!</p>
<?php endif; ?>
</div>
<div class="col-md-3" id="sidebar">
  <?php theme_include('sidebar'); ?>
</div>
</div>
</div>

<?php theme_include('footer'); ?>

Line by line. The “else” will ensure that we display SOMETHING to the user when there are no posts. The if(has_posts()) will fail.

 

Next, I wanted to create a sidebar so we’ll just pre-emptively include it and the same with the footer.

Congratulations! We have our home/category/posts pages done!

Sidebar

Quick, let’s do the sidebar. So technically, Anchor doesn’t have any special “sidebar” functions, widgets, or anything like WordPress does. I decided to tie in the search field with the sidebar so we could actually have one. Again, this is custom.

<div class="widget">
  <h3>
    Search
  </h3>
  <form action="<?php echo search_url(); ?>" method="get">
  <div class="input-group">
    <input type="search" class="form-control" name="term" id="term">
    <span class="input-group-btn">
      <input type="submit" value="Search!" class="btn btn-default">
    </span>
  </form>
</div>

Those are the entire contents of it. The only anchor-specific thing here is the search_url() function which will give you the url where you need to post your search query. Make sure you’re using “get” and that your search field is named “term”. This will ensure anchor knows what you’re talking about.

Article

Next up is our article page. The flow will be similar to the posts page except we won’t need a “posts()” loop. Here’s what we’re trying to create:

anchor-cms-article-pageWe basically want a left sidebar with meta information and right sidebar with search and content in the middle. Not bad.

<?php theme_include('header'); ?>

<div class="container" id="content">
  <div class="row">
    <div class="col-md-2 visible-md visible-lg">
      <p>
        <strong><?php echo article_author();?></strong>
        <br />
        <time datetime="<?php echo date(DATE_W3C, article_time()); ?>"><?php echo article_date();?></time>
        <br />
        <strong>About: </strong> <?php echo article_author_bio();?>
      </p>
    </div>
    <div class="col-md-7">
      <h1 class="post-title">
        <?php echo article_title(); ?>
      </h1>
      <p class="meta visible-sm visible-xs">
        <?php echo article_author();?> | <time datetime="<?php echo date(DATE_W3C, article_time()); ?>"><?php echo article_date();?></time>
      </p>
      <?php echo article_markdown(); ?>
    </div>
    <aside class="col-md-3" id="sidebar">
      <?php theme_include('sidebar'); ?>
    </aside>
  </div>
</div>

<?php theme_include('footer'); ?>

You should be used to the flow now. We specified the same meta information for the left sidebar (starting with the col-md-2 classed div), and then we moved onto the main content with the col-md-7 class. You’ll see that the meta information is repeated, this is because it’s information only visible for phones in horizontal/vertical view. The left sidebar disappears in that view. Here’s what it looks like:

responsive-view-articleI think it looks better than some 100% width meta sidebar. Weird. Anyways, one cool thing we can use is the article_markdown() function which automatically converts your markdown into html.

And last of all, regular sidebar and then footer.

Congratulations! We’re almost done :)

Page, 404, and Search

You should have a pretty clear idea on how to build the pages now. Figure out what main function groups to use (article, page, post) and then apply what information you’d like to present on the page (name, url, etc.). Let’s tackle page.

Create a page.php file. Here’s what to fill it with:

<?php theme_include('header'); ?>

<div class="container" id="content">
  <div class="row">
    <div class="col-md-2 visible-md visible-lg">
        &nbsp;
    </div>
    <div class="col-md-7">
      <h1 class="post-title">
        <?php echo page_title(); ?>
    </h1>
    <?php echo page_content(); ?>
</div>
<aside class="col-md-3" id="sidebar">
    <?php theme_include('sidebar'); ?>
</aside>
</div>
</div>

<?php theme_include('footer'); ?>

See? Not that hard, we’re, once again, including the header and footer. We’re using our existing html structure and switching a few things out. I left the left (col-md-2) column empty mainly because of possible future use and because of easier styling. It’s not a good practice but get over it :). And again, we have  page_title() and  page_content() functions that display what we want it to display.

Next up, 404 page. The 404 page, obviously, displays when the user hits a 404 error.

<?php theme_include('header'); ?>

<div class="container" id="content">
 <div class="row">
    <div class="col-md-2 visible-md visible-lg">
        &nbsp;
    </div>
    <div class="col-md-7">
      <h1 class="post-title">
       404 - Not Found
    </h1>
</div>
<aside class="col-md-3" id="sidebar">
    <?php theme_include('sidebar'); ?>
</aside>
</div>
</div>

<?php theme_include('footer'); ?>

Same thing as before, except this time we’re just letting the user know that the page they were looking for was not found. Bummer.

So what about the search page? This one is a bit more complicated:

<?php theme_include('header'); ?>

<div class="container" id="content">
 <div class="row">
    <div class="col-md-2 visible-md visible-lg">
      &nbsp;
    </div>
    <div class="col-md-7">
      <h1 class="post-title">
        You searched for &ldquo;<?php echo search_term(); ?>&rdquo;.
      </h1>
      <?php if(has_search_results()): ?>
      <?php while(search_results()): ?>
      <article class="post">
        <h2>
          <a href="<?php echo article_url(); ?>" title="<?php echo article_title(); ?>"><?php echo article_title(); ?></a>
        </h2>
      </article>
    <?php endwhile; ?>
    <?php if(has_pagination()): ?>
    <nav class="pagination">
      <?php echo posts_prev(); ?>
      <?php echo posts_next(); ?>
    </nav>
  <?php endif; ?>

<?php else: ?>
  <p>Unfortunately, there's no results for &ldquo;<?php echo search_term(); ?>&rdquo;. Did you spell everything correctly?</p>
<?php endif; ?>
</div>
<aside class="col-md-3" id="sidebar">
  <?php theme_include('sidebar'); ?>
</aside>
</div>
</div>

<?php theme_include('footer'); ?>

Reminds you of the posts page, right? It works similarly. Instead of using has_posts(), we’re using has_search_results() and then we’re copying our posts template. If there are no results, we’re giving the users a default message. Note that we’re not giving the users the article_description(); however, you can easily add it yourself. I just prefer not to.

What about comments? (optional)

I prefer to use Disqus for commenting because I go through TONS of CMS and blogs and what have you so, here’s how I implemented that. This is an optional step. Create a comments.php file. Paste the following code in:

<?php if(comments_open()): ?>
    <div id="disqus_thread"></div>
    <script type="text/javascript">
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
        var disqus_shortname = 'REPLACE!!!!'; // required: replace example with your forum shortname

        /* * * DON'T EDIT BELOW THIS LINE * * */
        (function() {
          var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
          dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
          (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
      })();
      </script>
      <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
      <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>

<?php endif; ?>

We’re using Anchor’s built-in commenting function to check if comments are allowed on the page or not. If they are, we use the Disqus snippet to show comments. Now we just need to include the comments file in the article.php file.

Add the following under <?php echo article_markdown();?>

<?php theme_include('comments');?>

And you’re done. Here’s the final result.

anchor-disqus

Custom Functions

Just like WordPress, Anchor features a functions.php file. Here, you can place functions that you’d like to globally use in your theme. The creator of Anchor made a neat list of them in his default theme. Here’s a sample:

function count_words($str) {
    return count(preg_split('/s+/', strip_tags($str), null, PREG_SPLIT_NO_EMPTY));
}

If we wanted to display the number of words an article has, we could easily do so by passing the article content into the functions like so:

<strong>Word Count: </strong> <?php echo count_words(article_markdown()); ?>

It’ll be automatically included so make sure that you don’t mess up the file and cause yourself a bunch of PHP errors!

Conclusion

As you can see, building an Anchor theme is pretty simple. You can pretty much build a few html templates and sprinkle in the PHP to make it a theme. It’s that easy.

If you have any questions about the process, feel free to comment. You can also check the forum!

Download Preview

Add Your Comment