Skip to content

Finished example wordpress app featuring a custom built theme with step by step instructions

License

Notifications You must be signed in to change notification settings

jongrover/building-a-wordpress-theme-from-scratch

Repository files navigation

Building a WordPress Theme From Scratch

This is a finished example of a WordPress app featuring a custom built theme where the theme is built using JS and CSS from the Bootstrap v4. Instructions provided are specific to using Mac ecosystem. I tried to provide relevant links to explanations for Windows users regarding WAMP vs MAMP, but some setup steps may differ. However, all PHP, HTML, CSS, JS code for creating the theme is platform independent and will be the same for both Mac and Windows users.

Setup Local Server and Install WordPress

  1. Download and install a code editor (if necessary) such as Atom.
  2. Download an app to spin up a local PHP Apache Server such as MAMP for Mac or WAMP for Windows.
  3. Download Wordpress from wordpress.org
  4. Open MAMP (or WAMP) App and click Start Servers. Please note: The following steps assume MAMP on Mac.
  5. When your browser opens under MySQL heading click the phpMyAdmin link.
  6. After logging into phpMyAdmin in the left hand navigation panel click new and under Create Database, name your database something, I called mine wp_dev_db (make sure there are no spaces in the name you choose). Then click Create. Then in the top navigation click Start. Let's leave this browser tab open and refer to the MySQL database details from here later on.
  7. Move into the downloaded WordPress folder using Terminal $ cd ~/Downloads/wordpress or optionally you can rename the folder first if you like, I renamed mine building-a-wordpress-theme-from-scratch and moved it to my Development folder, I then ran the command $ cd ~/Development/building-a-wordpress-theme-from-scratch.
  8. Rename wp-config-sample.php to wp-config.php with $ mv wp-config-sample.php wp-config.php.
  9. Open the site in your code editor I'm using Atom with the command $ atom .
  10. Open wp-config.php and set the database details to point to your local server the following are the instructions for MAMP on Mac directions for Windows may vary at this step so if your own windows instead refer to the instructions for setting up and connecting to databases on WAMP. Here are the MAMP specific code using the details from the MAMP page we left open in our browser:
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wp_dev_db');

/** MySQL database username */
define('DB_USER', 'root');

/** MySQL database password */
define('DB_PASSWORD', 'root');

/** MySQL hostname */
define('DB_HOST', 'localhost:8889');

/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');

/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');
  1. Then visit https://api.wordpress.org/secret-key/1.1/salt/ and copy the generated keys and paste them into your wp-config.php file under the section labeled Authentication Unique Keys and Salts.
  2. Also in wp-config.php set debug from false to true define('WP_DEBUG', true);.
  3. Then back to MAMP (WAMP instructions instead see their docs or forum) App click Stop Servers. Then click Preferences.
  4. Click Web Server tab and set the document root to point to the folder for your WP (WordPress) Site. On Mac in MAMP you click the folder icon with three dots on it to browse for the root folder. It is important that it is set to the folder that contains the wp-config.php file. than click OK. Then click to Start Servers again.
  5. In your browser set the URL to http://localhost if everything was done correctly this should forward to http://localhost/wp-admin/install.php.
  6. Select your desired install language and click Continue.
  7. On the next page set a Site Title I choose WP Theme From Scratch. Also set a username typically this is admin. Then set a password you will remember. Also set an admin email. Then click Install WordPress button.
  8. On the next page click Log In and use your credentials to login to your site. If all goes well you should see the admin dashboard for your site.
  9. Run any updates it suggests under Dashboard > updates

Creating A Custom Theme

  1. In Terminal (or in code editor) head to the theme folder at wp-content/themes/ $ cd wp-content/themes.
  2. Create a new theme folder using Terminal $ mkdir custom_theme or via Atom by right clicking on the themes folder and select create new folder. Note: you can name your theme folder anything you like I choose custom_theme as a generic name for this example.
  3. Inside custom_theme create a css folder $ mkdir custom_theme/css and also create a js_ folder $ mkdir custom_theme/js.
  4. Move into your custom theme folder $ cd custom_theme and create three files index.php and style.css and js/app.js$ touch index.php style.css js/app.js. Note that we did not save style.css inside the css folder, although we will be putting Bootstrap css in our css folder later on, WordPress requires a style.css file to be located inside the root folder in order to gather theme details.
  5. In style.css in your code editor add the following code:
/*
Theme Name: Custom Theme
Theme URI: https://github.com/jongrover/building-a-wordpress-theme-from-scratch
Author: Jonathan Grover
Author URI: https://jonathangrover.com
Description: Example Theme from Github Repo
Version: 0.0.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Tags: bootstrap
Text Domain: jongcustomtheme

This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned with others.
*/

h1 {
  color: red;
}

Note: You can change any of the settings in the CSS comment at the top as you wish these will eventually appear in your admin dashboard view under Appearance>Themes as details for each theme.

  1. In js/app.js in your code editor add the following code:
console.log('Hello from your theme!');
  1. In index.php in your code editor put the code:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><?php echo get_bloginfo('name'); ?></title>
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/style.css">
</head>
<body>
  <h1><?php echo get_bloginfo('name'); ?></h1>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/app.js"></script>
</body>
</html>

Note that in our title element we put <title><?php echo get_bloginfo('name'); ?></title> this uses the get_bloginfo() function to print the name of our site that we first set when we installed WordPress. We also printed this site name in the heading inside our page body. We used this function again to link to our CSS and JS files by making use of <?php echo get_bloginfo('template_directory'); ?> which was essential for printing the correct file path to our assets. For full details of what can be done with this function take a look at the docs here.

  1. Now head back to the admin dashboard in your browser and click Appearance>Themes
  2. Under Custom Theme (or whatever your theme name you set was) click Activate.
  3. Then visit localhost in your browser to see your site. It should say your site title in an h1 element and the loaded CSS should style the text color as red. Additionally if you view the JavaScript console using the Developer Tools you should see it print "Hello from your theme!".
  4. Now that our theme is working let's delete the previous theme folders (you don't have to do this, but I won't be using the default themes any longer and they are just taking up space.) I'll get rid of twentyseventeen, twentysixteen, and twentyfifteen.

Adding Bootstrap

  1. Start by downloading Bootstrap.
  2. Next download jQuery a Bootstrap dependency.
  3. Also download Popper another Bootstrap dependency.
  4. After all downloads finish unzip them and move all CSS into your projects css folder and move all JS files into your js folder.
  5. Now let's link to these new files for Bootstrap in our index.php file in the root of our theme folder custom_theme/index.php. Here We'll link to the files the same way we linked to our style.css and app.js.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><?php echo get_bloginfo('name'); ?></title>
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/css/bootstrap.min.css">
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/style.css">
</head>
<body>
  <h1><?php echo get_bloginfo('name'); ?></h1>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/jquery-3.2.1.slim.min.js"></script>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/popper.min.js"></script>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/bootstrap.min.js"></script>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/app.js"></script>
</body>
</html>
  1. Save all files and head to localhost in your browser, open the Network tab in the Developer Tools and refresh the page. You should see Bootstrap CSS, JS, jQuery, and Popper are all correctly loading.

Dividing Page Layout

  1. Let's start by building our layout in custom_theme/index.php and later we'll break it into separate PHP files. Here is my layout code:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><?php echo get_bloginfo('name'); ?></title>
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/css/bootstrap.min.css">
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/style.css">
</head>
<body>

<header>
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container">
      <a class="navbar-brand" href="<?php echo get_bloginfo( 'wpurl' ); ?>"><?php echo get_bloginfo('name'); ?></a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item">
            <a class="nav-link" href="#">About</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Contact</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Blog</a>
          </li>
        </ul>
      </div>
    </div><!-- .container -->
  </nav>
</header>

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

        <section class="col-md-9">
          <div class="jumbotron">
            <h1 class="display-3">Welcome</h1>
            <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
            <hr class="my-4">
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
          </div>
        </section>

        <aside class="col-md-3">
          <ul class="nav flex-column">
            <li class="nav-item">
              <a class="nav-link active" href="#">Active</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Link</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Link</a>
            </li>
            <li class="nav-item">
              <a class="nav-link disabled" href="#">Disabled</a>
            </li>
          </ul>
        </aside>

      </div><!-- .row -->
    </div><!-- .container -->
  </main>

  <footer>
    <div class="container">
      <div class="row">
        <div class="col">
          <p class="copyright"><small>&copy; <?php echo date( 'Y' ); ?> <?php bloginfo( 'name' ); ?>, <?php bloginfo( 'description' ); ?>. All Rights Reserved.</small></p>
        </div><!-- .col -->
      </div><!-- .row -->
    </div><!-- .container -->
  </footer>

  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/jquery-3.2.1.slim.min.js"></script>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/popper.min.js"></script>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/bootstrap.min.js"></script>
  <script src="<?php echo get_bloginfo('template_directory'); ?>/js/app.js"></script>
</body>
</html>
  1. Then in custom_theme/style.css add the code:
header {
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 100;
}

main {
  margin-top: 80px;
}

.navbar-light .navbar-brand.active, .navbar-light .navbar-nav .nav-link.active, .nav .nav-link.active {
  color: darkblue;
}
  1. Save all pages and refresh in the browser and you should see an updated page layout including a navigation bar, welcome page and sidebar as well as a footer.
  2. Now create the files: custom_theme/header.php, custom_theme/single.php, custom_theme/sidebar.php, and custom_theme/footer.php.
  3. In index.php add the function call <?php wp_head(); ?> just before the closing </head> tag.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><?php echo get_bloginfo('name'); ?></title>
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/css/bootstrap.min.css">
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/style.css">
  <?php wp_head(); ?>
</head>
<body>
  1. In index.php copy everything from <!doctype> all the way down to the closing </header> and paste it into header.php.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><?php echo get_bloginfo('name'); ?></title>
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/css/bootstrap.min.css">
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/style.css">
  <?php wp_head() ?>
</head>
<body>
<header>
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container">
      <a class="navbar-brand" href="<?php echo get_bloginfo( 'wpurl' ); ?>"><?php echo get_bloginfo('name'); ?></a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item">
            <a class="nav-link" href="#">About</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Contact</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Blog</a>
          </li>
        </ul>
      </div>
    </div><!-- .container -->
  </nav>
</header>

Notice I also added to the code above <?php echo get_bloginfo( 'wpurl' ); ?> into the href attribute for the navbar-brand link that shows our site title. This way when the user clicks our site title in the navbar it will head back to our site root (home page).

  1. Back in index.php remove that code you copied into header.php replacing it with <?php get_header(); ?>.
  2. In index.php add the function call <?php wp_footer(); ?> just before the closing </body> tag.
    <script src="<?php echo get_bloginfo('template_directory'); ?>/js/jquery-3.2.1.slim.min.js"></script>
    <script src="<?php echo get_bloginfo('template_directory'); ?>/js/popper.min.js"></script>
    <script src="<?php echo get_bloginfo('template_directory'); ?>/js/bootstrap.min.js"></script>
    <script src="<?php echo get_bloginfo('template_directory'); ?>/js/app.js"></script>
    <?php wp_footer(); ?>
</body>
</html>
  1. In index.php copy everything from <footer> all the way down to the closing </html> and paste it into footer.php.
<footer>
  <div class="container">
    <div class="row">
      <div class="col">
        <p class="copyright"><small>&copy; <?php echo date( 'Y' ); ?> <?php bloginfo( 'name' ); ?>, <?php bloginfo( 'description' ); ?>. All Rights Reserved.</small></p>
      </div><!-- .col -->
    </div><!-- .row -->
  </div><!-- .container -->
</footer>

<script src="<?php echo get_bloginfo('template_directory'); ?>/js/jquery-3.2.1.slim.min.js"></script>
<script src="<?php echo get_bloginfo('template_directory'); ?>/js/popper.min.js"></script>
<script src="<?php echo get_bloginfo('template_directory'); ?>/js/bootstrap.min.js"></script>
<script src="<?php echo get_bloginfo('template_directory'); ?>/js/app.js"></script>
<?php wp_footer(); ?>
</body>
</html>
  1. Back in index.php remove that code you copied into footer.php replacing it with <?php get_footer(); ?>.
  2. In index.php delete all the content inside of <section> element and replace with this:
<section class="col-md-9">
  <?php if ( have_posts() ) : while ( have_posts() ) : the_post();
    get_template_part( 'single', get_post_format() );
  endwhile; endif; ?>
</section>

This will check if there are posts and if there are, it will loop over them and display them in this space.

  1. Now in single.php add the following skeleton for each blog post:
<?php get_header(); ?>

  <main>
    <div class="container">
      <div class="row">
        <section class="col">
          <article id="post-<?php the_ID(); ?>">
            <h1><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
            <small><?php the_date(); ?> by <?php the_author(); ?></small>
            <?php the_content(); ?>
          </article>
          <?php if (comments_open() || get_comments_number()) { comments_template(); } ?>
        </section>
      </div><!-- .row -->
    </div><!-- .container -->
  </main>
  
  <?php get_footer(); ?>
  1. In index.php copy all the code from <aside class="col-md-3"> to the closing </aside> and paste it into sidebar.php.
<aside class="col-md-3">
  <h4>Archives</h4>
  <ul class="nav flex-column">
    <?php wp_get_archives( 'type=monthly' ); ?>
  </ul>
</aside>

Here we also removed all the <li> elements and are replacing it with dynamic code <?php wp_get_archives( 'type=monthly' ); ?> as well as a few <h4> to title the Archives list.

  1. Back in index.php remove that code you copied into sidebar.php replacing it with <?php get_sidebar(); ?>.
  2. After refreshing the page in the browser it should still look the same but the welcome box is now showing the Hello World post that WordPress creates for us when we first install it. Our sidebar now shows the about description and Archive month list.

Custom Menu Locations

  1. Create a functions.php file in the root directory of your theme $ touch functions.php.
  2. Inside functions.php add the following code to register a new menu locations:
<?php
function register_my_menus() {
  register_nav_menus(array(
    'header-menu' => 'Header Menu'
  ));
}
add_action( 'init', 'register_my_menus' );
?>
  1. Add the first Menu Location in the header.php by replacing the dummy <li> with the function wp_nav_menu(array('theme_location' => 'header-menu')) like so:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><?php echo get_bloginfo('name'); ?></title>
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/css/bootstrap.min.css">
  <link rel="stylesheet" href="<?php echo get_bloginfo('template_directory'); ?>/style.css">
  <?php wp_head() ?>
</head>
<body>
  <header>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <div class="container">
        <a class="navbar-brand active" href="<?php echo get_bloginfo( 'wpurl' ); ?>"><?php echo get_bloginfo('name'); ?></a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <ul class="navbar-nav mr-auto">
            <?php if (has_nav_menu('header-menu')) {
              wp_nav_menu(array('theme_location' => 'header-menu'));
            } ?>
          </ul>
        </div>
      </div><!-- .container -->
    </nav>
  </header>
  1. Then in style.css add the following code to re-style the links:
.menu {
  list-style: none;
  padding-left: 0;
}

.menu-item a {
    display: inline-block;
    padding: .5rem 1rem;
}

.navbar-nav .menu-item a {
    padding-right: 0;
    padding-left: 0;
}

.navbar-light .navbar-nav .menu-item a {
    color: rgba(0,0,0,.5);
}

.navbar-light .navbar-nav .menu-item a:hover {
    color: rgba(0,0,0,.7);
    text-decoration: none;
}

.navbar-light .navbar-brand.active, .navbar-light .navbar-nav .menu-item a.active, .nav .menu-item a.active {
  color: darkblue;
}

@media (min-width: 992px) {
  .menu-item {
    display: inline-block;
  }
  .navbar-expand-lg .navbar-nav .menu-item a {
    padding-right: .5rem;
    padding-left: .5rem;
  }
}
  1. Next in the browser head into the Admin dashboard and build a menu by going to Appearance>Menus and create a new menu assigning its location to Header Menu. Add your pages as desired. I created four pages: Home, About, Contact, and Blog. Save the Menu and refresh the browser page at localhost and your Header Navigation should appear.

Creating Pages Layout

  1. Next create a custome-theme/page.php file in the themes root folder allowing Pages to have a different layout From blog Post pages. For instance we will have only single columns in our Pages vs 2 columns as we see now in our Posts. In page.php insert this code:
<?php get_header(); ?>

  <main>
    <div class="container">

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

            <article>
              <h1><?php the_title(); ?></h1>
              <?php the_content(); ?>
            </article>

          <?php endwhile; ?>
        </section>
      </div><!-- .row -->
    </div><!-- .container -->
  </main>

<?php get_footer(); ?>
  1. Now links in the Header Menu should navigate to each page when clicked.

Set Static Homepage.

  1. Previously I created four pages: Home, About, Contact, and Blog; now we would like to set a static home page and have our blog posts show up under the blog page instead. In the browser in the Admin Dashboard view head to Settings>Reading and under Front page displays heading select the radio button for static page, and under Front page I will select Home a page I created previously. Under Posts page I will select Blog a blank page I created previously.

Create Custom Widget Areas

  1. In functions.php add the following code:
function register_my_widgets() {
  register_sidebar(array(
    'name' => 'Sidebar',
    'id' => 'sidebar-1',
    'description'   => 'Custom Sidebar Widget',
    'before_widget' => '<div class="sidebar-widget">',
    'after_widget' => '</div>',
    'before_title' => '<h4>',
    'after_title' => '</h4>',
  ));
}
add_action( 'widgets_init', 'register_my_widgets' );
  1. In sidebar.php remove the code inside <aside>...</aside> and add the following code in its place:
<aside class="col-md-3">
  <?php if (is_active_sidebar('sidebar-1')) {
    dynamic_sidebar('sidebar-1');
  } ?>
</aside>
  1. In style.css add the following code to style <ul> in your widgets:
[class="-widget"] ul {
  list-style: none;
  padding-left: 0;
}
  1. Now in the browser head to Appearance>Widgets and drag a Widget such as Archives to the new widget area labeled Sidebar. Now in the user facing view of the side you should see the Widget location appearing at in the sidebar of the blog link.
  2. Now let's add four additional register_sidebar functions for new footer widget areas in functions.php:
function register_my_widgets() {
  register_sidebar(array(
    'name' => 'Sidebar',
    'id' => 'sidebar-1',
    'description'   => 'Custom Sidebar Widget',
    'before_widget' => '<div class="sidebar-widget">',
    'after_widget' => '</div>',
    'before_title' => '<h4>',
    'after_title' => '</h4>',
  ));
  register_sidebar(array(
    'name' => 'Footer 1',
    'id' => 'footer-1',
    'description'   => 'Custom Footer Widget',
    'before_widget' => '<div class="footer-widget">',
    'after_widget' => '</div>',
    'before_title' => '<h4>',
    'after_title' => '</h4>',
  ));
  register_sidebar(array(
    'name' => 'Footer 2',
    'id' => 'footer-2',
    'description'   => 'Custom Footer Widget',
    'before_widget' => '<div class="footer-widget">',
    'after_widget' => '</div>',
    'before_title' => '<h4>',
    'after_title' => '</h4>',
  ));
  register_sidebar(array(
    'name' => 'Footer 3',
    'id' => 'footer-3',
    'description'   => 'Custom Footer Widget',
    'before_widget' => '<div class="footer-widget">',
    'after_widget' => '</div>',
    'before_title' => '<h4>',
    'after_title' => '</h4>',
  ));
  register_sidebar(array(
    'name' => 'Footer 4',
    'id' => 'footer-4',
    'description'   => 'Custom Footer Widget',
    'before_widget' => '<div class="footer-widget">',
    'after_widget' => '</div>',
    'before_title' => '<h4>',
    'after_title' => '</h4>',
  ));
}
  1. In footer.php create a new row with four columns and each has the widget placement code within:
<footer>
  <div class="container">
    <div class="row">
      <div class="col-md-3">
        <?php if (is_active_sidebar('footer-1')) {
          dynamic_sidebar('footer-1');
        } ?>
      </div>
      <div class="col-md-3">
        <?php if (is_active_sidebar('footer-2')) {
          dynamic_sidebar('footer-2');
        } ?>
      </div>
      <div class="col-md-3">
        <?php if (is_active_sidebar('footer-3')) {
          dynamic_sidebar('footer-3');
        } ?>
      </div>
      <div class="col-md-3">
        <?php if (is_active_sidebar('sidebar-4')) {
          dynamic_sidebar('footer-4');
        } ?>
      </div>
    </div>
    <div class="row">
      <div class="col">
        <p class="copyright"><small>&copy; <?php echo date( 'Y' ); ?> <?php bloginfo( 'name' ); ?>, <?php bloginfo( 'description' ); ?>. All Rights Reserved.</small></p>
      </div><!-- .col -->
    </div><!-- .row -->
  </div><!-- .container -->
</footer>
  1. Add some styles for our footer in style.css:
footer {
  margin-top: 40px;
  border-top: 1px solid #ccc;
  background: #f8f9fa;
  padding-bottom: 40px;
}

footer .row {
  padding: 40px 0 10px;
}

.copyright {
  text-align: left;
  color: #777;
}

[class$="-widget"] .menu-item, [class$="-widget"] .menu-item a {
  display: block;
  padding: 0;
}

[class$="-widget"] ul {
  list-style: none;
  padding-left: 0;
}
  1. In the browser under Appearance>Widgets your four new footer Widget areas should appear.

Displaying Comments On Posts & Pages

  1. Create a new file called comments.php and add the following code:
<?php
$args = array(
  'post_id' => get_the_ID(),
  'status' => 'approve'
);
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query( $args );
if ( $comments ) {
  foreach ( $comments as $comment ) {
    echo '<hr>';
    echo '<p>'.$comment->comment_content.'</p>';
  }
} else {
  echo '<p>No comments found.</p>';
}
comment_form();
?>
  1. Then in your index.php & page.php add a place for comments to display if they are enabled:
<?php if (comments_open() || get_comments_number()) {
  comments_template();
} ?>
  1. Then add some styles for your comment form in style.css:
.comment-respond {
  border: 1px solid #ccc;
  background: #efefef;
  padding: 20px;
}

.form-submit input[type="submit"] {
  display: inline-block;
  font-weight: 400;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  border: 1px solid transparent;
  padding: .5rem .75rem;
  font-size: 1rem;
  line-height: 1.25;
  border-radius: .25rem;
  transition: all .15s ease-in-out;
  color: #fff;
  background-color: #007bff;
  border-color: #007bff;
  cursor: pointer;
}

Create a Theme Screenshot

  1. In a browser head to localhost and take a screenshot of one of your pages I choose my Home page. Screenshots should follow 4:3 aspect ratio and be a maximum of 1200px x 900px in size. In our case we're going to open the file in Photoshop and resize it to 880px x 660px. Then save it under the name screenshot.png in the root of your custom theme folder in my case it is at custom_theme/screenshot.png. In the browser Admin Dashboard head to Appearance>Themes and you should see your thumbnail image appearing as well as all the details you included in your style.css file.

Creating Custom User Theme Controls

  1. In functions.php include the following code which will allow us to style the text color of <h1> elements:
function register_my_customizations( $wp_customize ) {
  // setting
  $wp_customize->add_setting( 'header_color' , array(
    'default'   => '#000000',
    'transport' => 'refresh',
  ));
  // section
  $wp_customize->add_section( 'colors' , array(
    'title'      => __( 'Colors', 'custom_theme' ),
    'priority'   => 30,
  ));
  // control
  $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'link_color', array(
    'label'      => __( 'Header Color', 'custom_theme' ),
    'section'    => 'colors',
    'settings'   => 'header_color',
   )
  ));
}
add_action( 'customize_register', 'register_my_customizations' );

function apply_my_customizations() {
  echo '<style type="text/css">'.
          'h1 { color: '.get_theme_mod('header_color','#000000').'; }'.
       '</style>';
}
add_action( 'wp_head', 'apply_my_customizations');
  1. Now head to the browser under Appearance>Customize there should be a new section labeled Colors, and inside it you hsould be able to update the header color. For more information on Customizations see the docs on Theme_Customization_API and browse some example code. For an explantion of the __() function see this reference.

Custom Page Template Files

  1. Create a sub folder in your theme called page-templates.
  2. Duplicate page.php into the page-templates folder and give it a name that is not already reserved by WordPress. I called mine include-sidebar.php.
  3. Add the following code as a PHP comment at the top of the file:
/*
 * Template Name: Include Sidebar
 * Description: Page template with sidebar included.
 */

The name under Template Name is what will be displayed under Page Attributes in the WordPress editor.

  1. Then I changed the previous layout, adding in the get_sidebar() function and changing the column classes to reflect a nine column beside a three column sidebar:
<?php
/*
 * Template Name: Include Sidebar
 * Description: Page template with sidebar included.
 */

get_header();
?>

  <main>
    <div class="container">

      <div class="row">
        <section class="col-md-9">
          <?php while ( have_posts() ) : the_post(); ?>

            <article>
              <h1><?php the_title(); ?></h1>
              <?php the_content(); ?>
            </article>

    			<?php endwhile; ?>
          <?php if (comments_open() || get_comments_number()) {
            comments_template();
          } ?>
        </section>

        <?php get_sidebar(); ?>

      </div><!-- .row -->
    </div><!-- .container -->
  </main>

<?php get_footer(); ?>
  1. Now to test our template, head back to the browser and under the Admin Dashboard click Pages > All Pages. Click to edit a page and now under Page Attributes there should now be a Template menu where you can select between Default Template (page.php) or Include Sidebar (page-templates/include-sidebar.php).

Advanced Custom Fields

Custom fields can be added both using raw code in either the functions.php file, as custom plugin code, or using a pre-created plugin such as Advanced Custom Fields Plugin. Below I demonstrate creating custom fields using a pre-made plugin. If you are interested to build this by writing your own code from scratch you can refer to the tutorial here instead. I teach using the plugin so the end user can update custom fields without having to write any code.

  1. Start by installing the Advanced Custom Fields Plugin under Plugins > Add New then search for Advanced Custom Fields, find the plugin by By Elliot Condon, click Install and then Activate.
  2. Next, click the new Custom Fields link from the left side Navigation in the Admin Dashboard.
  3. Click Add New, and under New Field Group give it a name I called mine Blurbs. Then click the Add Field button.
  4. Name the new field under Field Label About Blurb.
  5. Set the field type as Text.
  6. Write a description for users to understand what this field is for using the Field Instructions area. I wrote: Set this to add about text to pages using the include sidebar page template.
  7. Under location set a rule such as Page template is equal to Include Sidebar.
  8. Click Publish.
  9. Now to place the field content in the file page-templates/include-sidebar.php remove the sidebar code and add in the custom field to display using the get_field('about_blurb') function like so:
<?php
/*
 * Template Name: Include Sidebar
 * Description: Page template with sidebar included.
 */

get_header();
?>

  <main>
    <div class="container">

      <div class="row">
        <section class="col-md-9">
          <?php while ( have_posts() ) : the_post(); ?>

            <article>
              <h1><?php the_title(); ?></h1>
              <?php the_content(); ?>
            </article>

    			<?php endwhile; ?>
          <?php if (comments_open() || get_comments_number()) {
            comments_template();
          } ?>
        </section>

        <aside class="col-md-3">
          <?php if(get_field('about_blurb')) {
  	        echo '<p>'.get_field('about_blurb').'</p>';
          } ?>
        </aside>
      </div><!-- .row -->
    </div><!-- .container -->
  </main>

<?php get_footer(); ?>
  1. To test head to Pages > Edit a page and under Page Attributes set Template to Include Sidebar. Below should appear a text input field to type some content for our About Blurb. Whatever text and HTML content you type here will appear inside the sidebar area.

Custom Post Types

WordPress provides us with Posts and Pages but what if I want to create Products, Recipes, Portfolios, or some other custom content in my site. For this we can use Custom Post Types.

Can be created using a plugin or by coding it from scratch into the functions.php file as detailed in the tutorial here. The instructions below describe the process using the Plugin which gives the end user more control over these post types without needing to code them from scratch. This article describes the pros and cons of each method.

  1. Under Plugins > Add New, search for Custom Post Type UI.
  2. Find the plugin by WebDevStudios and click to Install and then Activate it.
  3. In the newly created left hand navigation link (in Admin Dashboard) click on CPT UI > Add/Edit Post Types.
  4. Under slug put product.
  5. For Singular Label put Product and plural label put Products.
  6. Under Has Archive select true so that we will be able to access a list of all products from the /product/ URL.
  7. Under Supports check the boxes for anything you'd like to include on Product pages. In my case I checked Custom Fields so I can include a Price.
  8. Fill out any other options you desire and then click Add Post Type button.
  9. Refresh the page and you should now see a Products link. Click Products > Add New. Type a name for the product Baseball and in the description write A baseball, good condition!.
  10. Click Publish button to publish this product.
  11. To display this product let's head to Appearance > Menus and select Header Menu.
  12. Under Custom Links, for URL put /product/ then for Link Text put Products and click Add to Menu button, and then click the Save menu button.
  13. To test head to the browser and click the Products link from the Header Menu. Your Baseball Product should be listed there.
  14. Got to Custom Fields > Field Group, Add New.
  15. Name the Field Group Products and then click Add Field button.
  16. Set the field label to Price and the field name to _price, field type to Number, required Yes, default value 0, step size 1.
  17. Set Location to Post Type is equal to product and then click Publish button. Now our custom post type of Product has a custom Price field.
  18. Next let's create a page layout unique to products by duplicating the index.php file and name it archive-product.php.
  19. In the archive-product.php file remove the sidebar and column classes and change the get_template_part( 'single', get_post_format() ) to get_template_part( 'single', 'product', get_post_format() ). Following is the full code for this page:
<?php get_header(); ?>

  <main>
    <div class="container">

      <div class="row">

        <section class="col">
          <?php if ( have_posts() ) : while ( have_posts() ) : the_post();
    				get_template_part( 'single', 'product', get_post_format() );
    			endwhile; endif;

          if (comments_open() || get_comments_number()) {
            comments_template();
          } ?>
        </section>

      </div><!-- .row -->
    </div><!-- .container -->
  </main>

<?php get_footer(); ?>
  1. Next duplicate single.php and name it single-product.php.
  2. In single-product.php change the code to the following:
<?php setup_postdata( $post ); ?>

<?php get_header(); ?>

  <main>
    <div class="container">

      <div class="row">
        <section class="col">
					<article id="post-<?php the_ID(); ?>">
						<h1><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
					  <p><?php the_content(); ?></p>
						<p><?php echo "Price: $".get_field('_price').".00"; ?></p>
					</article>
	       </section>
      </div><!-- .row -->
    </div><!-- .container -->
</main>

<?php get_footer(); ?>
  1. To test click the Products link to view all products which will now display our custom layout as well as our custom Price field.

Default Template Files

  1. See the documentation on Template File Name List to discover default names. It is recommended to create all template files such as: 404.php, category.php, archive.php, tag.php, author.php, attachment.php, image.php, etc. then style them to your liking.

Resources

License

Copyright (c) 2017 Jonathan Grover All Rights Reserved.

Contact

hello@jonathangrover.com

About

Finished example wordpress app featuring a custom built theme with step by step instructions

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published