Create a WordPress Theme

Written by: Lee Miller on 20 June 2020

Introduction

In this guide we’ll walk through the theme creation process, which as you’ll soon find out is surprisingly simple if you have project files, what I call a WordPress skeleton, which will get you started quickly and can lead to creating a theme in less than a day.

In truth the Skeleton theme took 2 days to create, but, I was writing this guide as I was developing the theme, so it gives you first hand knowledge of the development process, at least my process, I have no clue how other developers work.

The aim of this article is for you to learn how to create a theme. I’ve provided the skeleton files below, but to get the best from the guide you should use the files in combination with the following information if you’re to have a solid foundation in the theme development process.

This guide is for anyone that wants to create WordPress themes, you may be using a theme builder and want to move onto hand coding and to make things easier we’re going to use Bootstrap 4.5 and several Bootstrap 4 starter templates.

We’ll also be using Font Awesome 5 via a plugin – more info below.

I also assume you have a fresh install of WordPress.

And at the end of the guide we’ll test the theme using the plugin Theme Sniffer to verify that the skeleton theme is valid and attempt to submit to WordPress.org.

Part One

style.css

Everything starts with style.css, it’s the file that WordPress uses to register the theme, and contains the styling for the theme, I also use it to import font files and other external libraries required for a project.

/*
Theme Name: Skeleton
Theme URI: https://leemiller.club/documents/create-a-wordpress-theme/
Author: Lee Miller
Author URI: https://leemiller.club
Description: Free theme implementing Bootstrap 4.5
Version: 1.0
License: Creative Commons Attribution license
License URI: https://creativecommons.org/licenses/by/3.0/
Tags: bootstrap, bootstrap 4, bootstrap 4.5, blue, red, black, white, one-column, two-columns, right-sidebar, left-sidebar, flexible-width, custom-header, custom-menu, featured-images, translation-ready
Text Domain: 
*/

@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@100;300;400;500;700;900&display=swap');

/* Add custom styles here */

During the development process make sure that the stylesheet you use is unminified for ease of editing. We’ll discuss minification later in the guide.

screenshot.png

Using the included screenshot.png as a template, create a screenshot of your theme. The recommended image size is 1200px wide by 900px tall.

Template files

Create the following template files in your theme root folder, personally I don’t use the complete list, but you are welcome to add these later if you wish to do so.

404.php
archive.php
archive-portfolio.php
archive-news.php
footer.php
front-page.php
functions.php
header.php
index.php
page.php
single.php
sidebar-left.php
sidebar-right.php
single-news.php
single-portfolio.php

Theme folders

Create the following folders in the theme root folder.

js
css

And the following folder in the wp-content folder – we’ll be using this folder further below, when we add custom post types, which will be used to add custom menu’s to footer.php.

mu-plugins

Theme Activation

Once you have your template files you can go ahead and activate your theme and view your site in a new window. At this stage the window will be completely blank, don’t worry this is normal.

Font Awesome

Create a Font Awesome account, activate the account, create and grab the API token. Visit plugins and install and activate the official Font Awesome 5 plugin.

Visit settings Font Awesome and add your kit API token and save the settings.

Note that you’re only allowed one kit per account, but you can upgrade to a pro account to use on multiple sites, or use another email address.

functions.php

functions.php is used to register stylesheets and scripts, it is also used to add theme support. I also use this file to load essential plugins, but for the purposes of this guide we’ll not be doing that, as it’s not the recommended procedure.

Open up functions.php in your preferred code editor, I use Sublime Text, which is available for OSX, Windows and Linux.

And add the following;

<?php

function skeleton_scripts() {
    wp_enqueue_style( 'main_style', get_stylesheet_uri() );
    wp_enqueue_style( 'Bootstrap_style', get_template_directory_uri() . '/css/bootstrap.min.css' );
    wp_enqueue_script( 'bootrap_script', get_template_directory_uri() . '/js/bootstrap.bundle.min.js', array(), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'skeleton_scripts' );

function skeleton_features () {
	add_theme_support ('title-tag');
	add_theme_support( 'custom-logo' );
    add_theme_support( 'post-thumbnails' );
    add_image_size( 'portfilio-thumbnail', 250, 325 );
}

add_action('after_setup_theme','skeleton_features');

function skeleton_menus() {

    $locations = array(
        'primary'  => __( 'Main Menu', 'skeleton' ),
        'portfolio' => __(Portfolio Menu, 'skeleton'),
        'news' => __(News Menu, 'skeleton'),
    );

    register_nav_menus( $locations );
}

add_action( 'init', 'skeleton_menus' );

From hereon in, all css mods should go into style.css.

front-page.php

For now, we’ll be using front-page.php to create our theme.

Once you’ve reached this stage of the process, it won’t be too long before you’ll have a site you can view in the browser.

During the development process I spend most of the time modifying front-page.php, header.php and footer.php, which once complete, can be used to add content to the remaining files.

HTML Templates

Go ahead and download the templates.zip file below, unzip to a convenient location and open front-page.html with your preferred code editor.

[sdm_download id=”93″ fancy=”0″][sdm_download_counter id=”93″]

Mu-Plugin

For those of you that want the mu-plugin file.

[sdm_download id=”100″ fancy=”0″][sdm_download_counter id=”100″]

header.php

While front-page.html is open also open header.php.

To begin you’ll need to add some basic WordPress related info to header.php

<!DOCTYPE html>
<html>
<head>
   <meta charset="">
   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <?php wp_head();?>
</head>

And from front-page.html copy and paste the following into header.php, below the closing </head>.

<body>

  <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
    <div class="container">
      <a class="navbar-brand" href="#">Site Branding</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarResponsive">
        <ul class="navbar-nav ml-auto">

  <!-- WordPress menu goes here -->

        </ul>
      </div>
    </div>
  </nav>

Branding / Site Name

Let’s first change the site name and provide the functionality to add a custom logo if desired.

Replace;

<a class="navbar-brand" href="#">Site Name</a>

With;

      <a class="navbar-brand">
      <?php if( has_custom_logo() ) { 
      the_custom_logo(); 
      } else { ?>
      <a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?>
    <?php } ?>
      </a>

You may need to tidy the code a little as <pre> doesn’t render the code as I’d like.

Main Menu

We now add our first menu.

Replace;

<ul class="navbar-nav ml-auto">

<!-- This is where the WordPress menu will go -->

</ul>

With;

  <ul class="navbar-nav ml-auto">
          <?php
    if ( has_nav_menu( 'primary' ) ) {

      wp_nav_menu(
        array(
          'container'  => '',
          'items_wrap' => '%3$s',
          'theme_location' => 'primary',
          )
        );

      } elseif ( ! has_nav_menu( 'expanded' ) ) {

        wp_list_pages(
          array(
          'match_menu_classes' => true,
          'show_sub_menu_icons' => true,
            'title_li' => false,
          )
        );

      }
    ?> 
  </ul>

footer.php

Open up footer.php in the code editor and add;

<?php wp_footer(); ?>

</body>
</html>

front-page.php

Add to front-page.php

<?php get_header(); ?>




<?php get_footer(); ?>

For the first time you’ll be able to view your theme!

Return to the browser, refresh the page to see the skeleton theme take shape. If you see an error message, start from the beginning, you’ve probably made a mistake copying the code.

If this is a fresh install all you should see is the branding (name of your site) on the left and “sample page” on the right. Don’t worry about any styling aspects just yet, we’ll address this further below.

front-page.php

Let’s return to front-page.php and start adding content.

Select & copy the following from front-page.html

  <div class="container">
    <header class="jumbotron my-4">
      <h1 class="display-3">A Warm Welcome!</h1>
      <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa, ipsam, eligendi, in quo sunt possimus non incidunt odit vero aliquid similique quaerat nam nobis illo aspernatur vitae fugiat numquam repellat.</p>
      <a href="#" class="btn btn-primary btn-lg">Call to action!</a>
    </header>
  </div>

Paste into front-page.php beneath <?php get_header(); ?>

Refresh the browser page to see if the code has been included correctly. If you see an error message, go back to the last stage, as you’ve probably made a mistake copying the code.

Of course it’s all well an good pasting code into front-page, but that’s not what we want to achieve here, we want to make our content dynamic.

Below <?php get_header(); ?> and above <div class=”container”> paste;

    <?php 
    $homepageContent = new WP_Query(array(
    'posts_per_page' => 1,
    'post_type' => 'post'
    ));
    while($homepageContent->have_posts()) {
    $homepageContent->the_post(); ?>

This code is telling WordPress that we want to add the last created post into this section of front-page.php and we only want to add one post. There are different ways of ordering posts, but that’s not the objective here.

We now want to add a dynamic post title.

Replace;

A Warm Welcome!

With;

<?php the_title(); ?>

And for the content remove the text, so that you’re left with;

<p class="lead"></p>

Carriage return to create a space between the p’s and paste;

          <?php if (has_excerpt()) {
          the_excerpt();
          } else {
          echo wp_trim_words(get_the_content(),33);
          } ?>

This code is telling WordPress to use the excerpt, but in the event of the excerpt not being used onlt add 33 words to this section.

And finally, we want to add a dynamic link to the content, which we do by removing # from a href="" and replace with;

<?php the_permalink() ?>

So that we have the following for the link;

<a href="<?php the_permalink() ?>" class="btn btn-primary btn-lg">Call to action!</a>

All that’s left for this section is to close our php code, which we do by adding;

<?php } ?>

Beneath </header>

As a quick recap you should have the following code in front-page.php

<?php get_header(); ?>

    <?php 
    $homepageContent = new WP_Query(array(
    'posts_per_page' => 1,
    'post_type' => 'post'
    ));
    while($homepageContent->have_posts()) {
    $homepageContent->the_post(); ?>
  <div class="container">
    <header class="jumbotron my-4">
      <h1 class="display-3"><?php the_title(); ?></h1>
      <p class="lead">
          <?php if (has_excerpt()) {
          the_excerpt();
          } else {
          echo wp_trim_words(get_the_content(),33);
          } ?>      
      </p>
      <a href="<?php the_permalink() ?>" class="btn btn-primary btn-lg">Call to action!</a>
    </header>
    <?php } ?>


<?php get_footer(); ?>

If this is a fresh install of WordPress you should return to a clean page with just the menu showing.

Create a Post

Lets now create a post that mimics front-page.html

So a post entitled “A Warm Welcome!” with content “Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa, ipsam, eligendi, in quo sunt possimus non incidunt odit vero aliquid similique quaerat nam nobis illo aspernatur vitae fugiat numquam repellat.”

Refresh the page to see the Jumbotron section return.

Don’t worry that no page is displayed if you click the button, that’s normal at this stage as we haven’t created single.php as yet.

footer.php

Add the following to footer.php, you’ll find this at the bottom of front-page.html. Make sure that you paste the code beneath <?php wp_footer(); ?> and above </body>

  <footer class="py-5 bg-dark">
    <div class="container">
      <p class="m-0 text-center text-white">Copyright © Your Website 2019</p>
    </div>
  </footer>

All we’ll do here is add a little dynamic content for the date;

So;

2019 - <?php echo date("Y"); ?>

Refresh to see the footer is now displaying. Don’t worry that the footer doesn’t display correctly, this is normal at this stage, as we’re still to close the container </div>.

Portfolio Section

If you recall earlier I asked you to create the mu-plugin folder?

What we’ll do now is create mu-plugin.php and place it in the mu-plugin folder. There’s no need to install the plugin, WordPress will do this for you. If you visit plugins in the WordPress Dashboard you’ll see an extra file in the “Must-Use” section.

To add a new custom post type, add to mu-plugin.php

<?php

function skeleton_post_types() {
  // Portfolio Post type
  register_post_type('portfolio', array(
    'supports' => array ('title', 'editor', 'excerpt', 'thumbnail', 'author', 'attributes', 'comments'),
    'rewrite' => array('slug' => 'portfolio'),
    'has_archive' => true,
    'public' => true,
    'labels' => array(
      'name' => 'Portfolio',
      'add_new_item' => 'Add New',
      'edit_item' => 'Edit Post',
      'all_items' => 'All Posts',
      'singular_name' => 'Portfolio'
    ),
    'menu_icon' => 'dashicons-media-default'
  ));

}

add_action('init', 'skeleton_post_types');

Refresh the WordPress Dashboard to see the new post type.

front-page.php

Returning to front-page.php we can now add the next (portfolio) section.

From front-page.html copy the code below.

Paste under the extisting code, below <?php } ?>

    <div class="row text-center">
      <div class="col-lg-3 col-md-6 mb-4">
        <div class="card h-100">
          <img class="card-img-top" src="http://placehold.it/500x325" alt="">
          <div class="card-body">
            <h4 class="card-title">Card title</h4>
            <p class="card-text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sapiente esse necessitatibus neque.</p>
          </div>
          <div class="card-footer">
            <a href="#" class="btn btn-primary">Find Out More!</a>
          </div>
        </div>
      </div>
    </div>

We now need to repeat the process above, where we made our hero unit dynamic, only this time we’ll add a section that’ll display multiple posts.

The only difference is that this time we’ll be including an image.

Lets first add the loop, below <div class="row text-center"> and above <div class="col-lg-3 col-md-6 mb-4">

    <?php 
    $homepageContent = new WP_Query(array(
    'posts_per_page' => 4,
    'post_type' => 'portfolio'
    ));
    while($homepageContent->have_posts()) {
    $homepageContent->the_post(); ?>

Notice that this time we’re including 4 posts from the portfolio custom post type.

To add an image use;

          <?php the_post_thumbnail( 'portfilio-thumbnail' ); ?>

For the card title use;

<?php the_title(); ?>

Make a space between;

            <p class="card-text">
            	

            </p>

And add;

          <?php if (has_excerpt()) {
          the_excerpt();
          } else {
          echo wp_trim_words(get_the_content(),12);
          } ?>

Note how this time, we’re only including 12 words.

Add the permalink to the a href="#"

<a href="" class="btn btn-primary">Find Out More!</a>

And close the loop with the code below above the last </div>

<?php } ?>

And finally we can close off that illusive container </div>

Front Page Recap

You should now have the following in front-page.php

<?php get_header(); ?>

    <?php 
    $homepageContent = new WP_Query(array(
    'posts_per_page' => 1,
    'post_type' => 'post'
    ));
    while($homepageContent->have_posts()) {
    $homepageContent->the_post(); ?>
  <div class="container">
    <header class="jumbotron my-4">
      <h1 class="display-3"><?php the_title(); ?></h1>
      <p class="lead">
          <?php if (has_excerpt()) {
          the_excerpt();
          } else {
          echo wp_trim_words(get_the_content(),33);
          } ?>      
      </p>
      <a href="<?php the_permalink() ?>" class="btn btn-primary btn-lg">Call to action!</a>
    </header>
    <?php } ?>


  
    <div class="row text-center">
    <?php 
    $homepageContent = new WP_Query(array(
    'posts_per_page' => 4,
    'post_type' => 'portfolio'
    ));
    while($homepageContent->have_posts()) {
    $homepageContent->the_post(); ?>
      <div class="col-lg-3 col-md-6 mb-4">
        <div class="card h-100">
          <span class="card-img-top"><?php the_post_thumbnail( 'portfilio-thumbnail' ); ?>
          <div class="card-body">
            <h4 class="card-title"><?php the_title(); ?></h4>
            <p class="card-text">
          <?php if (has_excerpt()) {
          the_excerpt();
          } else {
          echo wp_trim_words(get_the_content(),12);
          } ?>
            </p>
          </div>
          <div class="card-footer">
            <a href="<?php the_permalink() ?>" class="btn btn-primary">Find Out More!</a>
          </div>
        </div>
      </div>
      <?php } ?>
    </div>

</div>

<?php get_footer(); ?>

Lets now create a post in our new Portfolio post type, again we’ll reproduce the content from front-page.html, so the title is “Card Title” and the content is “Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sapiente esse necessitatibus neque.”

We also need to include an image. You’ll find demo.jpg in album.zip, this is the ideal size for an image to display in a post, and it shrinks to fit on the front page.

Upload this image when creating the post, use the featured image section in the WordPress editor.

FYI, the image size is 1200px width, 444px height. You can try looking for the ideal size image so that it fits into the front page and the post, this is why we added the section of code below to functions.php.

add_image_size( 'portfilio-thumbnail', 250, 325 );

Create 3 more demo posts in the portfolio section before moving onto part two of the guide.

Before closing this chapter lets add a little styling to the menu links.

Add to style.css

.navbar a, a:link, a:hover, a:visited {
	color:#fff!important;
	text-decoration:none!important;
}

And that’s it for part 1, you should have something that looks similar to;

Part 2

You’re now well on your way to creating your first theme, and in this section, if you got this far, I’m going to assume you have the knowledge to continue without having to go into as much detail as in Part 1.

In this part of the guide we’ll be creating single.php & page.php, and our archive files.

Post, Page & Index

The code we’ll use for single.php, page.php, index.php and 404.php is almost idential, so you can open those up in the code editor. You can also open up single.html which we’ll use as our template.

Paste into all of the newly opened files;

<?php get_header(); ?>



<?php get_footer(); ?>

And between these paste;

  <div class="container">
    <div class="row">
      <div class="col-lg-12 mt-5">

        <span class="img-fluid rounded"><img src="http://placehold.it/900x300" alt=""></span>

        <hr>

        <h1 class="mt-4">Post Title</h1>
        <p class="lead">By <a href="#">Bootstrap</a></p>

        <hr>

        <p>Posted on January 1, 2019 at 12:00 PM</p>

        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.</p>
        
      </div>
    </div>
  </div>

Above <div class="container"> paste the code below into all files apart from 404.php

	<?php
	while (have_posts()){
		the_post(); 
	?>

Replace the image with;

<?php the_post_thumbnail(); ?>

Replace the post title with;

<?php the_title(); ?>

And a new piece of code, that provides the article creator.

Replace Bootstrap with;

<?php echo get_the_author(); ?>

And for the date, replace with;

<?php the_time('j F Y'); ?>

For the content, replace;

<p>Lorem ipsum dolor sit amet etc.</p>

With;

	    <?php 
	    the_content(); 
	       }; 
	    ?>

And finally modify 404.php

You can strip the file of most of the content, leaving just the title and content, perhaps add a button to return to the home page?

  <div class="container">
    <div class="row">
      <div class="col-lg-12">

        <h1 class="mt-4">404 Error</h1>

        <p>WOW! What happened there! You tried to find a page that doesn't exist!</p>

        <a class="btn btn-primary btn-lg mb-5" href="<?php echo esc_url( home_url( '/' ) ); ?>">Return to Home Page</a>
        
      </div>
    </div>
  </div>

Recap

You should have the following code in single.php, page.php and index.php

<?php get_header(); ?>
  
    <?php
  while (have_posts()){
    the_post(); 
  ?>

  <div class="container">
    <div class="row">
      <div class="col-lg-12 mt-3">

        <span class="img-fluid rounded mt-3"><?php the_post_thumbnail(); ?></span>

        <hr>

        <h1 class="mt-4"><?php the_title(); ?></h1>
        <p class="lead">By <a href="#"><?php echo get_the_author(); ?></a></p>

        <hr>

        <p>Posted: <?php the_time('j F Y'); ?></p>

      <?php 
      the_content(); 
         }; 
      ?>
        
      </div>
    </div>
  </div>

<?php get_footer(); ?>

Don’t worry that the footer is still a little basic we’ll be returning to this later in the guide.

Other Files

All that’s left now is to create a couple of more files, modify the archives and create our sidebars.

Open single-news.php and single-portfolio.php

Now copy and paste everything from single.php into these 2 files.

Archive’s

I use archives to display content groups, for example all articles in the portfolio post type will display in the portfolio archive and all articles in the news post type will display in the news archive.

As with the previous section we’ll be using single.html as our template, so please open that up, you can also open archive.php, archive-portfolio.php and archive-news.php, as they’ll be almost identical.

In these 3 files paste;

<?php get_header(); ?>




?php get_footer(); ?>

And paste everthing from single.html

  <div class="container">
    <div class="row">
      <div class="col-lg-12 mt-5">

        <span class="img-fluid rounded"><img src="http://placehold.it/900x300" alt=""></span>

        <hr>

        <h1 class="mt-4">Post Title</h1>
        <p class="lead">By <a href="#">Bootstrap</a></p>

        <hr>

        <p>Posted on January 1, 2019 at 12:00 PM</p>

        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.</p>
        
      </div>
    </div>
  </div>

In each of these files paste the code below under;

<div class="row">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

Replace the image with;

<?php the_post_thumbnail(); ?>

Post title with;

<?php the_title(); ?>

Author with;

<?php echo get_the_author(); ?>

And the date with;

<?php the_time('j F Y'); ?>

Remove the coontent from between the p tags, carriage return to make a space, a paste the following in the gap.

          <?php if (has_excerpt()) {
          the_excerpt();
          } else {
          echo wp_trim_words(get_the_content(),40);
          } ?>

And beneath the closing </p> add a button.

<a class="btn btn-primary mb-5" href="">Read more

Let’s add a little custom styling to style.css to seperate the posts.

.specialHr {
    background-color: #e53359 !important;
    color: #e53359 !important;
    border: solid 2px #e53359 !important;
    height: 2px !important;
    margin-top: 25px;
}

And after the button paste;

<hr class="specialHr" />

And finally! We need to close of our while and endif, so beneath the closing </div> under the <hr> paste;

      <?php endwhile;            

      endif; ?> 

Now if you followed me upto this point and haven’t just used the template files, you’ll see that the images extend beyond the container, so we’ll need to do something about that before closing this section of the guide.

Fortunately we can do this with css.

Add to style.css;

.image-contained {
	height:auto;
    overflow:hidden;
    float:left;
	height:auto;
}

And for the image, change this to;

<span class="img-fluid rounded image-contained"><?php the_post_thumbnail(); ?></span>

Archive Recap

You should now have 3 archive files that include the following code;

<?php get_header(); ?>

  <div class="container">
    <div class="row">
      <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
      <div class="col-lg-12 mt-5">

        <span class="img-fluid rounded image-contained"><?php the_post_thumbnail(); ?></span>

        <hr>

        <h1 class="mt-5"><?php the_title(); ?></h1>
        <p class="lead">By <a href="#"><?php echo get_the_author(); ?></a></p>

        <hr>

        <p>Posted on <?php the_time('j F Y'); ?></p>

        <p>
          <?php if (has_excerpt()) {
          the_excerpt();
          } else {
          echo wp_trim_words(get_the_content(),40);
          } ?>
        </p>
        <a class="btn btn-primary mb-5" href="<?php the_permalink() ?>">Read more</a>
        <hr class="specialHr">
      </div>
      
      <?php endwhile;            

      endif; ?>     
    </div>
  </div>

<?php get_footer(); ?>

And not to sound patronizing, but if you’ve made it upto this point without using the pre-made files, that’s awesome work! Drop me an email with details of the difference between the files in the archive section and the recap file, and I’ll send you a free theme.

News Post Type

Now if you hadn’t noticed, we’ve been working on a new News post types, and have yet to create this in our mu-plugin, so lets do that now before moving onto the sidebars.

Open up wp-content/mu-plugins/mu-plugin.php and paste the code below;

Under;

));

Paste;

  // News Post type
  register_post_type('news', array(
    'supports' => array ('title', 'editor', 'excerpt', 'thumbnail', 'author', 'attributes', 'comments'),
    'rewrite' => array('slug' => 'news'),
    'has_archive' => true,
    'public' => true,
    'labels' => array(
      'name' => 'News',
      'add_new_item' => 'Add New',
      'edit_item' => 'Edit Post',
      'all_items' => 'All Posts',
      'singular_name' => 'News'
    ),
    'menu_icon' => 'dashicons-media-text'
  ));

Refresh the WordPress Dashboard to see the new News post type displayed. We’re not going to use this until the final chapter where we create a dynamic footer.

Sidebars

In this section we’ll be using 2 custom html templates, sidebar-left.html and sidebar-right.html. We’ll also need to create our sidebars in functions.php file, so if you can open those three files, along with the files sidebar-right.php and sidebar-left.php.

I’m making it really easy in this chapter and from this point on the html files contain everything you need to create the sidebars, no messing! I sincerely hope that you know your stuff now, and are well on your way to becoming a WordPress guru.

Add to functions.php the following code (under the existing code);

add_action( 'widgets_init', 'skeleton_sidebar' );

function skeleton_sidebar() {
    register_sidebar(
        array(
            'id'            => 'primary',
            'name'          => __( 'Main Sidebar' ),
            'description'   => __( 'Place items from the available widgets section to the left.' ),
            'before_widget' => '<div id="%1$s" class="widget %2$s">',
            'after_widget'  => '</div>',
            'before_title'  => '<h3 class="page-title">',
            'after_title'   => '</h3>',
        )
    );
}

add_action( 'widgets_init', 'portfolio_sidebar' );

function portfolio_sidebar() {
    register_sidebar(
        array(
            'id'            => 'portfolio',
            'name'          => __( 'Portfolio Sidebar' ),
            'description'   => __( 'Place items from the available widgets section to the left.' ),
            'before_widget' => '<div id="%1$s" class="widget %2$s">',
            'after_widget'  => '</div>',
            'before_title'  => '<h3 class="page-title">',
            'after_title'   => '</h3>',
        )
    );
}

add_action( 'widgets_init', 'news_sidebar' );

function news_sidebar() {
    register_sidebar(
        array(
            'id'            => 'news',
            'name'          => __( 'News Sidebar' ),
            'description'   => __( 'Place items from the available widgets section to the left.' ),
            'before_widget' => '<div id="%1$s" class="widget %2$s">',
            'after_widget'  => '</div>',
            'before_title'  => '<h3 class="page-title">',
            'after_title'   => '</h3>',
        )
    );
}

Now we’re only going to use 1 of these 3 new sidebars in this chapter, the ‘primary’ Main Sidebar. The other 2 will be used to create our dynamic footer, which we’ll address in the final chapter.

sidebar-left.php

Take everything from sidebar-left.html and paste into sidebar-left.php

<?php
/*
Template Name: Sidebar Left
Template Post Type: post, page, portfolio, news
*/

  get_header();

  while (have_posts()){
    the_post(); 
  ?>

  <div class="container">
    <div class="row">

      <div class="col-md-4">
      <?php dynamic_sidebar( 'primary' ); ?>
      </div>

      <div class="col-lg-8 mt-5">

        <span class="img-fluid rounded image-contained"><?php the_post_thumbnail(); ?></span>        

        <h1 class="mt-4"><?php the_title(); ?></h1>

        <p class="lead">By <a href="#"><?php echo get_the_author(); ?></a></p>

        <hr>

        <p>Posted: <?php the_time('j F Y'); ?></p>

        <hr>

        <!-- Post Content -->
        <p class="lead">
        <?php 
        the_content(); 
         }; 
        ?>          
        </p>

      </div>
    </div>
  </div>

<?php get_footer(); ?>

sidebar-right.php

Take everything from sidebar-right.html and paste into sidebar-right.php

<?php
/*
Template Name: Sidebar Right
Template Post Type: post, page, portfolio, news
*/

  get_header();

  while (have_posts()){
    the_post(); 
  ?>

  <div class="container">
    <div class="row">
      <div class="col-lg-8 mt-5">

        <span class="img-fluid rounded image-contained"><?php the_post_thumbnail(); ?></span>        

        <h1 class="mt-4"><?php the_title(); ?></h1>

        <p class="lead">By <a href="#"><?php echo get_the_author(); ?></a></p>

        <hr>

        <p>Posted: <?php the_time('j F Y'); ?></p>

        <hr>

        <!-- Post Content -->
        <p class="lead">
        <?php 
        the_content(); 
         }; 
        ?>          
        </p>

      </div>

      <div class="col-md-4">
      <?php dynamic_sidebar( 'primary' ); ?>
      </div>
    </div>
  </div>

<?php get_footer(); ?>

Now when creating an article in any of the post types, including Pages, you will see a template in “Post Attibutes” that will easily allow you to create a post with a sidebar.

To add items to your sidebar, visit widget and add content in the normal manner.

Dynamic Footer

Finally we’ve reach the dynamic footer stage of the guide!!!

Ok, so we’ve already carried out most of the hard work, atleast we’ve created a good foundation that can be built upon, enabling you to create a space where the 4 post types can be added displayed.

You’ll only need to open footer.php and footer-final.html for this part, so the code editor won’t be as full now.

To create our new dynamic footer remove all code from footer.php, copy everything in footer-final.html and paste into footer.php, or use the code below.

<?php wp_footer(); ?>


                <footer class="footer pt-10 pb-5 mt-auto bg-dark footer-dark">
                    <div class="container">
                    	<hr class="footerHr">
                        <div class="row mt-5">
                            <div class="col-lg-3">
                                <div class="footer-brand lead">iDeviceUK C.I.C.</div>
                                <div class="mb-3">Sharing in the WP community.</div>
                                <div class="icon-list-social mb-5">
                                    
                                </div>
                            </div>
                            <div class="col-lg-9">
                                <div class="row">
                                    <div class="col-lg-3 col-md-6 mb-5 mb-lg-0">
                                        <div class="text-uppercase-expanded text-xs mb-4 text-white lead">Posts</div>
                                        <ul class="list-unstyled mb-0">
                                            <?php 
                                            $homepageEvents = new WP_Query(array(
                                            'posts_per_page' => 8,
                                            'post_type' => 'post'
                                            ));
                                            while($homepageEvents->have_posts()) {
                                            $homepageEvents->the_post(); ?>                                          
                                            <li class="mb-2"><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>
                                            <?php } ?>                                         
                                        </ul>
                                    </div>
                                    <div class="col-lg-3 col-md-6 mb-5 mb-lg-0">
                                        <div class="text-uppercase-expanded text-xs mb-4 text-white lead">Portfolio</div>
                                        <ul class="list-unstyled mb-0">
                                            <?php 
                                            $homepageEvents = new WP_Query(array(
                                            'posts_per_page' => 8,
                                            'post_type' => 'portfolio'
                                            ));
                                            while($homepageEvents->have_posts()) {
                                            $homepageEvents->the_post(); ?>                                          
                                            <li class="mb-2"><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>
                                            <?php } ?>
                                        </ul>
                                    </div>
                                    <div class="col-lg-3 col-md-6 mb-5 mb-md-0">
                                        <div class="text-uppercase-expanded text-xs mb-4 text-white lead">News</div>
                                        <ul class="list-unstyled mb-0">
                                            <?php 
                                            $homepageEvents = new WP_Query(array(
                                            'posts_per_page' => 8,
                                            'post_type' => 'news'
                                            ));
                                            while($homepageEvents->have_posts()) {
                                            $homepageEvents->the_post(); ?>                                          
                                            <li class="mb-2"><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>
                                            <?php } ?>
                                        </ul>
                                    </div>
                                    <div class="col-lg-3 col-md-6">
                                        <div class="text-uppercase-expanded text-xs mb-4 text-white lead">Pages</div>
                                        <ul class="list-unstyled mb-0">
                                            <?php 
                                            $homepageEvents = new WP_Query(array(
                                            'posts_per_page' => 8,
                                            'post_type' => 'page'
                                            ));
                                            while($homepageEvents->have_posts()) {
                                            $homepageEvents->the_post(); ?>                                          
                                            <li class="mb-2"><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>
                                            <?php } ?>
                                        </ul>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <hr class="my-5">
                            <div class="container">
						      <p class="m-0 text-center text-white">Copyright © <?php bloginfo( 'name' ); ?> 2019 - <?php the_time('Y'); ?></p>
						    </div>
                        </div>
                    </div>
                </footer>
</body>
</html>

readme.txt

If we’re going to submit a theme to WordPress.org, we need to include a readme.txt file. I use the Twenty Twenty Theme readme as a template and modify for the needs of the current project, which for the Skeleton theme is;

=== Skeleton ===
Tags: bootstrap, blue, red, black, white, one-column, two-columns, right-sidebar, left-sidebar, flexible-width, custom-header, custom-menu, featured-images,  translation-ready
Requires at least: 5.4.2
Tested up to: 5.4.2
Requires PHP: 7
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

Free theme implementing Bootstrap 4.5

== Description ==
Our free theme developed using Bootstrap 4.5. Skeleton has been primarily 
created to help new developers create WordPress themes. Skeleton accompanies
the guide entitled Create a WordPress Theme, available fro leemiller.club. 
Skeleton includes custom post types, which are implemented by way of a
mu-plugin, available at the demo site.

== Changelog ==

= 1.4 =
* Released: June 20, 2020

https://leemiller.club/documents/skeleton-changelog/

Initial release

== Copyright ==

Skeleton WordPress Theme, Copyright 2019-2020 WordPress.org
Twenty Twenty is distributed under the terms of the GNU GPL.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

Theme Translation

To translate a theme you’ll need some help, I purchased a copy of PoEdit, which is software that automatically translates WordPress themes. If you’re a newcomer to WordPress theme developement and use skeleton for personal or commercial use, email me and I’ll translate the theme into any language of your choosing!

Before translating your theme, you need to add localization to your theme, you can do this by adding the code below to functions.php, where skeleton is the name of the theme.

load_theme_textdomain( 'skeleton', get_template_directory() . '/lang' );

Once you have that, let PoEdit connect with the server to create the translation files, it’s not perfect but it’s a good place to start from.

Skeleton is translation ready (that doesn’t mean it’s translated, yet) for Chinese (simplified), German, Spanish, French and Japanese, with more to follow.

Theme Testing

Using Theme Sniffer, a plugin the WordPress team use to test themes with on submission, I tested Skeleton!

Rather surprising results if I may say so, I’m assuming these are mainly false positives, for eaxmple;

  • Screenshot not 4:3 ratio – despite using a 1200 x 900 image
  • bootstrap.min.css – Contains no php tag, well there’s a suprise
  • style.css – Contains no php tag
  • bootstrap.bundle.min.js – Contains no php tag
  • readme.txt – No valid license, despite taking it from Twenty Twenty
  • readme.txt – No valid license url, despite taking it from Twenty Twenty

Not entirely sure if these are enough for a submission to fail, but I’m going to give it a go anyway, I had 19 errors and warnings, though when tested Twenty Twenty had 55!

Theme Submission

Ok so today is 22nd June, and I’m albut ready to submit, I’ll let you know how it goes.