Theme Review Team

Welcome to the Theme Review team.

We are a group of volunteers who review and approve themes submitted to be included in the official WordPress Theme directory.

The Theme Review team maintains the official Theme Review Guidelines, the Theme Unit Test Data, and the Theme Check Plugin.

We also engage and educate the WordPress Theme community regarding best practices for themes.

Interested in joining the Theme Reviewers team?

Great! The team is open to anyone who wants to help out, and the process is simple. To find out more just visit the Join The Team page.

Want to know more? There is a more information in the Theme Review Team’s Handbook and the Review itself.

Once you get a theme to review, you will also get a mentor to help you on the road to becoming a theme reviewer.

Weekly meetings

We use Slack for real-time communication. As contributors live all over the world, there are discussions happening at all hours of the day.

We have a project meeting every Tuesday at 18:00 UTC in the #themereview channel on Slack.

There are also weekly theme trac meeting every Thursday at 18:00 UTC in #themereview

Recent Updates Toggle Comment Threads | Keyboard Shortcuts

  • Justin Tadlock 12:33 am on May 27, 2015 Permalink |

    Customizer snippet library: Initial feedback 

    One of the things we’ve been discussing is setting up a customizer snippet repository on the TRT GitHub account. Nothing is exactly set in stone just yet, but we wanted to gather some feedback before moving forward.

    • Should this be a library of non-core Controls?
    • Should it contain other snippets unrelated to controls?
    • How should things be organized?
    • What would you like to see?

    These are all really broad questions, but it’s important to get a feel for what we need to do first if we decide to go ahead with this project.

    We really need to start from square one and decide on exactly what we’d like the repo to be. From there, we can decide how to organize it. Then, we can put cool stuff in it.

    • Carolina Nymark 12:37 am on May 27, 2015 Permalink | Log in to Reply

      I think we should include core controls. Like a cheat sheet. It depends who the targeted audience is.

    • webdevmattcrom 12:53 am on May 27, 2015 Permalink | Log in to Reply

      This is an excellent idea. All of the above, categorized by type:
      — Core Controls
      — non-Core controls
      — Advanced Functionality (like forcing screen refreshes, or other things that are NOT controls)

    • tradesouthwest 1:04 am on May 27, 2015 Permalink | Log in to Reply

      Where was this when Theme Options was around? this may be why theme options is getting a bad name: it was never supported on the core team/TRT side, in any repository (such as Git) so develops ‘copy and pasted’ snippets from all over the web, that were not valid or sanitized.

      As to: “Should this be a library of non-core Controls?”
      Yes. Have a separate core hub. If you read my dialogue above you will see that the Customizer needs to support a wide variety of extensions and Theme Option’s “Replacement components” will be “outside of the box” (core).

      Organization: by the Default Customizer Sections (title_tag, color, header_image, background_image, nav…. ) and then by “Plugin-Like Customizer” sections, as I call them, that are all custom callouts, or extensions or the Default Sections.

      I still think Customizer is not a good fit for theme options. Customizer does not support a broad enough spectrum for end-users to be able to control the UI-UX. And it’s too page-physically small as well as full of scripts that eat up bandwidth.

      No reply to last para.; I am just remaining vigilant on my stance against Customizer: poor Method to develop or to become creative with. Maybe this snippet hub will provide a solution for theme options as well, by providing standardized, clean code to work with and TO will come back to life.

  • Tammie 10:13 pm on May 26, 2015 Permalink |  

    First theme trac meeting.

    We are having our first theme trac meeting on Thursday 2015-05-28 at 18:00 UTC. This will be a chance to look at tickets in themes and also core themes. Our goal is to get people to comment tickets they want looked at and we’ll discuss in the meeting. This is meant to be along with core efforts and is going to run for a month to see what happens.

    Each meeting will have a strict 1hour time slot. We can then ensure we keep on track. If we only discuss one ticket, so be it. We can get to things over time. We can also evolve things as we see what works.

    So far here is the tickets mentioned by @poena:

    I’m mentioning them now so people can have time to add others they want in comments and look at tickets. If you have time to then test, comment and even assist with these tickets before the meeting.

  • Tammie 10:02 pm on May 26, 2015 Permalink |  

    Weekly meeting notes

    The archive is here: https://wordpress.slack.com/archives/themereview/p1432663198000608

    We had a very active chat, here is a summary.

    • This Saturday 31st May we are having a queue sprint again. Any admins or key reviewers will be focusing on the admin approval queue. Everyone else please focus on the review queue. Lets get those queues down!
    • We talked content creation grey areas. Examples are going to be looked at and this will be next week’s main topic of conversation.
    • Our weekly meetings on Thursday are changing from being mentoring meetings to being Theme Trac meetings. This is a chance for us to work through the tickets, get involved and help in areas that relate to either themes in core component or core themes. This will be at 18:00 UTC. This group is starting out of interest from members and won’t take away from what core is doing, hopefully it will assist and support.

    Next week we will be discussing:

    • Content creation clarification
    • Snippet library

    Thanks for all that attended.

  • Tammie 10:00 am on May 26, 2015 Permalink |  

    Weekly meeting agenda

    This week we’re going to have a meeting at 18:00 UTC. We have no set agenda, so please add anything you’d like to talk about here as a comment.

  • Frank Klein 7:25 am on May 26, 2015 Permalink |  

    A Guide to Writing Secure Themes – Part 2: Validation 

    Validation is a technique to ensure that input is secure before using it in your code.

    When validating data, you are verifying that it corresponds to what the program needs. This only works if you have a list of criteria that you can check to determine that the data is valid.


    The simplest validation method is whitelisting. This only works when there is a precise set of possible values that the data can have.

    Let’s look at how whitelisting can be used for validating a theme option controlling the position of the sidebar.


    Here is the code that we used to create the setting and the control:

    $wp_customize->add_setting( 'sidebar-position', array(
        'default'           => 'left',
        'sanitize_callback' => 'wptrt_validate_sidebar_position',
    ) );
    $wp_customize->add_control( 'sidebar-position-control', array(
        'label'    => esc_html__( 'Sidebar Position', 'wptrt' ),
        'section'  => 'theme',
        'settings' => 'sidebar-position',
        'type'     => 'radio',
        'choices'  => array(
            'left'  => esc_html__( 'Left', 'wptrt' ),
            'right' => esc_html__( 'Right', 'wptrt' ),
    ) ) );

    The user only has two choices: left or right. This means that in the wptrt_validate_sidebar_position(), we can determine whether the submitted option is one of the two possible values.

    function wptrt_validate_sidebar_position( $sidebar_position ) {
        if ( in_array( $sidebar_position, array( 'left', 'right' ), true ) ) {
            return $sidebar_position;

    To do this, we use the in_array() PHP function. This function returns true when the needle, the submitted value for the position of the sidebar, is in the haystack, the list of possible positions.

    The third parameter of the in_array() function is to enable strict type comparison. We pass true as an argument, to enable the strict checking. This is important, because in PHP loose type comparison can lead to unexpected results.

    So whitelisting simply means that we compare the submitted data against a list of acceptable values. This works well for controls such as checkboxes, radio buttons, selects, and dropdowns.

    But how can we validate data for which we don’t know the possible values? Let’s have a look at validating data according to a set of qualifications.

    Qualifying data

    When qualifying data, we try to find out whether it meets a precise set of criteria. Let’s look at an example of validating data.

    Imagine that you have a meta box that allows users to enter a value for the width (in pixels) of the content area of a particular post. While not being a super useful feature in a theme, this example allows us to demonstrate the use of filter_input().

    The filter_input() PHP function gets a variable and validates it. The function accepts four arguments: the type of input, the name of the variable to get, the filter (validation) to apply, and an optional array of options.

    $content_area_width = filter_input(
                    array( 'options' => array(
                        'default'   => 500,
                        'min_range' => 100,
                        'max_range' => 1000,
                    ) )

    Although the code for this function might seem verbose, it’s much shorter and clearer than writing it all out:

    // Warning: This code does not work correctly.
    if ( isset( $_GET['content_area_width'] ) && is_int( $_GET['content_area_width'] ) && $_GET['content_area_width'] >= 100  && $_GET['content_area_width'] <= 1000 ) {
        $content_area_width = $_GET['content_area_width'];
    } else {
        $content_area_width = 500;

    You might wonder why there is a warning about this code not working. Seems to look good, right? The problem is that is_int( $_GET['content_area_width'] ) will always return false, so this code will always return 500.

    This is because data retrieved from the $_GET and $_POST super globals is always of the type string. Using the filter_input() function allows us to get around this limitation of the PHP language.

    Choosing the right qualifications

    When validating data, it’s crucial that you choose the right set of qualifications, and express this correctly in the code.

    Imagine that you have a Customizer setting in your theme for entering a link to a Twitter profile. You want to have a valid URL for this setting, so you use the filter_var() PHP function with the FILTER_VALIDATE_URL filter.

    // Warning: Insecure code!
    function wptrt_validate_twitter_profile_url( $url ) {
        return filter_var( $url, FILTER_VALIDATE_URL ) );

    The next thing you do is output the validated URL in your theme:

    // Warning: Insecure code!
    echo '<a href="' . $twitter_url . '">' . esc_html__( 'Twitter', 'wptrtp' ) . '</a>';

    In the four lines of code that we have seen so far, we have made two crucial mistakes:

    1. We trusted the filter_var() function to validate the URL to the Twitter profile.
    2. We didn’t escape the URL on output.

    We are going to look at escaping in a later part of this series. For now let’s look at why the validation was too weak to be secure.

    The problem is that if you enter javascript://test%0Aalert(321), this is a valid URL. As soon as a user would click on the Twitter link on the front end of the site, a Javascript dialog would appear.

    We need to add additional checks to our function:

    function wptrt_validate_twitter_profile_url( $url ) {
        if ( 0 !== strpos( $url, 'https://twitter.com/' ) ) {
        return filter_var( $url, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED ) );

    This function now verifies that the data meets three qualifications:

    1. The URL starts with https://twitter.com/.
    2. The URL is valid according to the RFC 2396 standard.
    3. The URL has a path component (as in http://example.org/path).

    Validation functions

    WordPress validation functions

    WordPress only has a couple of validation functions.

    • is_email(): Checks whether the data is a valid email address. The validation done by the function does not comply with the RFC 822 standard, and does not work with internationalized domain names.
    • wp_validate_boolean(): Despite the name, this function not only validates, but also sanitizes the data passed to it. So the return value will always be a boolean. You can use filter_var( $var, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ) as an alternative, as it returns NULL when the passed data is not valid.
    • sanitize_hex_color(): This actually a validation function, as it returns null if the color code isn’t valid. It is only available in the Customizer context, but it’s a small function so you can copy the code to your own validation function if needed.
    • sanitize_hex_color_no_hash(): The same as sanitize_hex_color() but for values without a leading #.

    PHP validation functions

    PHP offers a number of validation functions. As we have seen previously, using them can be a bit tricky. So make sure to read the documentation carefully, including the notes.

    • is_bool(): Returns true if the passed variable is of the type boolean.
    • is_float(): Returns true if the passed variable is of the type float.
    • is_int(): Returns true if the passed variable is of the type integer.
    • is_numeric(): Returns true if the passed variable contains a numeric value. Keep in mind that this encompasses all numeric values, so signs, hexadecimal, binary, and octal values are all valid.
    • strtotime(): Not a validation function strictly speaking, but can be used as such to validate dates. The function returns false if the passed data cannot be converted into a timestamp.

    Next we have a family of functions that have been specifically designed to validate data.

    • filter_input(): Retrieves an external variable (from $_GET, $_POST, $_SERVER,…) and applies the specified filter.
    • filter_input_array(): Works the same as filter_input(), but allows multiple values to be retrieved with one call.
    • filter_var(): Filters the variable passed as an argument.

    When using these functions, you need to indicate a filter to use. The validation filters can be combined with flags to achieve a specific behavior. Some filters also accept additional options.

    It’s the combination of the right filter, with the right flags, and the right options that makes these functions do their work correctly.


    Now that we have a solid grasp on how validating data works, we’ll look at sanitization in the next part of this series.

  • Dion Hulse 8:11 am on May 20, 2015 Permalink |  

    Hi Everyone,

    Just letting you know that today I’ve rolled out the start of the international Theme Directories, for example: https://ro.wordpress.org/themes/

    A few points that impact both Theme Reviewers and Theme Authors:

    • Theme submissions from these localised sites are possible, if theme reviewers start to see an increase in non-english uploads, please let the meta team know so we can alter wording/warnings for those uploading to be more clear
    • Theme Descriptions are not yet translated, even if the theme ships with translations of the description. We’ll be working on that part next. This will also apply to any eventual readme improvements we make.
  • Frank Klein 4:54 pm on May 19, 2015 Permalink |  

    A Guide to Writing Secure Themes – Part 1: Introduction 

    As a developer, keeping your users secure should be your most important priority.

    Having a theme available on WordPress.org is a huge responsibility, because security issues make every site running the theme potentially vulnerable.

    This guide will give you an introduction to the techniques you can apply to write secure code.

    The guide is broken up into parts to make it easier to read and apply. It contains everything I learned over the past three years while reviewing themes for WordPress.org, premium themes for WordPress.com, as well as themes and plugins for WordPress.com VIP.

    Before we get to the techniques, let’s have a look at the principles of secure code.

    Principles of secure code

    Writing secure code is not about using a particular function, tool, or workflow. Those things change over time, with new development techniques emerging and new security issues arising.

    The common element that connects all these things together is the state of mind of the developer. This mindset is based on three principles:

    1. Don’t assume anything. Only act on what you know for sure.
    2. Don’t trust any data. Consider data invalid and insecure until proven valid and secure.
    3. Don’t become complacent. Web technologies evolve, and so do best practices.

    With these principles on our mind, let’s clarify the meaning of a few terms we’re going to use in this series.

    Commonly used terms

    Input and output

    When we talk about input, this designates all the data that is given to our code.

    The most prevalent use case is information entered by the user, for example into a form field or the browser address bar. But it also encompasses data retrieved from stored cookies or from external services, like the Twitter API.

    Themes deal with this data in various ways. They might store it into the database, use it to retrieve data from the database, or display it to the user.

    When we talk about displaying information, we use the word output. But output is not just what we see on the screen, it’s all the data provided by our code.

    Imagine a PHP script that passes data to a Javascript script, such as data used to initialize a slider for example. In this case, the PHP outputs the data that is then used as input by the Javascript.

    If your code connects to a REST API, the JSON data returned by the API is the output, that your code then uses as input.

    Dynamic and static data

    When we talk about dynamic or static data, this is not to be confused with the static keyword in PHP.

    When we talk about static data, we designate data that cannot be changed except by changing the code. Here is an example:

    <?php echo 'Hello World'; ?>

    So when you read static, think of static HTML pages. These documents cannot return information that is not present in their source code.

    Dynamic data on the other hand can be modified through different ways. For example:

    <?php echo __( 'Hello World', 'wptrt' ); ?>

    In this code sample, the __() translation function returns data. This data can be filtered, or modified by loading a translation.

    What we are outputting is the return value of the function. Let’s look at this in more detail.

    Return values

    Return values is data provided by a function. In PHP you often see these return statements in functions:

    function wptrt_add_numbers( $a, $b ) {
        return $a + $b;

    Functions can return all kinds of data. Currently in PHP there is no way to force a function to return a certain type of data.

    This is important to keep in mind, because a lot of WordPress functions contain filters. So you can never be sure about the data that a certain function returns.

    Now that we have seen the vocabulary, we’ll look at common attacks.

    Common attacks

    In order for you to secure your code, you need to understand how attacks work.

    A good starting point is to read through the list of the Top 10 attacks in 2013, published by the Open Web Application Security Project (OWASP).

    Google Application security also has a very good introduction to Cross-Site scription (XSS) attacks. You actually can test out these attacks in the browser.

    If you are interested in specific attacks for WordPress, I recommend reading the Sucuri Blog.


    This part should have provided you with a good overview of what security is, the related terminology, and the type of attacks encountered.

    In the next part, we’re going to look at how you can protect against some of these attacks by validating data before use.

  • Tammie 4:55 pm on May 16, 2015 Permalink |  

    Weekly meeting

    This week we have our usual meeting at 18:00 UTC. So far the topics are:

    • Keeping up with core. There are tickets we should be paying attention to, how do we do that?
    • @greenshady would like to talk about adding customizer examples to the WPTRT github repo.
    • @chipbennett would like to talk about licenses.

    If there is anything else you’d like to talk about please note it here.

    • Chip Bennett 12:43 am on May 17, 2015 Permalink | Log in to Reply

      Actually, I want to talk about both Favicons, and CC 4.0 license compatibility with GPL.

      • Samuel Wood (Otto) 11:34 pm on May 18, 2015 Permalink | Log in to Reply

        I know all the details on CC 4.0. Ping me when the topic comes up, and i’ll come around to explain it

        • Chip Bennett 11:49 pm on May 18, 2015 Permalink | Log in to Reply

          I’ll ping you when the meeting starts, assuming I’m able to make it. The TL;DR version of what I want to propose is that CC-By 4.0, as listed as GPL-compatible for non-code artistic works by GNU, should be acceptable for directory-hosted Themes in that specific context:

          In general, I think we should adhere to our current policy of accepting what GNU accepts. Since GNU now accepts CC-By 4.0 as GPL-compatible for “art and entertainment works, and educational works”, then we should do likewise, for “art and entertainment works, and educational works” bundled with Themes. The main impact would be for image files, I think.

    • Justin Tadlock 7:54 pm on May 18, 2015 Permalink | Log in to Reply

      I might not be able to make the meeting tomorrow because my father is coming down to my place. It really just depends on what time he gets here. I’ll leave some notes about what I wanted to discuss with the customizer examples here in the comments if I can’t make it.

      • Justin Tadlock 3:48 pm on May 19, 2015 Permalink | Log in to Reply

        If I’m not able to make it today, the idea that I was thinking about is creating a GitHub repo for the WPTRT account that shares customizer examples.

        • Show how to utilize all of the “out of the box” customizer controls.
        • Show how to do more advanced controls, settings, etc.
        • Show how to manipulate controls with JS.
  • Tammie 8:59 pm on May 13, 2015 Permalink |  

    This week’s meeting

    We had a meeting this week at 18:00 UTC in #themereview. Here are the archives: https://wordpress.slack.com/archives/themereview/p1431453803000795

    We talked about a range of things. There was no set agenda but these things came up:

    • How hard it is to say what custom content should be in a theme and what a plugin.
    • The Rest API came up. As with all new things there is a lot of excitement – which is great. Right now, it’s about experimenting. There is no right or wrong way. There is no theme to use or not use. If you are interested and want to start experimenting, check out http://themeshaper.com/2015/05/07/theming-with-the-rest-api-meet-picard/. For now, it’s all about having fun with the format. Fork themes and play!
    • There was a mention of the PR for _s of the readme.txt file by @jami0821. This is was merged today.
  • Tammie 9:41 pm on May 11, 2015 Permalink |  

    Meeting agenda for Tuesday 18:00 UTC

    We have no agenda set. So, lets do some general catch up with everyone. If you have something you want to bring up, you can mention it here or there will be time during the meeting.

    • Justin Tadlock 6:26 pm on May 12, 2015 Permalink | Log in to Reply

      I’m attempting to join the meeting. But, after a couple of months with no Slack issues, they had to start back right before the meeting today. :(

compose new post
next post/next comment
previous post/previous comment
show/hide comments
go to top
go to login
show/hide help
shift + esc