Setting Up Your Theme Functions

We’ve got a file structure in place, now let’s start adding things to them!

First, we’re going to add some PHP functions to our theme. These functions will serve a variety of purposes, including:

  • adding support for WordPress features such as custom backgrounds, headers, post formats, etc
  • setting up theme defaults
  • acting as “containers” for code we can reuse throughout the theme

Files we’ll edit or create in this lesson

  • functions.php
  • inc/template-tags.php
  • inc/tweaks.php

If you’re new to PHP, then think of a function as a “machine” that performs a specific task, whenever we need it to, We define functions like this:

function my_function() {
  ...contents of the function
}

After we’ve defined a function, we can call it into our theme files wherever we need it to execute its magic. A function call can be as simple as writing the function name followed by a semicolon:

<div>
    <?php my_function(); ?>
</div>

Other function calls are a little more complex.

<div>
    <?php my_second_function( 'parameter 1', 'parameter 2' ); ?>
</div>

In the above example, we are passing parameters into our function. Parameters are a type of variable that you input, or pass, into the function. The function then uses it to produce the final output. It’s sort of like those penny press machines at zoos and museums.

We’ll be calling lots of functions into our theme!

Functions.php

Without delay, let’s get started. In the theme directory you created last lesson, open functions.php. At the top, paste the following:

<?php
/**
 * Shape functions and definitions
 *
 * @package Shape
 * @since Shape 1.0
 */

If you’re new to PHP, we start off the file with the opening PHP tag: <?php.

Next, we have a comment block with some inline documentation: a brief description of the file, followed by the PHPdoc Tags: “@package and @since”. You can read more about Inline Documentation on the WordPress Codex.

A word about PHP comments. You might be familiar with HTML comments: In PHP, you’ll find two types of comments, multi-line and single-line. Multi-line comments are wrapped between /* and */, while a single-line comment starts off with a double-slash (//). PHP will ignore the comments, so they’re great for inline documentation.

$content_width

$content_width is a global variable that sets the maximum width of content (such as uploaded images) in your theme. It prevents large images from overflowing the main content area. We should set the value of $content_width to match the width of our main content area. Thinking back to our HTML structure, this area is the #content div. We’ll use CSS to set the width of the div, however, we haven’t gotten to CSS yet. So for now, I’ll tell you that the div will be 654px wide, and we’ll revisit it later, during the CSS lesson.

In functions.php, skip a line after the last */, and paste this code:

/**
 * Set the content width based on the theme's design and stylesheet.
 *
 * @since Shape 1.0
 */
if ( ! isset( $content_width ) )
	$content_width = 654; /* pixels */

So, $content_width is set! PHP variables have a dollar sign (“$”) before their names, and a semi-colon (“;”) after the assigned value.

shape_setup()

Next, we’re going to create a function that sets up theme defaults and registers support for various WordPress features. Skip a line after the $content_width declaration, and add this.

if ( ! function_exists( 'shape_setup' ) ):
/**
 * Sets up theme defaults and registers support for various WordPress features.
 *
 * Note that this function is hooked into the after_setup_theme hook, which runs
 * before the init hook. The init hook is too late for some features, such as indicating
 * support post thumbnails.
 *
 * @since Shape 1.0
 */
function shape_setup() {

	/**
	 * Custom template tags for this theme.
	 */
	require( get_template_directory() . '/inc/template-tags.php' );

	/**
	 * Custom functions that act independently of the theme templates
	 */
	require( get_template_directory() . '/inc/tweaks.php' );

	/**
	 * Make theme available for translation
	 * Translations can be filed in the /languages/ directory
	 * If you're building a theme based on Shape, use a find and replace
	 * to change 'shape' to the name of your theme in all the template files
	 */
	load_theme_textdomain( 'shape', get_template_directory() . '/languages' );

	/**
	 * Add default posts and comments RSS feed links to head
	 */
	add_theme_support( 'automatic-feed-links' );

	/**
	 * Enable support for the Aside Post Format
	 */
	add_theme_support( 'post-formats', array( 'aside' ) );

	/**
	 * This theme uses wp_nav_menu() in one location.
	 */
	register_nav_menus( array(
		'primary' => __( 'Primary Menu', 'shape' ),
	) );
}
endif; // shape_setup
add_action( 'after_setup_theme', 'shape_setup' );

This code is well-commented, so you can get a good idea of what it’s doing. Did you notice that it’s mostly function calls? Can you spot the functions that take parameters?

Let’s walk through it, function by function.

We’re calling in two files that will live in our inc/ directory, template-tags.php and tweaks.php. We’ll create these files a little bit later in the lesson.

Next, we call the load_theme_textdomain() function. This tells WordPress we want to make our theme available for translation and that translation files can be found in our theme folder in a folder called “languages”. If you’re going to create a WordPress Theme, you should always try your best to make sure everything is translatable. You never know when you or someone else is going to need hard-coded content available in another language. There are several ways to make text translatable, and I’ll point these out when we get to them. If you just can’t wait, I18n for WordPress Developers is a great introduction.

All right, moving right along. The next two functions add support for links to your RSS feeds in the header; and for the Aside Post Format, respectively. The last function registers one navigation menu location, which we’ll use for our main menu.

Next, we close the function with a right curly brace “}”, and call it into our theme by “hooking” it onto another WordPress function:

add_action( 'after_setup_theme', 'shape_setup' );

In simplest terms, we’re telling WordPress to run shape_setup() when it runs the after_setup_theme() function. Did you notice that add_action() is itself a function, and that we’ve fed it two parameters?

We’ll add more things to functions.php in later lessons, but for now, we’re done with it.

You might have noticed that functions.php has no closing PHP tag (“?>”). When a file is mostly PHP, it’s safer to omit the closing tag. Why? Because it helps us to avoid errors caused by trailing white space after the closing PHP tag.

Template-tags.php and Tweaks.php

Remember these lines from earlier in this lesson?

/**
	 * Custom template tags for this theme.
	 */
	require( get_template_directory() . '/inc/template-tags.php' );

	/**
	 * Custom functions that act independently of the theme templates
	 */
	require( get_template_directory() . '/inc/tweaks.php' );

Go ahead and create template-tags.php and tweaks.php in your inc directory. Why are we placing these custom functions in separate files? Mostly to keep our functions.php clean, and to keep our theme modular. If you don’t need these functions in your theme, simply remove these lines.

template-tags.php

First things first. What, exactly, is a template tag? A function, of course! (“Function” seems to be the magic word in this lesson). Specifically, they’re WordPress functions that you insert within your theme to display dynamic information. You can learn everything you want to know about template tags on the WordPress Codex.

Most of the time, we’ll add template tags to our theme wherever we want them. However, there will be times when we put multiple template tags together to output a symphony of data. And because we “play” some of these “symphonies” more than once in our theme, it’s a good idea to place all of those tags into a function that we can call whenever we want to use them. So, think of all of the functions we’re going to add to this file as “mini-symphonies” of template tags that work together to produce a block of information: a sentence that says when a post was published, and by whom; or a set of previous and next post links; or a list of comments. You get the idea. We “write” the symphony once, and “play” it many times. Or, in technical terms: we define the function once, and call it many times.

In order to keep this lesson from becoming too long, we’ll return to template-tags.php in later lessons to add functions as we need them. For now, let’s just add the basic documentation to the top of the file.

<?php
/**
 * Custom template tags for this theme.
 *
 * Eventually, some of the functionality here could be replaced by core features
 *
 * @package Shape
 * @since Shape 1.0
 */

One last thing to note: “Eventually, some of the functionality here could be replaced by core features”. The functions we add here represent functionality that would be great as core WordPress features. That’ll all make more sense after we’ve added the functions, I promise.

Now, we can safely omit the closing PHP tag from this file as well.

tweaks.php

The functions we’ll place in this file don’t involve template tags. Instead, they will enhance our theme by modifying existing WordPress core features. They perform background tasks to add a little extra “awesome” to our theme.

At the top of the file, paste the usual documentation information.

<?php
/**
 * Custom functions that act independently of the theme templates
 *
 * Eventually, some of the functionality here could be replaced by core features
 *
 * @package Shape
 * @since Shape 1.0
 */

Next, paste the following functions.

/**
 * Get our wp_nav_menu() fallback, wp_page_menu(), to show a home link.
 *
 * @since Shape 1.0
 */
function shape_page_menu_args( $args ) {
	$args['show_home'] = true;
	return $args;
}
add_filter( 'wp_page_menu_args', 'shape_page_menu_args' );

/**
 * Adds custom classes to the array of body classes.
 *
 * @since Shape 1.0
 */
function shape_body_classes( $classes ) {
	// Adds a class of group-blog to blogs with more than 1 published author
	if ( is_multi_author() ) {
		$classes[] = 'group-blog';
	}

	return $classes;
}
add_filter( 'body_class', 'shape_body_classes' );

/**
 * Filter in a link to a content ID attribute for the next/previous image links on image attachment pages
 *
 * @since Shape 1.0
 */
function shape_enhanced_image_navigation( $url, $id ) {
	if ( ! is_attachment() && ! wp_attachment_is_image( $id ) )
		return $url;

	$image = get_post( $id );
	if ( ! empty( $image->post_parent ) && $image->post_parent != $id )
		$url .= '#main';

	return $url;
}
add_filter( 'attachment_link', 'shape_enhanced_image_navigation', 10, 2 );

The first function, shape_page_menu_args, has to do with our main navigation menu. We registered support for navigation menus earlier, in shape_setup(). If no navigation menu has been configured, WordPress will instead display a list of Pages (controlled by wp_page_menu()). This function adds a home page link to this list of pages.

In the second function, shape_body_classes(), we’re adding a new CSS class, ‘group-blog’, to our theme’s tag. We’ll talk about body classes in the WordPress Header Template lesson, but for now, just understand that body classes give us a way to style parts of our theme based on various conditions (such as, the type of page we’re viewing, or the number of published authors we have).

Finally, the third function, shape_enhanced_image_navigation(), adds a “#main” to the end of the next/previous image links on attachment pages (which we’ll build in a later lesson). Recall that “#main” is the ID name of the div that wraps our content and widget areas. IDs are also anchors within the page. When people click on your next/previous image links, they won’t have to scroll down from the top of the page to view each image.

And that’s it for tweaks.php. Remember, no closing PHP tag is needed at the end of the file.

Whew! That’s a lot of functions. We’ve laid a lot of groundwork in this lesson! There’s still much more to come, so stay tuned.

How To Create a WordPress Theme

This post is part of the The ThemeShaper WordPress Theme Tutorial: 2nd Edition that will show you how to create a powerful WordPress Theme from scratch. Read it from the beginning and code yourself up something awesome.

  1. WordPress Theme Tutorial Introduction
  2. Developing Theme Sense
  3. Theme Development Tools
  4. Creating a Theme HTML Structure
  5. Template and Directory Structure
  6. Setting Up Your Theme Functions
  7. Secure Your WordPress Theme
  8. The Header Template
  9. The Index Template
  10. The Single Post, Post Attachment, & 404 Templates
  11. The Comments Template
  12. The Search Template & The Page Template
  13. The Archive Template
  14. The Sidebar Template & The Footer Template
  15. The Sidebar Template & The Footer Template
  16. Reset-Rebuild Theme CSS & Define Your Layouts
  17. Custom Background & Custom Header
  18. Distributing Your WordPress Theme

45 responses

  1. You might want to go back and give the functions.php code snippet a second glance.

    I believe that lines 10-16 were meant to be part of the tutorial text and not included in the snippet.

    1. You’re right! Thank you so much, I’ve taken care of it.

  2. […] Home › Themes › Setting Up Your Theme Functions […]

  3. could you explain your choice of using:
    require vs require_once?

    I notice you don’t prefix the setup function (shape_setup) but instead wrap it in function_exists. Could you explain this choice?

    Is $content_width necessary in a responsive design, where we’ll declare img: max-width:100%?

    thanks 🙂

    1. WordPress relies on the $content_width variable for image sizes and embeds, some of which require a specific width (I think this is correct). So, even if you’re doing any type of flexible-width design, this is something that’s still required. I’m guessing you can always make it something like 9999 and just handle how it looks on the front end.

  4. Hey ThemeShapers! Love the series so far. Great work.

    One question: is there any particular reason you don’t put the $content_width definition inside your setup function? We (the Theme Review Team) have been trying to move developers more toward putting everything in functions.php inside callbacks. Is there any advantage/disadvantage in doing so with $content_width?

    1. Definitely put it within the theme setup function. This makes sure that it’s easy for child themes to know exactly what point to overwrite it. It also allows you to get rid of the isset() check.

    2. Just wanted to let everyone know that the discussion regarding $content_width is continuing as an issue on our github repo for _s.

  5. Now PHP is beginning to make sense and this is a great project to learn how WP works. It’s well written and fully explained; not just the How but, more specifically, the Why.
    Looking forward to the rest of the project.
    Thanks

  6. Let’s say you want a theme with a header nav and a footer nav ( footer nav for legal stuff, disclaimer, cookie policy and so on).

    Is it possible to register two different nav elements in functions.php like this;
    register_nav_menus( array(
    'primary' => __( 'Primary Menu', 'shape' ),
    'secondary' => __('Secondary Menu, 'shape') );

    or should any other custom nav be created later on?

    1. Hi Warner,

      Great question! Yes, you would register all of your navigation menus in functions.php just like you’ve done so in your code sample.

      In the header.php lesson (which is coming soon), we’ll use wp_nav_menu() to display the header navigation in our theme. To display the footer navigation, you would use wp_nav_menu() in a similar fashion in footer.php, or wherever you want the menu to appear.

      1. Hi Michelle,

        I will be looking out for the header.php lesson.

        You have done a great job explaining everything so far. Thank you! Now all i have to do is keep an eye out for the closing HTML tags (code tag in my initial question).

  7. I have a tough question. If I want to create a theme that doesn’t depend on shape is it even worth reading this tutorial? This tutorial seems like its very knowledge packed so far but its dependence on shape is making it hard to follow in this section. Maybe I am wrongly judging this material but please let me know if I am wasting my time if I have little interest in shape. I am actually very interested in using bootstrapped for scaffolding and css so I want to learn as much as I can about WordPress creation but the dependence on shape is making it tough to follow, especially when creating the functions.php file. Thanks a lot in advance Michelle.

    1. Hi Erick!

      You might find some of the concepts we’ll cover — such as WordPress Template Tags, the WordPress Loop, WordPress template files, etc — useful, regardless of whether or not you build your theme on Shape (or on Underscores, the starter theme on which Shape is based). What’s more important is that you understand the broader concepts: what types of files make up a WordPress theme (index.php, header.php, single.php, etc), and how to implement WordPress Template Tags and other WordPress functions within those files. The functions.php file — along with every file that that we’re building in this tutorial — is intended to be a starting point. You can always adapt it to suit the purposes of your project. The WordPress Codex is a great resource for furthering your knowledge of Template Tags and other WordPress functions to suit your needs, beyond what we cover in the tutorial.

      I hope this helps!

      1. Thank you very much!

  8. David Ackerman Avatar
    David Ackerman

    In Setting Up Theme Functions, I wonder if this is a typo:
    if ( ! function_exists( ‘shape_setup’ ) ):

    Shouldn’t the “!” be removed?

    David

    1. The code is correct as-written. The Theme is defining the setup function as pluggable, so that a Child Theme can easily override it, by defining a function with the same name.

  9. looking for today’s article??

    Al

    1. Hi Al! The next article, Securing Your WordPress Theme, will be published tomorrow (Tuesday), October 30. Apologies for the delay.

  10. […] Setting Up Your Theme Functions – We’ve got a file structure in place, now let’s start adding things to them! First, we’re going to add some PHP functions to our theme. These functions will serve a variety of purposes […]

  11. Nate Spry Avatar

    I am getting an error on my page and my lack of understanding in regard to what the:

    register_nav_menus( array(
    ‘primary’ => _( ‘Primary Menu’, ‘mozart’ ),

    command is doing ( I’m using ‘mozart’ instead of ‘shape’)

    When I load my page I get:

    Warning: _() expects exactly 1 parameter, 2 given in /home/content/05/9108205/html/wp-content/themes/mozart/functions.php on line 61

    Can someone help a dummy?

    1. Hi Nate,

      I believe you are trying to register the primary nav without a double underscore _ and you seem to be missing a bracket ) and a semi-colon ; at the end.
      try;
      register_nav_menus ( array (
      'primary' => __( 'Primary Menu', 'mozart' ),
      ) );

      More information on creating menu’s can be read here;
      http://codex.wordpress.org/Function_Reference/register_nav_menus

  12. Hi Nate! You are getting this error because there is a small typo in your code. You are using _() which is an alias for the php function gettext() which only accepts on parameter. You will want to use __() which is a function defined in WordPress and returns a translated string if one exists.

    1. Nate Spry Avatar

      Thank you so much! What a silly mistake.

      That’s fixed it! Thanks again!

  13. I don’t understand 2 things from the code of the tweak page. Sorry i’m a newbie!

    First:
    isn’t more simple to use wp_page_menu(‘show_home=1’) instead of what you have proposed?
    Second:
    I don’t understand, even i’ve read the codex explanation of add_filter function, what actually it does.

    Sorry if my english isn’t perfect.

  14. In case anyone else is having the same problem–make sure that the includes exist.

    I’m using Using MS WebMatrix (because it’s the fastest way I’ve found to get a test environment on a Windows box), I was getting problems because the included files were missing. I simply added the called includes as blank files (specifically, these: /inc/template-tags.php and /inc/tweaks.php), and it works again.

  15. John Creapy Avatar
    John Creapy

    hi my theme is “dazzle”

    so I have to use dazzle_setup instead of shape_setup?

    1. You don’t have to use it (shape_setup will technically work as-is) but for the sake of good namespacing using dazzle_setup is recommended.

  16. Hi there, I have a question regarding shape_page_menu_args(). All that function does is set a value, so why is it a function? Wouldn’t add_filter( ‘wp_page_menu_args’, ‘$args’ ); do exactly the same thing?

  17. Just some questions:

    May I call template-tags.php and tweaks.php outside the theme_setup?
    What is the different between calling theme insite and outsite the theme_setup?

    When I try to call the custom_header.php insite the theme_setup, I lost my custom header. Why?

    I have read some explanations form others but, I still don’t understand what function must or may be called insite or outsite the theme_setup.

    1. One quetion again:
      When I want to put my custom functions (filtering, creating shortcode, etc), where’s the best place to put them, insite the template-tags.php, tweaks.php or easily insite the functions.php?
      Thanks.

      1. It is really up to you 🙂 I have been putting them inside the files that I think are most appropriate, but I think I’m going to change this moving forward and only put them in functions.php or maybe even a custom file like my-theme.php. The reason is that I think this will make merging new changes from _s a bit easier in the future. In all honesty, it’s really personal preference.

    2. May I call template-tags.php and tweaks.php outside the theme_setup?

      Yep!

      What is the different between calling theme insite and outsite the theme_setup?

      Requiring these files outside of the after_setup_theme callback means that the code is included before the after_setup_theme action fires. Requiring them in the callback means that they will be included during the after_setup_theme action.

      When I try to call the custom_header.php insite the theme_setup, I lost my custom header. Why?

      This is because the the custom header script hooks into after_setup_theme itself. If you require it inside another callback to after_setup_theme it will be too late because after_setup_theme has already fired.

      1. Many thanks for your kindness to answer my questions clearly. It very helps me to understand more.

        And after reading this:

        This is because the the custom header script hooks into after_setup_theme itself. If you require it inside another callback to after_setup_theme it will be too late because after_setup_theme has already fired.

        Oh how stupid I am, why didn’t I notice before this the line 61 in custome-header.php of _s theme and the line 47 in custom-header.php of twentytwelve? Thanks for your direction.

        …or maybe even a custom file like my-theme.php.

        So, is it correct if I create for example miscellaneous .php and I put all my custom functions and lastly I call them after calling custom-header.php? Or maybe after calling tweaks.php inside the theme_setup? I’m sorry, this question just for make me more sure and I want to keep my functions.php in small size because I have added many menus (about 5 menus) and many sidebar (about 10 areas).

        I’m sorry and thanks.

  18. sofian Avatar

    Hello, first of all thank you for this wonderful tutorial, i’m working my way through it and the detailed and nice descriptions make it very easy and joyable to follow.

    – i have a question regarding the if ( ! isset( $content_width ) ) or if ( ! function_exists( ‘shape_setup’ ) ) usage. I understood that it would not be needed to ask if they exist, but it is best practice in programming, right? Now i started to wonder: If we want to avoid, that our programming overwrites an already existing function that might appear from (no)where?, then what do we do if this should really happen? Then our function or variable would not be defined and our whole theme might break down. Please tell me where my gap in thinking lies.

    – and i was searching for such a solution for the “leave a reply” section as you have it here, something decent that only unfolds when we use it. Is it a plugin?

    Thank you and a wonderful day
    Sofian

    1. i have a question regarding the if ( ! isset( $content_width ) ) or if ( ! function_exists( ‘shape_setup’ ) )

      We are defining the setup function to be pluggable, so a Child Theme can easily override it by defining a function with the same name.

      and i was searching for such a solution for the “leave a reply” section as you have it here

      We are on WordPress.com here but you can replicate it on your self-hosted WordPress.org site with the Jetpack plugin: http://jetpack.me/ http://jetpack.me/support/comments/

  19. Carlos Z. Avatar
    Carlos Z.

    I get a lot of what’s going on but, I am confused where (‘shape’) comes from and how it gets created. I know gets passed as a parameter/argument. But is ‘shape’ a function or a variable and what does it refer to? For example

    load_theme_textdomain( ‘shape’, get_template_directory() . ‘/languages’ );

    What is shape passing to this function.

    OR

    register_nav_menus( array(
    ‘primary’ => __( ‘Primary Menu’, ‘shape’ ),
    ) );

    That’s the part that really confuses me. Any help would be appreciated since ‘shape’ pops up a lot on this tutorial. Once again Thanks.

    1. 'shape' is the theme’s textdomain, which is being registered as such by passing it as the first argument to load_theme_textdomain();. This is how we let WordPress know, that all translation functions with 'shape' as the textdomain, should be looked up in the directory that was registered with that domain.

  20. Hi, I am new to both wordpress and creating wordpress themes. But I had a question about the tweaks.php file. When I created it I replaced the name shape with my theme name cgsd in all the comments and in the function names/variables. When I did this my site receive the wordpress white-screen of death. But when I put the everything back to shape it loads fine. Going forward should I leave the shape name or should I use my template name in the function name? If the later how should I go about changing the names without have my template blow up? Any help you can give me would be greatly appreciated.

    1. Hi David,

      You can either keep the “shape_” prefix before all functions, or change it to your own to reflect the name of your theme. One way to change all of the prefixes is to use Find/Replace in your editor. For example, in each file, you can automatically replace all instances of “shape_” with “cgsd_”. Hope this helps!

  21. Hi, first of all thank you for the tutorial. It’s great!

    After creating functions.php and copying the content into it I can’t see the source of my page any more. Is that what is expected or am I doing something wrong?

    1. No there – that definitely shouldn’t happen. 🙂 Try making sure you’re using a plain-text editor for your files – set to plaintext mode – and doublecheck that there are no blank lines at the top or bottom of the file.

  22. Hi Kathryn,
    thank you for your help. I’ve double checked everything you said but it is still not working. I added lines of code sequentially and the ‘bad’ one is the last one: add_action( ‘after_setup_theme’, ‘shape_setup’ ); Any idea why?

  23. Thanks for this informative tutorial!

    I’m trying to apply a function that would add text on only one page (page I.D. is 54) of the site, using a conditional statement.

    In the functions.php file I’ve pasted the following:

    function custom_add_text() {
    if (is_page(’54’)) {
    ?>

    This text is displayed by using a custom function that only appears on the About (page I.D. 54) page.

    <?php
    }
    }
    add_action( 'after_setup_theme', 'custom_add_text' );

    So far, I haven't gotten this function to add text to the specific page.

    Any advice for this novice would be greatly appreciated.

    Thanks,
    Alex

    1. Hi there, it looks like you’re passing the “54” as a string inside is_page(), when it should be an integer. Can you try: if ( is_page( 54 ) ) { ... } instead?