WordPress 主题手册 WordPress 主题手册,介绍主题结构、模板、样式与发布流程。 Advanced Topics Welcome to the advanced theme topics documentation. In this chapter, you will learn about some of the more complex features, techniques, and more that are not covered in previous chapters. While this chapter is considered “advanced” it doesn’t mean you cannot learn something if you’re still getting started on your theme development journey. In many ways, the articles in this chapter are essential if you plan to distribute your theme to others, such as through the WordPress Theme Directory. Navigating this chapter Use the following links to locate a topic within this chapter. Each article covers a specific topic that is relevant to theme development, and you can explore each at your own pace. Internationalization: Must-know techniques and tips to ensure your theme can be translated into any language. Child Themes: Build a custom theme that extends an existing theme (i.e., parent theme) and requires less work. Build Process: How to integrate with the @wordpress/scripts package to process and bundle your theme assets. Privacy: Test the built-in WordPress privacy features and ensure your theme works with them. Testing: How to run your theme through a suite of testing tools to make sure it works across a variety of environments. Debugging: How to enable debugging in WordPress to ensure your theme is error free. Security: A rundown of security best practices that your theme should be doing to defend against exploits. Publishing Themes: The steps you need to take to publish your theme on WordPress.org or distribute to others. This chapter also includes several other documents that are currently undergoing updates. These will eventually be updated or moved to more appropriate chapters: Plugin API Hooks UI Best Practices JavaScript Best Practices Core Concepts Welcome to the Core Concepts documentation. The goal of this chapter is to introduce you to the foundational concepts necessary for creating your own WordPress block themes. The focus of this chapter is to help you familiarize yourself with the basic theme structure and standard files like style.css, functions.php, and theme.json. Once you have these core concepts down, you can more comfortably dive into the later chapters in this handbook. Navigating this chapter Use the following links to locate a topic within this chapter. Each article is listed in the recommended reading order for those new to theme development. For those with existing experience creating themes, feel free to jump to the section you need: Theme Structure: Walks through how a theme’s files and folders are structured following WordPress standards. Main Stylesheet: Explains the importance of the theme’s style.css file and how to use it. Custom Functionality: Dives into the theme’s functions file ( functions.php) and how you can use it to add your own functionality to a theme. Templates: Introduces how WordPress’ block templates system works and provides pathways for deeper learning. Including Assets: A guide on including CSS, JavaScript, images, and more in your themes. Global Settings and Styles: Gives a basic overview of how the theme.json file works in themes with learning pathways to more detailed articles. Credits @ancawonka @Anthonynotes @atachibana @austingunter @bandonrandon @utz119 @BFTrick @BigActual @bkozma @boborchard @Brainfestation @celloexpressions @charliehanger @claymonk @code_poet @colorful-tones @crondeau @davidjlaietta @daisyo @digisavvy @DrewAPicture @enricchi @esmi @fabianapsimoes @fiveo @grapplerulrich @greenshady @hanni @hlashbrooke @hardeepasrani @iandstewart @jackreichert @jacobmc @JasonM4563 @jazzs3quence @jboydston @jcastaneda @jcrglobalcaplaw @JenniferBourn @jerrysarcastic @jgclarke @jhoffm34 @jim-spencer @jimdoran @juhise @juliekuehl @kadamwhite @kafleg @karmatosed @kenshino @kenyasullivan @kpdesign @lettergrade @linux-garage @lizkaraffa @lorax @mariawoothemescom @markel @martydia @missybunnie @mt_Suzette @nao @NikV @Otto42 @ozzyr @philiparthurmoore @poena @PriscillaBiju @rachelbaker @Raporteur @rahulsprajapati @rclations @rhauptman @RussE @ryanr14 @SagarGurnani @samuelsidler @sarahovenall @semblance_er @sewmyheadon @SeReedMedia @sheebaabraham @siobhan @stubbs123 @suastex @sushil-adhikari @Techdoode @thepixelista @topher1kenobe @TJNowell @xfrontend @viniciuslourenco @vrm Features Welcome to the Features documentation. In this chapter, you will learn about various features supported by the WordPress block theming system. This chapter does not have a singular focus. Instead, it offers information on several different topics that will help you work with more advanced features, stepping beyond the basics that you learned in Global Settings and Styles and Templates. Navigating this chapter Use the following links to locate a topic within this chapter. Each article covers a specific feature related to building block themes, and you can explore each at your own pace. Block Style Variations: Build custom block style variations (aka: block styles) for your users to select. Block Stylesheets: Register per-block stylesheets to compartmentalize your custom CSS and make your theme load faster. Block Variations: Register variations on the default settings for a block and let your users add them via the interface. Getting Started Welcome to the Getting Started documentation. This chapter is primarily intended to introduce you to navigating the handbook itself, learning what WordPress themes are, and helping you get your first WordPress block theme up and running. While this chapter primarily focuses on readers who are new to theme development altogether, it is also meant as a resource for seasoned themers who are learning how to build block themes for the first time. Navigating this chapter Use the following links to locate a topic within this chapter. Each article will walk you through the steps of navigating this handbook and getting a base understanding of how WordPress themes work: What Is a Theme?: An introduction to what WordPress themes are and an explanation of the various types of themes. Who Is This Handbook For?: Explains who this handbook is for and why you might want to read it. Reading This Handbook: Offers learning pathways for navigating the handbook based on skill level and provides an introduction on reading code samples. Tools and Setup: Gives an overview of all the tools that are required to create WordPress themes and offers recommendations on other useful apps and programs to consider. Quick-Start Guide: A step-by-step guide for getting your first basic theme up and running for those new to block theme development. Global Settings and Styles (theme.json) Welcome to the Global Settings and Styles documentation. In this chapter you will learn everything you need to know about configuring settings, styles, and more via your theme’s theme.json file. theme.json is a foundational piece of block theming. While it is not a strictly required file, you will need to work with it for nearly any theme project. It is useful for everything from configuring colors to defining default typography settings to applying front-end styles to your theme. Navigating this chapter Use the below links to find the topic you are looking for in this chapter. Each section of the chapter is set up to offer a straightforward learning path toward learning the ins-and-outs of theme.json for first-time themers. But if you are already familiar with the foundational concepts, feel free to skip ahead to the topic you want to learn more about. Introduction to theme.json: A walkthrough of setting up your theme.json file, introducing you to the foundational concepts for configuring global settings and styles for your theme. Settings: Documentation for each of the standard and custom settings that you can configure via theme.json. Sub-pages document every available setting. Styles: Learn how to use the standard design system to apply styles through theme.json, which also integrate with the user interface. Custom Templates: How to register custom post, page, and CPT (custom post type) templates for your theme. Template Parts: How to register custom template parts that can be reused across your theme. Patterns: How to bundle patterns from the official patterns repository with your theme. Style Variations: Documentation on creating custom theme.json style variations, giving your users alternative designs to choose from. Theme Handbook Welcome to the WordPress Theme Developer Handbook, your resource for learning all about the exciting world of WordPress themes. The Theme Developer Handbook is a repository for all things WordPress themes. Whether you’re new to WordPress themes, or you’re an experienced theme developer, you should be able to find the answer to many of your theme-related questions right here. In this handbook, you can learn how to build block themes or classic themes. A block theme is a new theme that you can use from WordPress version 5.9. It is built mainly using HTML and a theme configuration file. The block theme is composed entirely of blocks, allowing you to edit all parts of your site in the Site Editor. A classic theme is the original theme, without version limitations, that primarily uses PHP, JavaScript and CSS. Classic themes take advantage of WordPress PHP functions, hooks and filters. If you’re new to developing WordPress themes, start with section 1, where you can find out what a theme is, learn about WordPress’ license, and set up your development environment. Once you’re through the introduction, continue with the Core Concepts section. It is recommended to read through both the block theme section and the classic theme sections. This will give you an understanding of the differences between the two types of themes, and help you choose what type of theme to build. If you’ve got to grips with the basics of themes, check out the Advanced Theme Topics to learn about child themes, best UI practices, theme testing and more. Once you’ve got your theme ready for the world, the final section will cover releasing your theme, teaching you some best practices for theme distribution, and for getting it ready for the WordPress.org theme directory. The WordPress Theme Developer Handbook is created by the WordPress community, for the WordPress community. We are always looking for more contributors; if you’re interested stop by the docs team blog to find out more about getting involved. Patterns Patterns are one of the most useful tools for theme development, allowing you to reuse groups of blocks across a wide variety of scenarios. Over time, you will likely use patterns more than any other theme feature available in WordPress. In this chapter, you will learn what patterns are and dive into the various use cases where you will apply them in your themes. This will include everything from providing insertable layouts to your theme users to running PHP for loading assets and even more. Navigating this chapter Use the following links to locate a specific topic within this chapter. It’s best to read them in order, but if you are already familiar with the basic tenets of pattern development, feel free to jump to the topic that you’re looking for. Introduction to Patterns: Provides an overview of what patterns are and how they work, giving you a foundation for later articles in the chapter. Registering Patterns: A guide on registering/unregistering patterns and pattern categories for your theme. Using PHP in Patterns: How and why to use PHP in your themes, including practical applications like internationalizing text and including media. Usage in Templates: How to include patterns in templates and why you should use them over templates in many cases. Block Type Patterns: A walkthrough of creating block-specific patterns that offer a more elegant experience for your theme users. Starter Patterns: Building custom patterns as starting points for creating starting points for your theme users to build their pages and templates. Patterns and Block Locking: How to use the Block Locking API to curate the editing experience for your theme users. Releasing Your Theme This section covers the requirements and submission process for releasing your theme into the WordPress Theme Directory. If you’ve followed the instructions in this handbook, your theme is almost ready for release into the directory. The first requirement to releasing your theme is to make sure you have – at a minimum – the required theme files before submitting your theme for review. Once you’ve confirmed the required theme files, thorough testing of the theme – including content – must be completed. Following the theme review guidelines will help ensure acceptance of your theme. After completing everything above, having the proper documentation is the final step before submitting your theme for approval. After submitting your theme for review, the theme reviewer may request other changes to your theme. Important Notices Themes that have 3 or more distinct issues may be closed as not-approved. Theme authors are encouraged to review the Theme Review Guidelines. “How to do a review (Draft)” is another practical guide to understand the review process in-depth. First Two Checks 1. Commonly missed requirements Here are some of the commonly missed requirements at the initial review. Themes with incomplete requirements may be closed as not-approved. Themes must be compatible with the GNU General Public License. GPLv2 or later is strongly recommended. Themes are not allowed to include plugins and non-design related functionalities such as forms. Anything that will be deleted when user switches a theme should not be included. Shortcodes, custom post types, and custom blocks are not allowed in themes. 2. Testing your theme with Theme Check Plugin Theme Check plugin is an easy way to test your theme and ensure it’s up to spec with the latest theme review standards. Learn more about Theme Check Plugin. Templates Welcome to the Templates documentation. In this chapter you will learn how the WordPress block template system works, how to build custom templates and parts, and include them in your theme. Templates are one of the core concepts of building websites, representing the underlying structure that presents your content in the browser. In many ways, they are the most important feature of developing WordPress themes. Navigating this chapter Use the below links to find the topic you are looking for in this chapter. Each section of the chapter is set up to offer a straightforward learning path toward learning how to build templates for those building their first theme. But if you are already familiar with the foundational concepts, feel free to skip ahead to the topic you want to learn more about. Introduction to Templates: An overview of what templating is, how the templating system in WordPress works, and a look at the relationship between the template hierarchy, templates, and template parts. Templates: How to build custom templates and include them in your WordPress theme. Template Hierarchy: How WordPress decides which template to use based on the page the user is viewing. Template Parts: How to build template parts and insert them into top-level templates. Build Process A build process is a method of converting source code files into a final build/production version that can be read by the computer. In particular, themes will most often be minifying or converting source code into CSS or JavaScript so that they can be read by the browser. When creating a WordPress theme, you may find yourself in need of a build process to handle more complex projects. There are many systems to choose from, and you can use whatever you prefer. But WordPress also offers a standard package that you can be assured is continually updated and should cover most of your needs. In this article, you will learn how to integrate with the @wordpress/scripts package to handle your theme’s build process. Prerequisites Most of WordPress theme development is pretty much plug and play. You just need a code editor and an install of WordPress in some type of development environment as outlined in Tools and Setup. But to work with a build process, there are some other requirements: You need to have Node.js and npm installed on your local machine. A basic understanding of webpack is also highly recommended. Some familiarity with the @wordpress/scripts package (read Getting started with wp-scripts in the Block Editor Handbook). These are more advanced tools than what is normally required to build themes, but they are necessary if you want to work with the standard WordPress build process. Setting up your files and folders The @wordpress/scripts package was originally created for block development, but it evolved to also work with themes over time. By default, it expects that development files live in the /src folder and will output build files in the /build folder. Because most theme authors utilize a custom system for working with assets, this guide will show you how to do that. For the examples that follow, you will use this structure within your theme folder: public/ resources/ js/ editor.js scss/ editor.scss screen.scss package.json webpack.config.js Installing the WordPress scripts package Once you have your files and folders set up, you need to install the correct packages on your local machine. First, open your theme’s package.json file and add the following code: { "name": "your-project-name", "scripts": { "start": "wp-scripts start --webpack-src-dir=resources --output-path=public", "build": "wp-scripts build --webpack-src-dir=resources --output-path=public" } } The @wordpress/scripts package has several other available scripts that you can add, but you will definitely need start and build. Now open your command line tool on your computer, navigate to your theme folder, and input the following command: npm install @wordpress/scripts path webpack-remove-empty-scripts --save-dev That command installs three packages: @wordpress/scripts path webpack-remove-empty-scripts The latter two are third-party packages, but they are useful for integrating with webpack in the next step. Configuring webpack The @wordpress/scripts package is built on top of webpack. If you were building a block, everything would already be in place for you. However, because you are building a theme, you need to overwrite some of the default configuration of the @wordpress/scripts package with your own. That’s where your theme’s custom webpack.config.js file comes in. There two primary things you need to configure: The entry points for your custom CSS and JavaScript files (those in the code below correspond to the file structure in this article). The webpack-remove-empty-scripts plugin so that there are no leftover .js files mapped to your CSS. Add the following code to your webpack.config.js file: // WordPress webpack config. const defaultConfig = require( '@wordpress/scripts/config/webpack.config' ); // Plugins. const RemoveEmptyScriptsPlugin = require( 'webpack-remove-empty-scripts' ); // Utilities. const path = require( 'path' ); // Add any new entry points by extending the webpack config. module.exports = { ...defaultConfig, ...{ entry: { 'js/editor': path.resolve( process.cwd(), 'resources/js', 'editor.js' ), 'css/screen': path.resolve( process.cwd(), 'resources/scss', 'screen.scss' ), 'css/editor': path.resolve( process.cwd(), 'resources/scss', 'editor.scss' ), }, plugins: [ // Include WP's plugin config. ...defaultConfig.plugins, // Removes the empty `.js` files generated by webpack but // sets it after WP has generated its `*.asset.php` file. new RemoveEmptyScriptsPlugin( { stage: RemoveEmptyScriptsPlugin.STAGE_AFTER_PROCESS_PLUGINS } ) ] } }; Using the WordPress scripts package To use the WordPress scripts package to process your assets, you can run one of two commands in your command line tool: start: Builds the development version of your files and activates “watch” mode, which will process any code changes while enabled. build: Builds the production version of your files. Now open your command line tool and run the start command: npm run start It should automatically process your files from the /resources folder and place them in the /public folder with this structure: public/ js/ editor.js editor.asset.php scss/ editor.scss editor.asset.php screen.scss screen.asset.php You’ll now see new *.asset.php files generated for each of your CSS and JavaScript files. These will contain metadata about each asset file that you can use when loading your files. This is covered in the “Loading scripts and styles” section below. To disable the start command, type Ctrl + C (on either Windows or Mac) of your command line tool. Once you’re ready to do a final production build of your files, run this command in your command line tool: npm run build Loading scripts and styles The methods for loading scripts and styles are already covered in depth in the Including Assets documentation in this handbook. You should already be familiar with how to do this before proceeding with the next steps. The documentation below is primarily geared towards teaching you how the *.asset.php file is generated for each asset. In each file, you will see an array that looks similar to the following snippet: array('wp-block-editor'), 'version' => '2eae4c519afeff2a8c77'); In particular, the array will have two pieces of metadata that you can use in any wp_enqueue_*() functions: dependencies: An array of dependencies that your script/style rely on. version: A version number that you can use for cache busting. Because the file returns the array, you can use PHP’s include to assign the array to a variable in your code. The following example shows getting the array for the screen.asset.php file: $asset = include get_theme_file_path( 'public/css/screen.asset.php' ); // Returns: array( 'dependencies' => array(), 'version' => '0000' ); When loading a script or style using either wp_enqueue_script() or wp_enqueue_style(), you can pass $asset['dependencies'] and $asset['version'] to the corresponding parameters in the functions. Try adding the following code to your theme’s functions.php file to load the assets that you’ve previously defined: // Load front-end assets. add_action( 'wp_enqueue_scripts', 'themeslug_assets' ); function themeslug_assets() { $asset = include get_theme_file_path( 'public/css/screen.asset.php' ); wp_enqueue_style( 'themeslug-style', get_theme_file_uri( 'public/css/screen.css' ), $asset['dependencies'], $asset['version'] ); } // Load editor stylesheets. add_action( 'after_setup_theme', 'themeslug_editor_styles' ); function themeslug_editor_styles() { add_editor_style( [ get_theme_file_uri( 'public/css/screen.css' ) ] ); } // Load editor scripts. add_action( 'enqueue_block_editor_assets', 'themeslug_editor_assets' ); function themeslug_editor_assets() { $script_asset = include get_theme_file_path( 'public/js/editor.asset.php' ); $style_asset = include get_theme_file_path( 'public/css/editor.asset.php' ); wp_enqueue_script( 'themeslug-editor', get_theme_file_uri( 'public/js/editor.js' ), $script_asset['dependencies'], $script_asset['version'], true ); wp_enqueue_style( 'themeslug-editor', get_theme_file_uri( 'public/css/editor.css' ), $style_asset['dependencies'], $style_asset['version'] ); } Debugging Debugging is the practice of finding and fixing errors in any software that you build. And it is an essential part of WordPress theme development, regardless of whether you are building a block or classic theme. WordPress provides some tools out of the box, but there are also plugins that you can use to enhance the experience. You’ll learn about some of these methods in this article, but you should also study the Debugging in WordPress documentation in the Common APIs handbook. Debugging constants When creating themes from within a development environment, you should always enable debugging to ensure that your theme is not creating notices or errors. WordPress offers several constants, which you can set in your installation’s wp-config.php file. If you open the wp-config.php file, scroll down until you locate this code: /** * For developers: WordPress debugging mode. * * Change this to true to enable the display of notices during development. * It is strongly recommended that plugin and theme developers use WP_DEBUG * in their development environments. * * For information on other constants that can be used for debugging, * visit the documentation. * * @link https://wordpress.org/documentation/article/debugging-in-wordpress/ */ define( 'WP_DEBUG', false ); This is where you will configure any debugging constants outlined in the sections below. WP_DEBUG The WP_DEBUG constant is the only one defined in a default WordPress installation’s wp-config.php file. In a standard install, it is set to false, but it is set to true if you are running a development copy of WordPress. The WP_DEBUG PHP constant is used to trigger the built-in “debug” mode on your WordPress installation. This allows you to view errors in your theme. It should be used in conjunction with all of the other debugging constants listed in the next sections. You should see this line in your wp-config.php file: define( 'WP_DEBUG', false ); To enable debugging, make sure it is set to true, as shown here: define( 'WP_DEBUG', true ); WP_DISABLE_FATAL_ERROR_HANDLER WordPress 5.2 introduced a fatal error handler to ensure that users do not get locked out of their site when a theme or plugin causes a fatal error. This is a great feature in production/live sites. But it can be problematic in development, preventing you from fully diagnosing errors. For this reason, in development, you should disable this to make sure things are broken until you can fix them. Define this constant in your wp-config.php file: define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true ); WP_DEBUG_DISPLAY WP_DEBUG_DISPLAY is used to control whether debug messages display within the HTML of your WordPress site. By default, when WP_DEBUG is enabled, debugging messages will be shown on the screen. So, you can safely not define WP_DEBUG_DISPLAY during development. If you want to disable on-screen debugging messages, you can set WP_DEBUG_DISPLAY to false in your  wp-config.php file: define( 'WP_DEBUG_DISPLAY', false ); WP_DEBUG_LOG The WP_DEBUG_LOG constant is an optional feature that you can set to log errors to a debug.log file in your site’s /wp-content directory. By default, this is disabled. Generally, if you turn off on-screen debugging messages via WP_DEBUG_DISPLAY, then you will want to opt for storing these messages in the debug log. To enable logging, define the WP_DEBUG_LOG constant as true in your wp-config.php file: define( 'WP_DEBUG_LOG', true ); Plugins There are several plugins that are helpful when debugging your theme. Each is hosted in the WordPress Plugin Directory: Debug Bar: Provides a central location for debugging in your WordPress toolbar. Query Monitor: Enables debugging of database queries, PHP errors, hooks and actions, block editor blocks, enqueued scripts and stylesheets, HTTP API calls, and more. Log Deprecated Notices: Logs incorrect and deprecated function and file usages in your theme. Internationalization Internationalization is the process of developing your theme in such a way that its custom text can be translated into other languages. The term is often abbreviated as “i18n” because there are 18 letters between the “i” and “n,” the first and last letters. In this article, you will learn how to internationalize your WordPress themes and why it is important. Why internationalization is important WordPress is used all over the world, in countries where your native language is not used. The strings in the WordPress themes need to be coded in a special way so that they can be easily translated into other languages. Even if you yourself do not know multiple languages, internationalization leaves the door open for translators to localize the text. Localization is the process of taking internationalized text and translating it for a specific language and locale. It is often abbreviated as “l10n.” WordPress has a built-in translation system that allows localizing a theme without having to modify the source code of the theme itself. This is important because it means that users can keep up with theme updates while using their preferred translation. You can certainly build a WordPress theme without internationalization, particularly if it’s for a site that you know will never be translated. But in most cases, it is considered standard practice to internationalize all of your theme’s text. For one, it means that it can be used by people in other languages, giving you a wider audience. And it is also a requirement when submitting a theme to the official Theme Directory. How to internationalize your theme Getting your text domain The text domain is a unique identifier, allowing WordPress to distinguish between all of the loaded translations. That means that you need something unique for your theme so that WordPress will recognize translations that belong to it. The text domain is used in three different places in your theme: In the style.css file header. As an argument in internationalization functions. As an argument when loading translations (optional for themes submitted to the WordPress Theme Directory). Your theme’s text domain should always match your theme slug, as described in the Reading this handbook documentation. This is a central component in making sure your theme is ready for translation. The de facto standard (and requirement if submitting your theme to the WordPress Theme Directory) is to use the kebab-case version of your theme name. This means that it should: Use all lowercase letters. Have no spaces. Hyphenate when there are multiple words. So if your theme’s name is Fabled Sunset, your text domain should be fabled-sunset. Defining your text domain As described in the Main Stylesheet documentation, you can configure several important pieces of metadata about your theme via the style.css file header. In particular, there are two meta values you can define related to internationalization: Text Domain: The string used for the text domain for translations. Domain Path: A relative path to where theme translations are stored. WordPress uses this field when the theme is disabled to detect translations. Defaults to /languages if not defined. For translations to work correctly, you must at least define the Text Domain field, which should be your theme’s slug. Let’s imagine your theme name is “Fabled Sunset” and you want translations stored in your theme’s /assets/lang folder. Your theme’s style.css should define these fields like so: /** * Theme Name: Fabled Sunset * ... * Text Domain: fabled-sunset * Domain Path: /assets/lang * ... */ It’s important to add this metadata to your style.css file because WordPress uses it even when the theme is not enabled (for example, when viewing all themes from the Appearance > Themes screen in the admin). Wrapping text with internationalization functions For text in your theme to be easily translated in your theme, it must be wrapped in an internationalization function instead of hardcoded. The available internationalization functions are listed in the Common APIs handbook. In a typical HTML-based webpage, you would add plain text strings. For example, take a look at this example heading:

Latest Posts

Because it is merely plain text, it cannot be translated into other languages without directly modifying the code. Let’s wrap that text in the _e() internationalization function, which tells WordPress that the text inside should be available for translation and echoed (printed to the screen):

Now users can add translations for your theme without touching the code. As you may have noticed, the _e() function accepted a second parameter of themeslug. This should be replaced with your text domain. There are many other internationalization functions that you will use, and you will learn about them later. For now, the idea is to introduce you to the basic concept. Because internationalized text is technically a PHP variable, it means that it can be exploited and become a security vulnerability. You should always use the translate-and-escape functions when possible. Otherwise, be sure to wrap them in an escaping function when outputting, as described in the Security documentation. Loading translations For themes hosted in the WordPress Theme Directory, you do not need to load translations. WordPress automatically checks the wp-content/languages directory in a user’s install and will download translations from the Translating WordPress site. All translations can be handled there, and you don’t have to worry about storing or loading them from your theme. Translation in WordPress are saved in .po (human readable) and .mo (machine readable) files. The .mo files are the ones actually used by WordPress. WordPress will look in two places for translation files based on the user’s locale defined for the site: wp-content/themes/your-theme/{domain-path}/{locale}.mo wp-content/languages/themes/{textdomain}-{locale}.mo To load translation files from your theme, you must use one of two functions: load_theme_textdomain() load_child_theme_textdomain() (if building a child theme) Let’s take a look at the load_theme_textdomain() function signature (it’s the same for both functions): load_theme_textdomain( string $domain, string|false $path = false ): bool The function accepts two parameters: $domain: This should be the text domain for your theme as defined in style.css. $path: This must be a full directory path to the location of translations in your theme. If left undefined, WordPress will fall back to your theme’s root folder. Using the same example “Fabled Sunset” theme described earlier with translations stored in the /assets/lang folder, let’s try loading translations from the theme. Add this code to your theme’s functions.php file: add_action( 'after_setup_theme', 'themeslug_load_textdomain' ); function themeslug_load_textdomain() { load_theme_textdomain( 'fabled-sunset', get_parent_theme_file_path( 'assets/lang' ) ); } The above call to load_theme_textdomain() was executed on the after_setup_theme action hook, which fires immediately after the theme’s functions.php is loaded. If you were building a child theme, your functions.php code would instead look like this: add_action( 'after_setup_theme', 'themeslug_load_textdomain' ); function themeslug_load_textdomain() { load_child_theme_textdomain( 'fabled-sunset', get_theme_file_path( 'assets/lang' ) ); } Resources Internationalization is a large topic and is covered in full in the Internationalization chapter of the Common APIs handbook. What you learn there will apply to both theme and plugin development. WordPress has many internationalization functions for you to use when wrapping text. Which one to use will be context-specific. Take the time to study each function so that you will know when to use it. The Internationalization Guidelines will set you down the correct path. JavaScript Best Practices Many themes use JavaScript to provide interactivity, animation or other enhancements. These best practices will help ensure your code works efficiently and does not cause conflicts with your content or plugins. Use Included Libraries There are many useful JavaScript libraries you may want to include when building your theme. Did you know that WordPress comes bundled with dozens of popular libraries? Check out this list of default scripts included with WordPress. A common mistake made by beginning theme and plugin developers is to bundle their theme or plugin with their own version of the library. This may conflict with other plugins that enqueue the version bundled with WordPress. As a best practice, make your theme compatible with the version of your favorite library included with WordPress. Do not try to use your own version of a JavaScript library that is already bundled with WordPress. Doing so may break core functionality and conflict with plugins. If you feel you MUST replace the WordPress version with one of your own… well… the answer is still: don’t do it.  The versions of JavaScript libraries used by WordPress may include custom tweaks that WordPress needs to operate.  Any time you override these libraries, you risk breaking your WordPress instance. Moreover, plugins created by other authors should be written to be compatible with WordPress’s version of these libraries as well. Adding your own version may (and often does!) conflict with plugins. Standard JavaScript Javascript is growing in popularity for web developers, and it’s being used to accomplish for a variety of tasks. Here are some best practices to use when writing your JavaScript Avoid Global Variables Keep your JavaScript unobtrusive Use closures and the module pattern Stick to a coding style. Use The WordPress Javascript Coding Standard. Validate and Lint Your Code – ESLint.com Ensure your site still works without JavaScript first – then add JavaScript to provide additional capabilities. This is a form of Progressive Enhancement. Lazy load assets that aren’t immediately required. Don’t use jQuery if you don’t need to — There’s a great site that shows you how to do some common tasks with plain old JavaScript – you might not need jQuery jQuery Including jQuery in your theme jQuery is a popular JavaScript library to make working with JavaScript easier and more reliable across browsers. If you use jQuery, be sure to follow the handbook guidelines on including JavaScript. Giving your theme’s enqueued .js files a dependency array of array( 'jquery' ) ensures that the jQuery script has been downloaded and loaded before your theme’s code. Using $ Because the copy of jQuery included in WordPress loads in noConflict() mode, use this wrapper code in your theme’s .js files to map “$” to “jQuery”: ( function( $ ) { // Your code goes here } )( jQuery ); This wrapper (called an Immediately Invoked Function Expression, or IIFE) lets you pass in a variable—jQuery—on the bottom line, and give it the name “$” internally. Within this wrapper you may use $ to select elements as normal. Selectors Every time you select an element with jQuery, it performs a query through your document’s markup. These queries are very fast, but they do take time—you can make your site respond faster by re-using your jQuery objects instead of using a new query. So instead of repeating selectors: // Anti-pattern $('.post img').addClass('theme-image'); $('.post img').on('click', function() { ... }); it is recommended to cache your selectors so you can re-use the returned element without having to repeat the lookup process: var $postImage = $('.post img'); // All image tags within posts can now be accessed through $postImage $postImage.addClass('theme-image'); $postImage.on('click', function() { ... }); Event Handling When you use jQuery methods like .bind or .click, jQuery creates a new browser event object to handle processing the requested event. Each new event created takes a small amount of memory, but the amount of memory required goes up the more events you bind. If you have a page with a hundred anchor tags and wanted to fire a logClick event handler whenever a user clicked a link, it is very easy to write code like this: // Anti-pattern $('a').click( logClick ); This works, but under the hood you have asked jQuery to create a new event handler for every link on your page. Event delegation is a way to accomplish the same effect with less overhead. Because events in jQuery “bubble”—that is, a click event will fire on a link, then on the link’s surrounding

tag, then on the div container, and so on up to the document object itself—we can put a single event handler higher up in the page structure, and still catch the click events for all of those links: // Bind one handler at the document level, which is triggered // whenever there is a "click" event originating from an "a" tag $(document).on('click', 'a', logClick); Plugin API Hooks A theme should work well with WordPress plugins. Plugins add functionality by using actions and filters, which are collectively called hooks (see Plugin API for more information). Most hooks are executed internally by WordPress, so your theme does not need special tags for them to work. However, a few hooks need to be included in your theme templates. These hooks are fired by special Template Tags: wp_head() : Goes at the end of the  element of a theme’s header.php template file. wp_body_open() : Goes at the begining of the  element of a theme’s header.php template file. wp_footer() : Goes in footer.php, just before the closing  tag. wp_meta() : Typically goes in the Meta section of a Theme’s menu or sidebar. comment_form() : Goes in comments.php directly before the file’s closing tag (). Take a look at a core theme’s templates for examples of how these hooks are used. Privacy WordPress 4.9.6 introduced several tools to help sites meet the requirements of the European Union’s new GDPR (General Data Protection Regulation) and other potential laws across the world. This article details what theme authors need to know about compatibility with the features. For the most part, this should not directly impact themes, but you should make sure that nothing in your theme’s design or functionality conflicts with these features. Privacy Policy page WordPress lets users select a privacy policy page via the Settings > Privacy screen in the admin. For newly-created WordPress installs (since version 4.9.6), a privacy policy page is automatically created with a draft status. Linking to the Privacy Policy page If you need to manually link to the Privacy Policy page on a site, WordPress provides a few functions for getting or outputting the URL or link: get_privacy_policy_url(): Retrieves the URL to the Privacy Policy page. the_privacy_policy_link(): Displays the Privacy Policy page link with formatting, when applicable. get_the_privacy_policy_link(): Returns the Privacy Policy page link with formatting, when applicable. The following example will display the privacy policy link surrounded by a

element: ', '
' ); ?> Privacy Policy page template While it is generally unnecessary for most themes, you can add a custom Privacy Policy template to customize the output of the page. This is an optional template: Block Themes: templates/privacy-policy.html Classic Themes: privacy-policy.php If you decide to create a custom template, make sure that you output the page’s content using the appropriate block or function: Block Themes: Post Content block Classic Themes: the_content() function This ensures that the user’s Privacy Policy content will be correctly displayed on the front end of the site. Comment cookies When a logged out user comments on a post, they are asked for their name, email, and website. This information is stored locally in the commenter’s browser for two purposes: When they leave another comment on the site, their name, email, and website will be pre-populated into the respective fields. If their comment is held for moderation, they can return to that post and remove the comment before it is approved. The information stored in this cookie is for convenience and is not essential. Therefore, the user needs to be given the choice to opt in or opt out of the storage of this data. For this reason, WordPress outputs a checkbox in the comment form that allows commenters to opt-in to storing this data in the cookie. This checkbox will be unchecked by default, as opt-in is an action the user must explicitly approve. The new checkbox field is automatically added to comment forms displayed using the Comment Form block (block themes) or the comment_form() function (classic themes). While most themes will not require any action, it is recommended that you double check that the input and label does not require CSS adjustments in custom themes. Testing Whether you are planning to share your WordPress theme with a broad audience or aiming for a specific platform, this article will help you get your theme ready for release. It focuses on general theme testing to ensure your theme’s quality and compatibility across various environments. Expanding on the principles from previous sections, this article covers things like code quality, compatibility, and responsiveness. By the end, your theme will be ready to use on a live site. Testing environment When building your theme, it is good practice to test from within some type of development environment. In this section, you will get an overview of a couple of methods that you can explore further on your own. Local environment A local development environment provides a controlled space for developing and testing your theme without impacting your live site. Some of the available options are listed in the Tools and Setup documentation. When developing locally, you should always have debugging enabled. Check out the Debugging documentation for information on debugging techniques and tools that will help you handle errors and optimize your theme development process. WordPress Playground WordPress Playground is another option for testing. It operates entirely in the browser, providing a controlled space for testing. Here is a look at the default Twenty Twenty-Four theme running in Playground: To become more familiar with using this platform, please refer to the official WordPress Playground documentation. Theme Unit Test Data When developing a WordPress theme, ensuring that it can handle a variety of content is fundamental. To assist in this process, WordPress provides a set of Theme Unit Test Data via an importable XML file. To be clear, this is just one part of a larger theme testing process. The test data is a collection of posts, pages, comments, and media that you can import into your WordPress installation. By testing with this data, you can check how your theme handles edge cases, such as extremely long titles, images of varying sizes, nested comments, and a mix of HTML elements. To test your theme with the Theme Unit Test Data, you need to: Download the data: Get the latest version from the GitHub repository. Import the data: Use the WordPress Importer tool to import the data into your WordPress environment. Once you’ve imported the content into your test install, examine how each piece of content is displayed. Pay special attention to areas where your theme might be prone to issues. Also be sure to view your theme on various devices and screen sizes to make sure the content is displayed as expected. Tools and resources When testing your theme, it is important to use tools that will check every aspect of your theme for potential issues. The Theme Check Plugin evaluates your theme against the Theme Review Guidelines before submitting to the official directory. Even if not submitting to the directory, it can also be useful for making sure your theme meets some baseline standards. Some other WordPress plugins you should include in your testing suite are: Debug Bar: Adds an admin bar to your WordPress admin and provides a central location for debugging. Query Monitor: Allows debugging of database queries, API requests, and AJAX used to generate theme pages and functionality. Log Deprecated Notices: Logs incorrect function usage, deprecated file usage, and deprecated function usage in your theme. Monster Widget: Consolidates the core WordPress widgets into a single widget, making it easier to test them all at once (classic themes only). For effective cross-browser compatibility testing of block themes, it is important to use the developer tools available with modern browsers, such as: Firefox: Developer Edition Chrome DevTools Functional testing Testing your theme’s compatibility with basic WordPress features is necessary. This step ensures that your theme not only looks good but also works with WordPress’s core functionality. Testing basic WordPress features It is important that your theme works with core features and behaves as expected. The following are some of the basic features to test: Posts and pages: Create a variety of posts and pages using the block editor. Experiment with different types of content, including text, images, and videos. Pay attention to how all standard blocks (paragraphs, images, headings, lists, etc.) are displayed. Are they aligning correctly? Is the spacing consistent? Block settings: Test the settings of each block to ensure they function as intended. For instance, when you change the alignment of an image or the color of a heading, does the theme reflect these changes accurately? Responsiveness: Check how these elements adapt to different screen sizes. Ensure the layout remains intuitive and user-friendly on mobile devices. Comments: Look at the comments section of your posts. Are comments and replies displaying correctly? Ensure that threaded comments are displayed in a nested format, making it easy to follow conversations. Test the comment block in the block editor. Does it integrate well with your theme? Are there styling or functionality issues? If you’re building a block theme, as this handbook recommends, you should also test these features: Site Editor: Test the Site Editor and make sure that you can edit templates and template parts like headers and footers. Styles interface: Check the functionality of the Styles interface, where you can customize colors, typography, and layout settings that apply across your theme. Navigation block: Pay special attention to the Navigation block. Test its responsiveness, the ease of adding menu items, sub-menu functionality, and alignment options. Template editing: Explore the Template Editor for creating and modifying templates for specific posts or pages. Accessibility testing Ensuring accessibility is a key aspect of responsible theme development. You should strive to make sure your theme meets the WordPress Accessibility Guidelines. This includes aspects like keyboard navigation, screen reader compatibility, and proper use of ARIA roles. Tools like aXe and WAVE are invaluable in identifying potential accessibility issues. Regularly use them during development to find and fix any problems. This proactive approach helps in creating a theme that is accessible to all users, regardless of how they navigate the web. Performance testing You should also ensure that your theme is not unnecessarily loading too many resources. For this, you can use tools like PageSpeed Insights to check your theme’s performance. These types of tools provide information on how quickly your theme loads and offers suggestions for improvement. When shipping media or other assets with your theme, be sure that they are optimized. This includes but is not limited to: Images/Media: Ensure media items bundled with your theme are correctly sized, in the most appropriate format, and compressed to reduce load times. CSS and JavaScript files: Make sure to include minified assets that will be loaded by the browser. Theme Testing The Theme Unit Test data is a WordPress import file will fill a WordPress site with enough stub data (posts, media, users) to test a theme. The Theme Unit Tests are manual tests to walk through to test theme functionality and how the theme responds to the edge-cases of content and settings. Theme Unit Test Overview Fix PHP and WordPress errors. Add the following debug setting to your  wp-config.php file to see deprecated function calls and other WordPress-related errors:  define('WP_DEBUG', true); See Deprecated Functions Hook for more information. Check template files against Template File Checklist (see above). Do a run-through using the Theme Unit Test. Validate HTML and CSS. See Validating a Website. Check for JavaScript errors. Test in all your target browsers. For example Safari, Chrome, Opera, Firefox and Microsoft Edge. Clean up any extraneous comments, debug settings or TODO items. See Theme Review if you are publicly releasing the Theme by submitting it to the Themes Directory. UI Best Practices Logo Homepage Link The logo at the top each page should send the user to the homepage of your site. If you are using the recommended function, the_custom_logo() or the site logo block, the logo is linked to the homepage by default. You can also add your logo manually. Assuming your logo is in your theme directory, this is how to display it in the  header.php template file. <?php esc_attr_e( 'Home Page', 'textdmomain' );?> Descriptive Anchor Text The anchor text is the visible text for a hyperlink. Good link text should give the reader an idea of the action that will take place when clicking it. A bad example: The best way to learn WordPress is to start using it. To Download WordPress, click here. A better example: Download WordPress and start using it. That's the best way to learn. Style Links with Underlines By default, browsers underline links to let the user know what is clickable. Some designers use CSS to turn off underlines for hyperlinks. This causes usability and accessibility problems, as it makes it more difficult to identify hyperlinks from the surrounding text. Different Link Colors Color is another visual cue that text is clickable. Styling hyperlinks with a different color than the surrounding text makes them easier to distinguish. Hyperlinks are one of the few HTML features that have state. The two most important states are visited and unvisited. Having different colors for these two states helps users identify the pages they’ve visited before. A good trick for taking the guess work out of visited links is to color them 10%-20% darker than the unvisited links. There are 3 other states that links can have: hover, when a mouse is over an element focus, similar to hover but for keyboard users active, when a user is clicking on a link Since hover and focus have similar meanings, it is useful to give them the same styles. Though hover and focus have similar meanings, they have different interaction patterns. If you choose a subtle hover state, you should have a more easily identifiable focus state. Hovering over a link is a directed activity, where the user knows where they are in the page and only needs to identify whether that spot is linked. Focus is an undirected activity, where the user needs to discover where their focus has moved to after shifting focus from the previous location. Color Contrast Color contrast refers to the difference between two colors. Contrast is low between navy blue and black. Contrast is high between white and black. WebAIM, a non-profit web accessibility organization, provides a color contrast calculator to help you determine the contrast in your website design. The WCAG 2.0 requires a ratio of 4.5:1 on normal text to be AA compliant. Sufficient Font Size Make your text easy to read. By making your text large enough, you increase the usability of your site and make the content easier to understand. 14px is the smallest text should be. Associate Labels with Inputs Labels inform the user what an input field is for. You can connect the label to the input by using the for attribute in the label. This will allow the user to click the label and focus on the input field. Labels work for radio buttons as well. Since it works using the id field and not the name, each input for the group gets its own label. Placeholder Text in Forms Placeholder text shows the user an example of what to type. When a user puts their cursor in the field, the placeholder text will disappear, while the label remains. Use placeholders to suggest the type of data a field requires, and not as a substitute for the field label. Descriptive Buttons The web is filled with buttons that have unclear meanings. Remember the last time you used ‘OK’ or ‘submit’ on your login form? Choosing better words to display on your buttons can make your website easier to use. Try the pattern [verb] [noun] — Create user, Delete File, Update Password, Send Message. Each describes what will happen when the user clicks the button. Theme Basics In this chapter, you’ll begin learning how to build a theme. The anatomy of a theme and its parts will be broken down and explained. You’ll begin by understanding the concepts of building a theme by looking at theme files and post types. Then you’ll learn how to keep your files organized within your theme. You’ll also look at The Loop, which is responsible for pulling content out of the WordPress database. Finally, you’ll learn more about adding features to your theme by using theme functions, including CSS & JavaScript, leveraging conditional tags to only show content you need, and working with default taxonomies and creating your own. Theme Options – The Customize API The Customize API (Customizer) is a framework for live-previewing any change to WordPress. It provides a unified interface for users to customize various aspects of their theme and their site, from colors and layouts to widgets, menus, and more. Themes and plugins alike can add options to the Customizer. The Customizer is the canonical way to add options to your theme. The customizer as it appears in WordPress 4.6 with the Twenty Fifteen theme. Customizer options can be granted to users with different capabilities on a granular basis, so while most options are visible only to administrators by default, other users may access certain options if you want them to be able to. Different parts of the Customizer can also be contextual to whether they’re relevant to the front-end context that the user is previewing. For example, the core widgets functionality only shows widget areas that are displayed on the current page; other widget areas are shown when the user navigates to a page that includes them within the Customizer preview window. This section contains an overview of the Customize API, including code examples and discussion of best practices. For more details, it is strongly recommended that developers study the core customizer code (all core files containing “customize”). This is considered the canonical, official documentation for the Customize API outside of the inline documentation within the core code. Theme Functionality Now that you’re familiar with the basics of theme development, it’s time to start digging deeper into the world of themes. This section covers all of the basic theme functionality that you’ll need to consider while creating your theme: Custom headers – learn how to give your users the flexibility of adding their own header image Sidebars – add widgetized areas to your theme where users can add widgets Widgets – create re-usable PHP objects that can be added to a sidebar Navigation menus – register and display menus within your theme Taxonomy Templates – create templates for your taxonomy archive pages Pagination – work with WordPress’ built-in pagination Comments – customize the comments template Media – work with WordPress core’s media capabilities Featured Images & Post Thumbnails – work with and customize post thumbnails Post Formats – create different formats for displaying users’ posts Internationalization – learn how to prepare your theme for translation into different languages Localization – learn how to translate a WordPress theme Accessibility – learn about accessibility best practices to ensure everyone can use your theme Administration Menus – add menu items to the WordPress administration 404 Pages – create a custom 404 page If you’re new to themes it’s worth working your way through each section, but you can also jump into a section if you’re looking for something specific. References This section contains lists of Template Tags and Conditional Tags. Template Tags are used in your Template Files to display information dynamically or otherwise customize your site. Conditional Tags are a boolean data type that can be used in your Template Files to alter the display of content depending on the conditions that the current page matches. Template Files We introduced template files earlier in the handbook.  This next section is going to break up the different template files through the post types that they display and provide a more in depth explanation of the purpose for these template files.  You’ll also get a handle on some practical use cases for the different template files. You’ll start with post template files that deal with displaying the Post post type.  Then you’ll look at page template files that display the Page post type and drill down into specific page templates that WordPress has built in to its functionality.  Next you’ll learn about attachment template files which display the attachment post type.  You’ll also learn about how to display custom post types that are built by a plugin in the custom post type templates.  Lastly, you’ll touch on some partial and miscellaneous template files which are important to include but don’t necessarily display post types. It’s important to understand WordPress doesn’t really break down template files down into specific types of template files such as post template files or attachment template files. Especially since many template files, such as index.php or  search.php can display many different post types. To help you reference specific template files this handbook is categorizing them based on the post types they can display. Your First Theme Block Theme This section is for a block theme. Required Files The only files needed for a block theme is, index.html, which is the main template to display your list of posts. Index.html needs to be placed inside a folder called templates. style.css file to style content. theme.json file to set style properties in a structured way. For advanced block theme development, you can add templates and template parts. For example, You can create a templates directory inside the theme folder and put your templates there. Templates examples, index.html archive.html single.html page.html You can create a parts directory inside the theme folder and put template parts. Template parts examples, header.html footer.html sidebar.html As you know the required files for block themes, now let’s create your first block theme. Step 1 – Create a theme folder First, create a new folder on your computer, and name it my-first-theme. This is where all of your theme’s files will go. Step 2 – Create a style.css file You can use any basic text editor on your computer to create a new file called style.css. If you’re on a Windows-based machine use Notepad for now and if you’re using a Mac then use TextEdit. Copy and paste the following code into your newly created style.css file: /* Theme Name: My First WordPress Theme */ Step 3 – Create a theme.json file Create the theme.json file in the root folder, and copy and paste the following code: { “version”: 2, “settings”: { “layout”: { “contentSize”: “840px”, “wideSize”: “1100px” } } } Step 4 – Add index.html inside the templates folder Inside your theme directory, create a templates folder. Inside the templates folder creates an index.html file. Now, your theme structure should look like this, templates/ index.html style.css theme.json Your block theme is now ready. You can install and activate the theme. First, make the ZIP file of your theme directory. The ZIP file will be like, my-first-theme.zip Step 5 – Install and activate your theme Now, go to your WordPress admin panel and Appearance > Themes > Add New > Upload. Upload the my-first-theme.zip and click on install and then activate. Congratulations – you’ve made your first WordPress block theme. To know more about block themes, you can download the default Twenty Twenty-Three theme and use it as a reference. Classic Theme Required Files As mentioned earlier in the “What is a Theme” section, the only files needed for a WordPress theme to work out of the box are an index.php file to display your list of posts and a style.css file to style the content. Once you get into more advanced development territory and your themes grow in size and complexity, you’ll find it easier to break your theme into many separate files (called template files) instead. For example, most WordPress themes will also include: header.php index.php sidebar.php footer.php We will cover creating separate files later in this handbook, but for now let’s get your first theme launched! (Note: The following steps assume you have already completed the “Setting up a Development Environment” section.) Step 1 – Create a theme folder First, create a new folder on your computer, and name it my-first-theme. This is where all of your theme’s files will go. Step 2 – Create a style.css file You can use any basic text editor on your computer to create a new file called style.css. If you’re on a Windows-based machine use Notepad for now and if you’re using a Mac then use TextEdit. Copy and paste the following code into your newly created style.css file: /* Theme Name: My First WordPress Theme */ body { background: #21759b; } Reference Gist Step 3 – Create an index.php file Now create a file named index.php and put it into your theme’s folder, adding the following code to it: <?php wp_title( '|', true, 'right' ); ?>

No posts found. :(

Reference Gist Step 4 – Install Your Theme Copy your new theme into the  wp-content/themes folder on your development environment and activate it for review and testing. Step 5 – Activate Your Theme Now that you’ve installed your theme, go to Admin > Appearance > Themes to activate it. Using Your First Theme Congratulations – you’ve just made your first WordPress theme! If you activate your new theme and view it within a browser, you should see something like this: Here’s how Your First Theme looks on the front end. Okay, so it’s not the prettiest theme yet, but it’s a terrific start! What have we learned? Although your first theme may be missing the functionality and design elements that are found in other themes, the basic building blocks of a WordPress theme, as we have just created above, are all the same. Remember that the key here is not to get caught up in how all those other things are done now, but to understand the guiding principles behind making WordPress themes that will stand the test of time, no matter how the code changes or the template file structure changes over time. All websites, regardless of how they are created underneath the hood, need common elements: headers, primary content areas, menus, sidebars, footers, and the like. You’ll find that making WordPress themes is really just another way of crafting a website. From this most basic theme, you’ll start learning about the building blocks that you put together to create a more complex theme. Up Next In Chapter 2: Theme Basics, we’ll dive further into themes and discuss the templates and other files that make up most themes, along with the PHP used to make dynamic themes, including: Template Tags The Loop Theme Functions Conditional Tags and more Categories, Tags, & Custom Taxonomies Categories, tags, and taxonomies are all related and can be easily confused. We’ll use the example of building a theme for a recipe website to help break down categories, tags, and taxonomies. In our recipe website, the categories would be Breakfast, Lunch, Dinner, Appetizers, Soups, Salads, Sides, and Desserts. All recipes will fit within those categories, but users might want to search for something specific like chocolate desserts or ginger chicken dinners. Chocolate, ginger, and chicken are all examples of tags.  They are another level of specificity that provides meaning to the user. Lastly, there are taxonomies. In reality, categories and tags are examples of default taxonomies which simply are a way to organize content.  Taxonomies are the method of classifying content and data in WordPress. When you use a taxonomy you’re grouping similar things together. The taxonomy refers to the sum of those groups. As with Post Types, there are a number of default taxonomies, and you can also create your own. Recipes are normally organized by category and tag, but there are some other helpful ways to break the recipes down to be more user friendly.  For example, the recipe website might want an easy way to display recipes by cook time. A custom taxonomy of cook time with 0-30 min, 30-min to an hour, 1 to 2 hours, 2+ hours would be a great breakdown.  Additionally, cook method such as grill, oven, stove, refrigerator, etc would be another example of a custom taxonomy that would be relevant for the site.  There could also be a custom taxonomy for how spicy the recipe is and then a rating from 1-5 on spiciness. Default Taxonomies The default taxonomies in WordPress are: categories: a hierarchical taxonomy that organizes content in the post Post Type tags: a non-hierarchical taxonomy that organizes content in the post Post Type post formats: a method for creating formats for your posts. You can learn more about these on the Post Formats page. Terms Terms are items within your taxonomy. So, for example, if you have the Animaltaxonomy you would have the terms, dogs, cats, and sheep. Terms can be created via the WordPress admin, or you can use the wp_insert_term() function. Database Schema Taxonomies and terms are stored in the following database tables: wp_terms – stores all of the terms wp_term_taxonomy – places the term in a taxonomy wp_term_relationships – relates the taxonomy to an object (for example, category to post) Templates WordPress offers several different hierarchies of templates for categories, tags, or custom taxonomies. More details on their structure and usage may be found on the Taxonomy Templates page. Custom Taxonomies It is possible to create new taxonomies in WordPress. You may, for example, want to create an author taxonomy on a book review website, or an actor taxonomy on a film site. As with custom post type it is recommended that you put this functionality in a plugin. This ensures that when the user changes their website’s design, their content is preserved in the plugin. You can read more about creating custom taxonomies in the Plugin Developer Handbook. Conditional Tags Conditional Tags can be used in your Template Files in classic themes to alter the display of content depending on the conditions that the current page matches. They tell WordPress what code to display under specific conditions. Conditional Tags usually work with PHP if /else Conditional Statements. The code begins by checking to see if a statement is true or false. If the statement is found to be true, the first set of code is executed. If it’s false, the first set of code is skipped, and the second set of code (after the else) is executed instead. For example, you could ask if a user is logged in, and then provide a different greeting depending on the result. if ( is_user_logged_in() ) : echo 'Welcome, registered user!'; else : echo 'Welcome, visitor!'; endif; Note the close relation these tags have to WordPress Template Hierarchy. Where to Use Conditional Tags For a Conditional Tag to modify your data, the information must already have been retrieved from your database, i.e. the query must have already run. If you use a Conditional Tag before there is data, there’ll be nothing to ask the if/else statement about. It’s important to note that WordPress loads functions.php before the query is run, so if you simply include a Conditional Tag in that file, it won’t work. Two ways to implement Conditional Tags: place it in a Template File create a function out of it in functions.php that hooks into an action/filter that triggers at a later point The Conditions For Listed below are the conditions under which each of the following conditional statements proves to be true. Tags which can accept parameters are noted. The Main Page is_home() This condition returns true when the main blog page is being displayed, usually in standard reverse chronological order. If your home page has been set to a Static Page instead, then this will only prove true on the page which you set as the “Posts page” in Settings > Reading. The Front Page is_front_page() This condition returns true when the front page of the site is displayed, regardless of whether it is set to show posts or a static page. Returns true when: the main blog page is being displayed and the Settings > Reading -> Front page displays option is set to Your latest posts OR when Settings > Reading -> Front page displays is set to A static page and the Front Page value is the current Page being displayed. The Administration Panels is_admin() This condition returns true when the Dashboard or the administration panels are being displayed. A Single Post Page is_single() Returns true when any single Post (or attachment, or custom Post Type) is being displayed. This condition returns false if you are on a page. is_single( '17' ); is_single() can also check for certain posts by ID and other parameters. The above example proves true when Post 17 is being displayed as a single Post. is_single( 'Irish Stew' ); Parameters include Post titles, as well. In this case, it proves true when the Post with title “Irish Stew” is being displayed as a single Post. is_single( 'beef-stew' ); Proves true when the Post with Post Slug “beef-stew” is being displayed as a single Post. is_single( array( 17, 'beef-stew', 'Irish Stew' ) ); Returns true when the single post being displayed is either post ID 17, or the post_name is “beef-stew”, or the post_title is “Irish Stew”. is_single( array( 17, 19, 1, 11 ) ); Returns true when the single post being displayed is either post ID = 17, post ID = 19, post ID = 1 or post ID = 11. is_single( array( 'beef-stew', 'pea-soup', 'chilli' ) ); Returns true when the single post being displayed is either the post_name “beef-stew”, post_name “pea-soup” or post_name “chilli”. is_single( array( 'Beef Stew', 'Pea Soup', 'Chilli' ) ); Returns true when the single post being displayed is either the post_title is “Beef Stew”, post_title is “Pea Soup” or post_title is “Chilli”. Note: This function does not distinguish between the post ID, post title, or post name. A post named “17” would be displayed if a post ID of 17 was requested. Presumably the same holds for a post with the slug “17”. A Single Post, Page, or Attachment is_singular() Returns true for any is_single, is_page, and is_attachment. It does allow testing for post types. A Sticky Post is_sticky() Returns true if the “Stick this post to the front page” check box has been checked for the current post. In this example, no post ID argument is given, so the post ID for the Loop post is used. is_sticky( '17' ); Returns true when Post 17 is considered a sticky post. A Post Type get_post_type() You can test to see if the current post is of a certain type by including get_post_type() in your conditional. It’s not really a conditional tag, but it returns the registered post type of the current post. if ( 'book' == get_post_type() ) { ... } post_type_exists() Returns true if a given post type is a registered post type. This does not test if a post is a certain post_type. Note: This function replaces a function called is_post_type which existed briefly in 3.0 development. A Post Type is Hierarchical is_post_type_hierarchical( $post_type ) Returns true if this $post_type has been set with hierarchical support when registered. is_post_type_hierarchical( 'book' ); Returns true if the book post type was registered as having support for hierarchical. A Post Type Archive is_post_type_archive() Returns true on any post type archive. is_post_type_archive( $post_type ); Returns true if on a post type archive page that matches $post_type (can be a single post type or an array of post types). To turn on post type archives, use ‘has_archive’ => true, when registering the post type. Any Page Containing Posts comments_open() When comments are allowed for the current Post being processed in the WordPress Loop. pings_open() When pings are allowed for the current Post being processed in the WordPress Loop. A “PAGE” Page This section refers to WordPress Pages, not any generic webpage from your blog, or in other words to the built in post_type ‘page’. is_page() When any Page is being displayed. is_page( '42' ); When Page 42 (ID) is being displayed. is_page( 'About Me And Joe' ); When the Page with a post_title of “About Me And Joe” is being displayed. is_page( 'about-me' ); When the Page with a post_name (slug) of “about-me” is being displayed. is_page( array( 42, 'about-me', 'About Me And Joe' ) ); Returns true when the Pages displayed is either post ID = 42, or post_name is “about-me”, or post_title is “About Me And Joe”. is_page( array( 42, 54, 6 ) ); Returns true when the Pages displayed is either post ID = 42, or post ID = 54, or post ID = 6. Testing for Paginated Pages You can use this code to check whether you’re on the nth page in a Post or Page that has been divided into pages using the QuickTag. This can be useful, for example, if you wish to display meta-data only on the first page of a post divided into several pages. Example 1 get( 'page' ); if ( ! $paged || $paged < 2 ) : // This is not a paginated page (or it's simply the first page of a paginated page/post) else : // This is a paginated page. endif; Example 2 post_parent ) : // This is a subpage else : // This is not a subpage endif; Snippet 1 You can create your own is_subpage() function using the code in Snippet 2. Add it to your functions.php file. It tests for a parent page in the same way as Snippet 1, but will return the ID of the page parent if there is one, or false if there isn’t. Snippet 2 post_parent ) { // return the ID of the parent post return $post->post_parent; // there is no parent so ... } else { // ... the answer to the question is false return false; } } It is advisable to use a function like that in Snippet 2, rather than using the simple test like Snippet 1, if you plan to test for sub-pages frequently. To test if the parent of a page is a specific page, for instance “About” (page id pid 2 by default), we can use the tests in Snippet 3. These tests check to see if we are looking at the page in question, as well as if we are looking at any child pages. This is useful for setting variables specific to different sections of a web site, so a different banner image, or a different heading. Snippet 3 post_parent ) { $bannerimg = 'about.jpg'; } elseif ( is_page( 'learning' ) || '56' == $post->post_parent ) { $bannerimg = 'teaching.jpg'; } elseif ( is_page( 'admissions' ) || '15' == $post->post_parent ) { $bannerimg = 'admissions.jpg'; // Just in case we are at an unclassified page, perhaps the home page } else { $bannerimg = 'home.jpg'; } Snippet 4 is a function that allows you to carry out the tests above more easily. This function will return true if we are looking at the page in question (so “About”) or one of its sub pages (so a page with a parent with ID “2”). Snippet 4 Add Snippet 4 to your functions.php file, and call is_tree( ‘id’ ) to see if the current page is the page, or is a sub page of the page. In Snippet 3, is_tree( ‘2’ ) would replace “is_page( ‘about’ ) || ‘2’ == $post->post_parent” inside the first if tag. Note that if you have more than one level of pages the parent page is the one directly above and not the one at the very top of the hierarchy. Is a Page Template Allows you to determine whether or not you are in a page template or if a specific page template is being used. is_page_template() Is a Page Template being used? is_page_template( 'about.php' ); Is Page Template ‘about’ being used? Note that unlike other conditionals, if you want to specify a particular Page Template, you need to use the filename, such as about.php or my_page_template.php. Note: if the file is in a subdirectory you must include this as well. Meaning that this should be the filepath in relation to your theme as well as the filename, for example ‘page-templates/about.php’. A Category Page is_category() When a Category archive page is being displayed. is_category( '9' ); When the archive page for Category 9 is being displayed. is_category( 'Stinky Cheeses' ); When the archive page for the Category with Name “Stinky Cheeses” is being displayed. is_category( 'blue-cheese' ); When the archive page for the Category with Category Slug “blue-cheese” is being displayed. is_category( array( 9, 'blue-cheese', 'Stinky Cheeses' ) ); Returns true when the category of posts being displayed is either term_ID 9, or slug “blue-cheese”, or name “Stinky Cheeses”. in_category( '5' ); Returns true if the current post is in the specified category id. in_category( array( 1, 2, 3 ) ); Returns true if the current post is in either category 1, 2, or 3. ! in_category( array( 4, 5, 6 ) ); Returns true if the current post is NOT in either category 4, 5, or 6. Note the ! at the beginning. Note: Be sure to check your spelling when testing. There’s a big difference between “is” or “in”. See also is_archive() and Category Templates. A Tag Page is_tag() When any Tag archive page is being displayed. is_tag( 'mild' ); When the archive page for tag with the slug of ‘mild’ is being displayed. is_tag( array( 'sharp', 'mild', 'extreme' ) ); Returns true when the tag archive being displayed has a slug of either “sharp”, “mild”, or “extreme”. has_tag(); When the current post has a tag. Must be used inside The Loop. has_tag( 'mild' ); When the current post has the tag ‘mild’. has_tag( array( 'sharp', 'mild', 'extreme' ) ); When the current post has any of the tags in the array. See also is_archive() and Tag Templates. A Taxonomy Page is_tax() When any Taxonomy archive page is being displayed. is_tax( 'flavor' ); When a Taxonomy archive page for the flavor taxonomy is being displayed. is_tax( 'flavor', 'mild'); When the archive page for the flavor taxonomy with the slug of ‘mild’ is being displayed. is_tax( 'flavor', array( 'sharp', 'mild', 'extreme' ) ); Returns true when the flavor taxonomy archive being displayed has a slug of either “sharp”, “mild”, or “extreme”. has_term() Check if the current post has any of given terms. The first parameter should be an empty string. It expects a taxonomy slug/name as a second parameter. has_term( 'green', 'color' ); When the current post has the term ‘green’ from taxonomy ‘color’. has_term( array( 'green', 'orange', 'blue' ), 'color' ); When the current post has any of the terms in the array. See also is_archive(). A Registered Taxonomy taxonomy_exists() When a particular taxonomy is registered via register_taxonomy(). Formerly is_taxonomy() , which was deprecated in Version 3.0 An Author Page is_author() When any Author page is being displayed. is_author( '4' ); When the archive page for Author number (ID) 4 is being displayed. is_author( 'Vivian' ); When the archive page for the Author with Nickname “Vivian” is being displayed. is_author( 'john-jones' ); When the archive page for the Author with Nicename “john-jones” is being displayed. is_author( array( 4, 'john-jones', 'Vivian' ) ); When the archive page for the author is either user ID 4, or user_nicename “john-jones”, or nickname “Vivian”. See also is_archive() and Author Templates. A Multi-author Site is_multi_author() When more than one author has published posts for a site. Available with Version 3.2. A Date Page is_date() When any date-based archive page is being displayed (i.e. a monthly, yearly, daily or time-based archive). is_year() When a yearly archive is being displayed. is_month() When a monthly archive is being displayed. is_day() When a daily archive is being displayed. is_time() When an hourly, “minutely”, or “secondly” archive is being displayed. is_new_day() If today is a new day according to post date. Should be used inside the loop. Any Archive Page is_archive() When any type of Archive page is being displayed. Category, Tag, Author and Date based pages are all types of Archives. A Search Result Page is_search() When a search result page archive is being displayed. A 404 Not Found Page is_404() When a page displays after an “HTTP 404: Not Found” error occurs. A Privacy Policy Page is_privacy_policy() When the Privacy Policy page is being displayed. An Attachment is_attachment() When an attachment document to a post or Page is being displayed. An attachment is an image or other file uploaded through the post editor’s upload utility. Attachments can be displayed on their own ‘page’ or template. A Single Page, Single Post or Attachment is_singular() When any of the following return true: is_single(), is_page() or is_attachment(). is_singular( 'book' ); True when viewing a post of the Custom Post Types book. is_singular( array( 'newspaper', 'book' ) ); True when viewing a post of the Custom Post Types newspaper or book. A Syndication is_feed() When the site requested is a Syndication. This tag is not typically used by users; it is used internally by WordPress and is available for Plugin Developers. A Trackback is_trackback() When the site requested is WordPress’ hook into its Trackback engine. This tag is not typically used by users; it is used internally by WordPress and is available for Plugin Developers. A Preview is_preview() When a single post being displayed is viewed in Draft mode. Has An Excerpt has_excerpt() When the current post has an excerpt has_excerpt( 42 ) When the post 42 (ID) has an excerpt. post_excerpt ) ) { // This post has no excerpt } else { // This post has excerpt } Other use When you need to hide the auto displayed excerpt and only display your post’s excerpts. is_main_query() && is_post_type_archive( 'products' ) && ! is_admin() ) { // If it's the main query on a custom post type archive for Products. // And if we're not in the WordPress admin, then do something special. } if ( is_post_type_archive( 'movies' ) || is_tax( 'genre' ) || is_tax( 'actor' ) ) { // If it's a custom post type archive for Movies. // Or it's a taxonomy archive for Genre. // Or it's a taxonomy archive for Actor, do something special. } Date Based Differences If someone browses our site by date, let’s distinguish posts in different years by using different colors:

by '; } else { echo '
'; } } else { echo '
'; } the_content( 'Read the rest of this entry »' ); echo '
'; ?> Variable Sidebar Content This example will display different content in your sidebar based on what page the reader is currently viewing. Helpful 404 Page The Creating an Error 404 Page article as an example of using the PHP conditional function isset() in the Writing Friendly Messages section. In the theme’s footer.php file At times queries performed in other templates such as sidebar.php may corrupt certain conditional tags. For instance, in header.php a conditional tag works properly but doesn’t work in a theme’s footer.php. The trick is to put wp_reset_query before the conditional test in the footer. For example: "myfirsttheme-$block_name", 'src' => get_theme_file_uri( "assets/css/blocks/$block_name.css" ), $args['path'] = get_theme_file_path( "assets/css/blocks/$block_name.css" ), ); wp_enqueue_block_style( "core/$block_name", $args ); } } add_action( 'after_setup_theme', 'myfirsttheme_setup' ); Scripts Any additional JavaScript files required by a theme should be loaded using  wp_enqueue_script. This ensures proper loading and caching, and allows the use conditional tags to target specific pages. These are optional. wp_enqueue_script uses a similar syntax to  wp_enqueue_style. Enqueue your script: wp_enqueue_script( $handle, $src, $deps, $ver, $args ); $handle is the name for the script. $src defines where the script is located. $deps is an array that can handle any script that your new script depends on, such as jQuery. $ver lets you list a version number. $args an array of arguments that define footer printing (via an in_footer key) and script loading strategies (via a strategy key) such as defer or async. This replaces/overloads the $in_footer parameter as of WordPress version 6.3. Your enqueue function may look like this: wp_enqueue_script( 'script', get_template_directory_uri() . '/js/script.js', array( 'jquery' ), 1.1, true); Delayed Script Loading WordPress provides support for specifying a script loading strategy via the wp_register_script() and wp_enqueue_script() functions, by way of the strategy key within the new $args array parameter introduced in WordPress 6.3. Supported strategies are as follows: defer Added by specifying an array key value pair of 'strategy' => 'defer' to the $args parameter. Scripts marked for deferred execution — via the defer script attribute — are only executed once the DOM tree has fully loaded (but before the DOMContentLoaded and window load events). Deferred scripts are executed in the same order they were printed/added in the DOM, unlike asynchronous scripts. async Added by specifying an array key value pair of 'strategy' => 'async' to the $args parameter. Scripts marked for asynchronous execution — via the async script attribute — are executed as soon as they are loaded by the browser. Asynchronous scripts do not have a guaranteed execution order, as script B (although added to the DOM after script A) may execute first given that it may complete loading prior to script A. Such scripts may execute either before the DOM has been fully constructed or after the DOMContentLoaded event. Following is an example of specifying a loading strategy during script registration: wp_register_script( 'foo', '/path/to/foo.js', array(), '1.0.0', array( 'strategy' => 'defer', ) ); The same approach applies when using wp_enqueue_script(). When specifying a delayed script loading strategy, consideration of the script’s dependency tree (its dependencies and/or dependents) is taken into account when deciding on an “eligible strategy” so as not to result in application of a strategy that is valid for one script but detrimental to others in the tree by causing an unintended out of order of execution. As a result of such logic, the intended loading strategy that you pass via the $args parameter may not be the final (chosen) strategy, but it will never be detrimental to (or stricter than) the intended strategy. The Comment Reply Script WordPress comments have quite a bit of functionality in them right out of the box, including threaded comments and enhanced comment forms. In order for comments to work properly, they require some JavaScript. However, since there are certain options that need to be defined within this JavaScript, the comment-reply script should be added to every classic theme that uses comments. In block themes, the script is included when you place a comment block. You do not need to add it manually. The proper way to include comment reply in classic themes is to use conditional tags to check if certain conditions exist, so that the script isn’t being loaded unnecessarily. For instance, you can only load scripts on single post pages using  is_singular, and check to make sure that “Enable threaded comments” is selected by the user. So you can set up a function like: if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) { wp_enqueue_script( 'comment-reply' ); } If comments are enabled by the user, and we are on a post page, then the comment reply script will be loaded. Otherwise, it will not. Combining Enqueue Functions It is best to combine all enqueued scripts and styles into a single function, and then call them using the  wp_enqueue_scripts action. This function and action should be located somewhere below the initial setup (performed above): function add_theme_scripts() { wp_enqueue_style( 'style', get_stylesheet_uri() ); wp_enqueue_style( 'slider', get_template_directory_uri() . '/css/slider.css', array(), '1.1', 'all' ); wp_enqueue_script( 'script', get_template_directory_uri() . '/js/script.js', array( 'jquery' ), 1.1, true ); if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) { wp_enqueue_script( 'comment-reply' ); } } add_action( 'wp_enqueue_scripts', 'add_theme_scripts' ); Default Scripts Included and Registered by WordPress By default, WordPress includes many popular scripts commonly used by web developers, as well as the scripts used by WordPress itself. Some of them are listed on this reference page: wp_enqueue_script() The list is far from complete. You can find a full list of included files in wp-includes/script-loader.php. / Changelog: Updated 2023-02-24: Added information about wp_enqueue_block_style() . Updated 2024-06-06: Added alert to point readers to new doc. Linking Theme Files & Directories Linking to Core Theme Files As you’ve learned, WordPress themes are built from a number of different template files. At the very least this will usually include a sidebar.php, header.php and footer.php. These are called using Template Tags, for example: get_header() ; get_footer() ; get_sidebar() ; You can create custom versions of these files can be called as well by naming the file sidebar-{your_custom_template}.php, header-{your_custom_template}.php and  footer-{your_custom_template}.php. You can then use Template Tags with the custom template name as the only parameter, like this: get_header( 'your_custom_template' ); get_footer( 'your_custom_template' ); get_sidebar( 'your_custom_template' ); WordPress creates pages by assembling various files. Aside from the standard files for the header, footer and sidebar, you can create custom template files and call them at any location in the page using get_template_part() . To create a custom template file in your theme give the file an appropriate name and use the same custom template system as with the header, sidebar and footer files: slug-template.php For example, if you would like to create a custom template to handle your post content you could create a template file called content.php and then add a specific content layout for product content by extending the file name to content-product.php. You would then load this template file in your theme like this: get_template_part( 'content', 'product' ); If you want to add more organization to your templates, you can place them in their own directories within your theme directory. For example, suppose you add a couple more content templates for profiles and locations, and group them in their own directory called content-templates. The theme hierarchy for your theme called my-theme might look like the following. style.css and page.php are included for context. themes my-theme content-templates content-location.php content-product.php content-profile.php style.css To include your content templates, prepend the directory names to the slug argument like this: get_template_part( 'content-templates/content', 'location' ); get_template_part( 'content-templates/content', 'product' ); get_template_part( 'content-templates/content', 'profile' ); Linking to Theme Directories To link to the theme’s directory, you can use the following function: get_theme_file_uri() ; If you are not using a child theme, this function will return the full URI to your theme’s main folder. You can use this to reference sub-folders and files in your theme like this: echo get_theme_file_uri( 'images/logo.png' ); If you are using a child theme then this function will return the URI of the file in your child theme if it exists. If the file cannot be found in your child theme, the function will return the URI of the file in the parent theme. This is particularly important to keep in mind when distributing a theme or in any other case where a child theme may or may not be active. To access the path to a file in your theme’s directories, you can use the following function: get_theme_file_path() ; Like get_theme_file_uri() , this will access the path of the file in the child theme if it exists. If the file cannot be found in the child theme, the function will access the path to the file in the parent theme. In a child theme, you can link to a file URI or path in the parent theme’s directories using the following functions: get_parent_theme_file_uri() ; get_parent_theme_file_path() ; As with   get_theme_file_uri(), you can reference sub-folders and files like this: echo get_parent_theme_file_uri( 'images/logo.png' ); //or echo get_parent_theme_file_path( 'images/logo.png' ); Take care when referencing files that may not be present, as these functions will return the URI or file path whether the file exists or not. If the file is missing, these functions will return a broken link. The functions get_theme_file_uri() , get_theme_file_path() , get_parent_theme_file_uri() , get_parent_theme_file_path() were introduced in WordPress 4.7. For previous WordPress versions, use get_template_directory_uri() , get_template_directory() , get_stylesheet_directory_uri() , get_stylesheet_directory() . Take note that the newer 4.7 functions run the older functions anyway as part of the checking process so it makes sense to use the newer functions when possible. Dynamic Linking in Templates Regardless of your permalink settings, you can link to a page or post dynamically by referring to its unique numerical ID (seen in several pages in the admin interface) with This is a link This is a convenient way to create page menus as you can later change page slugs without breaking links, as IDs will stay the same. However, this might increase database queries. Main Stylesheet (style.css) The style.css is a stylesheet (CSS) file required for every WordPress theme. It controls the presentation (visual design and layout) of the website pages. Location In order for WordPress to recognize the set of theme template files as a valid theme, the style.css file needs to be located in the root directory of your theme, not a subdirectory. For more detailed explanation on how to include the style.css file in a theme, see the “Stylesheets” section of Enqueuing Scripts and Styles. Basic Structure WordPress uses the header comment section of a style.css to display information about the theme in the Appearance (Themes) dashboard panel. Example Here is an example of the header part of style.css. /* Theme Name: Twenty Twenty Theme URI: https://wordpress.org/themes/twentytwenty/ Author: the WordPress team Author URI: https://wordpress.org/ Description: Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor. Organizations and businesses have the ability to create dynamic landing pages with endless layouts using the group and column blocks. The centered content column and fine-tuned typography also makes it perfect for traditional blogs. Complete editor styles give you a good idea of what your content will look like, even before you publish. You can give your site a personal touch by changing the background colors and the accent color in the Customizer. The colors of all elements on your site are automatically calculated based on the colors you pick, ensuring a high, accessible color contrast for your visitors. Tags: blog, one-column, custom-background, custom-colors, custom-logo, custom-menu, editor-style, featured-images, footer-widgets, full-width-template, rtl-language-support, sticky-post, theme-options, threaded-comments, translation-ready, block-styles, wide-blocks, accessibility-ready Version: 1.3 Requires at least: 5.0 Tested up to: 5.4 Requires PHP: 7.0 License: GNU General Public License v2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html Text Domain: twentytwenty 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. */ WordPress Theme Repository uses the number after “Version” in this file to determine if the theme has a new version available. Explanations Items indicated with (*) are required for a theme in the WordPress Theme Repository. Theme Name (*): Name of the theme. Theme URI: The URL of a public web page where users can find more information about the theme. Author (*): The name of the individual or organization who developed the theme. Using the Theme Author’s wordpress.org username is recommended. Author URI: The URL of the authoring individual or organization. Description (*): A short description of the theme. Version (*): The version of the theme, written in X.X or X.X.X format. Requires at least (*): The oldest main WordPress version the theme will work with, written in X.X format. Themes are only required to support the three last versions. Tested up to (*): The last main WordPress version the theme has been tested up to, i.e. 5.4. Write only the number, in X.X format. Requires PHP (*): The oldest PHP version supported, in X.X format, only the number License (*): The license of the theme. License URI (*): The URL of the theme license. Text Domain (*): The string used for textdomain for translation. Tags: Words or phrases that allow users to find the theme using the tag filter. A full list of tags is in the Theme Review Handbook. Domain Path: Used so that WordPress knows where to find the translation when the theme is disabled. Defaults to /languages. After the required header section, style.css can contain anything a regular CSS file has. Style.css for a Child Theme If your theme is a Child Theme, the Template line is required in style.css header. /* Theme Name: My Child Theme Template: twentytwenty */ For more information on creating a Child Theme, visit the Child Themes page. Organizing Theme Files While WordPress themes technically only require two files ( index.php in classic themes and index.html in block themes, and style.css), they usually are made up of many files. That means they can quickly become disorganized! This section will show you how to keep your files organized. Theme folder and file structure As mentioned previously, the default Twenty themes are some of the best examples of good theme development. For instance, here is how the Twenty Seventeen Theme organizes its file structure: . ├── assets (dir)/ │ ├── css (dir) │ ├── images (dir) │ └── js (dir) ├── inc (dir) ├── template-parts (dir)/ │ ├── footer (dir) │ ├── header (dir) │ ├── navigation (dir) │ ├── page (dir) │ └── post (dir) ├── 404.php ├── archive.php ├── comments.php ├── footer.php ├── front-page.php ├── functions.php ├── header.php ├── index.php ├── page.php ├── README.txt ├── rtl.css ├── screenshot.png ├── search.php ├── searchform.php ├── sidebar.php ├── single.php └── style.css You can see that the main theme template files are in the root directory, while JavaScript, CSS, images are placed in assets directory, template-parts are placed in under respective subdirectory of template-parts and collection of  functions related to core functionalities are placed in inc directory. There are no required folders in classic themes. In block themes, templates must be placed inside a folder called templates, and all template parts must be placed inside a folder called parts. style.css should reside in the root directory of your theme not within the CSS directory. Languages folder It’s best practice to internationalize your theme so it can be translated into other languages. Default themes include the languages folder, which contains a .pot file for translation and any translated .mo files. While  languages is the default name of this folder, you can change the name. If you do so, you must update load_theme_textdomain(). Post Types There are many different types of content in WordPress. These content types are normally described as Post Types, which may be a little confusing since it refers to all different types of content in WordPress. For example, a post is a specific Post Type, and so is a page. Internally, all of the Post Types are stored in the same place — in the wp_posts database table — but are differentiated by a database column called post_type. In addition to the default Post Types, you can also create Custom Post Types. The Template files page briefly mentioned that different Post Types are displayed by different Template files.  As the whole purpose of a Template file is to display content a certain way, the Post Types purpose is to categorize what type of content you are dealing with. Generally speaking, certain Post Types are tied to certain template files. Default Post Types There are several default Post Types readily available to users or internally used by the WordPress installation. The most common are: Post (Post Type: ‘post’) Page (Post Type: ‘page’) Attachment (Post Type: ‘attachment’) Revision (Post Type: ‘revision’) Navigation menu (Post Type: ‘nav_menu_item’) Block templates (Post Type: ‘wp_template’) Template parts (Post Type: ‘wp_template_part’) The Post Types above can be modified and removed by a plugin or theme, but it’s not recommended that you remove built-in functionality for a widely-distributed theme or plugin. It’s out of the scope of this handbook to explain other post types in detail. However, it is important to note that you will interact with and build the functionality of navigation menus and that will be detailed later in this handbook. Post Posts are used in blogs. They are: displayed in reverse sequential order by time, with the newest post first have a date and time stamp may have the default taxonomies of categories and tags applied are used for creating feeds The template files that display the Post post type are: single and  single-post category and all its iterations tag and all its iterations taxonomy and all its iterations archive and all its iterations author and all its iterations date and all its iterations search home index Read more about Post Template Files in classic themes. Page Pages are a static Post Type, outside of the normal blog stream/feed. Their features are: non-time dependent and without a time stamp are not organized using the categories and/or tags taxonomies can be organized in a hierarchical structure — i.e. pages can be parents/children of other pages The template files that display the Page post type are: page and all its iterations front-page search index Read more about Page Template Files in classic themes. Attachment Attachments are commonly used to display images or media in content, and may also be used to link to relevant files. Their features are: contain information (such as name or description) about files uploaded through the media upload system for images, this includes metadata information stored in the wp_postmeta table (including size, thumbnails, location, etc) The template files that display the Attachment post type are: MIME_type attachment single-attachment single index Read more about Attachment Template Files in classic themes. Custom Post Types Using Custom Post Types, you can create your own post type. It is not recommend that you place this functionality in your theme. This type of functionality should be placed/created in a plugin. This ensures the portability of your user’s content, and that if the theme is changed the content stored in the Custom Post Types won’t disappear. You can learn more about creating custom post types in the WordPress Plugin Developer Handbook. While you generally won’t develop Custom Post Types in your theme, you may want to code ways to display Custom Post Types that were created by a plugin.  The following templates can display Custom post types: single-{post-type} archive-{post-type} search index Read more about Custom Post Type Templates in classic themes. Reworking Theme Files & Organization Theme folder and file structure While WordPress themes technically only require two files ( index.php and style.css), they usually are made up of many files and can become quickly disorganized. In the last section, Template Files, you set up your header.php, footer.php, page.php, home.php, and single.php files. Let’s look at the Twenty Twelve theme default themes as one example of good file structure and organization.  While this may be a bit overwhelming at first, let’s break it down. Can you find the templates you just built? While there are still a lot of files, their names help provide a context of what they are. Basically, each file handles a feature of WordPress.  I.e. comments.php deals with how the theme will handle comments; image.php instructs the theme how to handle images, etc.  Don’t worry about adding these files unless you need them. You can see that the main theme template files are in the theme’s root directory, while JavaScript, languages, CSS, and page template files are placed within their own folders. At this time, there are no required folders within a WordPress theme. However, WordPress does recognize the following folders by default: Page templates folder The custom page templates, named page-templates (since 3.4.0), allow for better organization of template files. Custom page template files placed in this folder are automatically recognized by WordPress. Language folder If you wish to internationalize your theme so it’s usable in other languages, you can create a languages folder to contain translations. Template Files Template files are used throughout WordPress themes, but first let’s learn about the terminology. Template Terminology The term “template” is used in different ways when working with WordPress themes: Templates files exist within a theme and express how your site is displayed. Template Hierarchy is the logic WordPress uses to decide which theme template file(s) to use, depending on the content being requested. Page Templates are those that apply to pages, posts, and custom post types to change their look and feel. In classic themes, Template Tags are built-in WordPress functions you can use inside a template file to retrieve and display data (such as the_title() and the_content()). In block themes, blocks are used instead of template tags. Template files WordPress themes are made up of template files. In classic themes these are PHP files that contain a mixture of HTML, Template Tags, and PHP code. In block themes these are HTML files that contain HTML markup representing blocks. When you are building your theme, you will use template files to affect the layout and design of different parts of your website. For example, you would use a header template or template part to create a header. When someone visits a page on your website, WordPress loads a template based on the request. The type of content that is displayed by the template file is determined by the Post Type associated with the template file. The Template Hierarchy describes which template file WordPress will load based on the type of request and whether the template exists in the theme. The server then parses the code in the template and returns HTML to the visitor. The most critical template file is the index, which is the catch-all template if a more-specific template can not be found in the template hierarchy. Although a theme only needs a  index template, typically themes include numerous templates to display different content types and contexts. Template partials A template part is a piece of a template that is included as a part of another template, such as a site header. Template part can be embedded in multiple templates, simplifying theme creation. Common template parts include: header.php or header.html for generating the site’s header footer.php or footer.html for generating the footer sidebar.php or sidebar.html for generating the sidebar While the above template files are special-case in WordPress and apply to just one portion of a page, you can create any number of template partials and include them in other template files. In block themes, template parts must be placed inside a folder called parts. Common WordPress template files Below is a list of some basic theme templates and files recognized by WordPress. index.php (classic theme) or index.html (block theme) The main template file. It is required in all themes. style.css The main stylesheet. It is required in all themes and contains the information header for your theme. rtl.css The right-to-left stylesheet is included automatically if the website language’s text direction is right-to-left. front-page.php (classic theme) or front-page.html (block theme) The front page template is always used as the site front page if it exists, regardless of what settings on Admin > Settings > Reading. home.php (classic theme) or home.html (block theme) The home page template is the front page by default. If you do not set WordPress to use a static front page, this template is used to show latest posts. singular.php (classic theme) or singular.html (block theme) The singular template is used for posts when single.php is not found, or for pages when page.php are not found. If singular.php is not found, index.php is used. single.php (classic theme) or single.html (block theme) The single post template is used when a visitor requests a single post. single-{post-type}.php (classic theme) or single-{post-type}.html (block theme) The single post template used when a visitor requests a single post from a custom post type. For example, single-book.php would be used for displaying single posts from a custom post type named book. archive-{post-type}.php (classic theme) or archive-{post-type}.html (block theme) The archive post type template is used when visitors request a custom post type archive. For example, archive-books.php would be used for displaying an archive of posts from the custom post type named books. The archive template file is used if the archive-{post-type} template is not present. page.php (classic theme) or page.html (block theme) The page template is used when visitors request individual pages, which are a built-in template. page-{slug}.php (classic theme) or page-{slug}.html (block theme) The page slug template is used when visitors request a specific page, for example one with the “about” slug (page-about.php). category.php (classic theme) or category.html (block theme) The category template is used when visitors request posts by category. tag.php (classic theme) or tag.html (block theme) The tag template is used when visitors request posts by tag. taxonomy.php (classic theme) or taxonomy.html (block theme) The taxonomy term template is used when a visitor requests a term in a custom taxonomy. author.php (classic theme) or author.html (block theme) The author page template is used whenever a visitor loads an author page. date.php (classic theme) or date.html (block theme) The date/time template is used when posts are requested by date or time. For example, the pages generated with these slugs: http://example.com/blog/2014/ http://example.com/blog/2014/05/ http://example.com/blog/2014/05/26/ archive.php (classic theme) or archive.html (block theme) The archive template is used when visitors request posts by category, author, or date. Note: this template will be overridden if more specific templates are present like category.php, author.php, and date.php. search.php (classic theme) or search.html (block theme) The search results template is used to display a visitor’s search results. attachment.php (classic theme) or attachment.html (block theme) The attachment template is used when viewing a single attachment like an image, pdf, or other media file. image.php (classic theme) or image.html (block theme) The image attachment template is a more specific version of attachment.php and is used when viewing a single image attachment. If not present, WordPress will use attachment.php instead. 404.php (classic theme) or 404.html (block theme) The 404 template is used when WordPress cannot find a post, page, or other content that matches the visitor’s request. comments.php The comments template in classic themes. In block themes, blocks are used instead. Using template files Classic themes In classic themes, within WordPress templates, you can use Template Tags to display information dynamically, include other template files, or otherwise customize your site. For example, in your index.php you can include other files in your final generated page: To include the header, use get_header() To include the sidebar, use get_sidebar() To include the footer, use get_footer() To include the search form, use get_search_form() To include custom theme files, use get_template_part() Here is an example of WordPress template tags to include specific templates into your page: There’s an entire page on Template Tags that you can dive into to learn all about them. Refer to the section Linking Theme Files & Directories for more information on linking component templates. Block themes In block themes you use blocks instead of template tags. Block markup is the HTML code that WordPress uses to display the block. Template parts are blocks, and you add them to your template files the same way as you add blocks. To include a header or footer template part, add the block markup for the template part. The slug is the name of the part. If the file you want to include is called header.html, then the slug is “header”: (your page content) To include the search form, use the block markup for the search block: Template Hierarchy As discussed, template files are modular, reusable files, used to generate the web pages on your WordPress site. Some template files (such as the header and footer template) are used on all of your site’s pages, while others are used only under specific conditions. This article explains how WordPress determines which template file(s) to use on individual pages. If you want to customize an existing WordPress theme it will help you decide which template file needs to be edited. You can also use Conditional Tags to control which templates are loaded on a specific page. The Template File Hierarchy Overview WordPress uses the query string to decide which template or set of templates should be used to display the page. The query string is information that is contained in the link to each part of your website. Put simply, WordPress searches down through the template hierarchy until it finds a matching template file. To determine which template file to use, WordPress: Matches every query string to a query type to decide which page is being requested (for example, a search page, a category page, etc); Selects the template in the order determined by the template hierarchy; Looks for template files with specific names in the current theme’s directory and uses the first matching template file as specified by the hierarchy. With the exception of the basic index.php template file, you can choose whether you want to implement a particular template file or not. In these examples, the PHP file extension is used. In block themes, HTML files are used instead, but the template hierarchy is the same. If WordPress cannot find a template file with a matching name, it will skip to the next file in the hierarchy. If WordPress cannot find any matching template file, the theme’s index.php file will be used. When you are using a child theme, any file you add to your child theme will over-ride the same file in the parent theme. For example, both themes contain the same template  category.php, then child theme’s template is used. If a child theme contains the specific template such as  category-unicorns.php and the parent theme contains lower prioritized template such as  category.php, then child theme’s  category-unicorns.php is used. Contrary, if a child theme contains general template only such as  category.php and the parent theme contains the specific one such as  category-unicorns.php, then parent’s template  category-unicorns.php is used. Examples If your blog is at http://example.com/blog/ and a visitor clicks on a link to a category page such as  http://example.com/blog/category/your-cat/, WordPress looks for a template file in the current theme’s directory that matches the category’s ID to generate the correct page. More specifically, WordPress follows this procedure: Looks for a template file in the current theme’s directory that matches the category’s slug. If the category slug is “unicorns,” then WordPress looks for a template file named category-unicorns.php. If category-unicorns.php is missing and the category’s ID is 4, WordPress looks for a template file named category-4.php. If category-4.php is missing, WordPress will look for a generic category template file, category.php. If category.php does not exist, WordPress will look for a generic archive template, archive.php. If archive.php is also missing, WordPress will fall back to the main theme template file, index.php. Visual Overview The following diagram shows which template files are called to generate a WordPress page based on the WordPress template hierarchy. The Template Hierarchy In Detail While the template hierarchy is easier to understand as a diagram, the following sections describe the order in which template files are called by WordPress for a number of query types. Home Page display By default, WordPress sets your site’s home page to display your latest blog posts. This page is called the blog posts index. You can also set your blog posts to display on a separate static page. The template file home.php is used to render the blog posts index, whether it is being used as the front page or on separate static page. If  home.php does not exist, WordPress will use  index.php. home.php index.php If front-page.php exists, it will override the  home.php template. Front Page display The front-page.php template file is used to render your site’s front page, whether the front page displays the blog posts index (mentioned above) or a static page. The front page template takes precedence over the blog posts index ( home.php) template. If the front-page.php file does not exist, WordPress will either use the home.php or page.php files depending on the setup in Settings → Reading. If neither of those files exist, it will use the index.php file. front-page.php – Used for both “your latest posts” or “a static page” as set in the front page displays section of Settings → Reading. home.php – If WordPress cannot find  front-page.php and “your latest posts” is set in the front page displays section, it will look for home.php. Additionally, WordPress will look for this file when the posts page is set in the front page displays section. page.php – When “front page” is set in the front page displays section. index.php – When “your latest posts” is set in the front page displays section but  home.php does not exist or when front page is set but page.php does not exist. As you can see, there are a lot of rules to what path WordPress takes. Using the chart above is the best way to determine what WordPress will display. Privacy Policy Page display The privacy-policy.php template file is used to render your site’s Privacy Policy page. The Privacy Policy page template takes precedence over the static page ( page.php) template. If the privacy-policy.php file does not exist, WordPress will either use the page.php or singular.php files depending on the available templates. If neither of those files exist, it will use the index.php file. privacy-policy.php – Used for the Privacy Policy page set in the Change your Privacy Policy page section of Settings → Privacy. custom template file – The page template assigned to the page. See get_page_templates(). page-{slug}.php – If the page slug is privacy, WordPress will look to use page-privacy.php. page-{id}.php – If the page ID is 6, WordPress will look to use page-6.php. page.php singular.php index.php Single Post The single post template file is used to render a single post. WordPress uses the following path: single-{post-type}-{slug}.php – (Since 4.4) First, WordPress looks for a template for the specific post. For example, if post type is product and the post slug is dmc-12, WordPress would look for single-product-dmc-12.php. single-{post-type}.php – If the post type is product, WordPress would look for single-product.php. single.php – WordPress then falls back to single.php. singular.php – Then it falls back to singular.php. index.php – Finally, as mentioned above, WordPress ultimately falls back to index.php. Single Page The template file used to render a static page ( page post-type). Note that unlike other post-types, page is special to WordPress and uses the following path: custom template file – The page template assigned to the page. See get_page_templates(). page-{slug}.php – If the page slug is recent-news, WordPress will look to use page-recent-news.php. page-{id}.php – If the page ID is 6, WordPress will look to use page-6.php. page.php singular.php index.php Category Rendering category archive index pages uses the following path in WordPress: category-{slug}.php – If the category’s slug is news, WordPress will look for category-news.php. category-{id}.php – If the category’s ID is 6, WordPress will look for category-6.php. category.php archive.php index.php Tag To display a tag archive index page, WordPress uses the following path: tag-{slug}.php – If the tag’s slug is sometag, WordPress will look for tag-sometag.php. tag-{id}.php – If the tag’s ID is 6, WordPress will look for tag-6.php. tag.php archive.php index.php Custom Taxonomies Custom taxonomies use a slightly different template file path: taxonomy-{taxonomy}-{term}.php – If the taxonomy is sometax, and taxonomy’s term is someterm, WordPress will look for taxonomy-sometax-someterm.php. In the case of post formats, the taxonomy is ‘post_format’ and the terms are ‘post-format-{format}. i.e. taxonomy-post_format-post-format-link.php for the link post format. taxonomy-{taxonomy}.php – If the taxonomy were sometax, WordPress would look for taxonomy-sometax.php. taxonomy.php archive.php index.php Custom Post Types Custom Post Types use the following path to render the appropriate archive index page. archive-{post_type}.php – If the post type is product, WordPress will look for archive-product.php. archive.php index.php (For rendering a single post type template, refer to the single post display section above.) Author display Based on the above examples, rendering author archive index pages is fairly explanatory: author-{nicename}.php – If the author’s nice name is matt, WordPress will look for author-matt.php. author-{id}.php – If the author’s ID were 6, WordPress will look for author-6.php. author.php archive.php index.php Date Date-based archive index pages are rendered as you would expect: date.php archive.php index.php Search Result Search results follow the same pattern as other template types: search.php index.php 404 (Not Found) Likewise, 404 template files are called in this order: 404.php index.php Attachment Rendering an attachment page ( attachment post-type) uses the following path: {MIME-type}.php – can be any MIME type (For example:  image.php, video.php, pdf.php). For text/plain, the following path is used (in order): text-plain.php plain.php text.php attachment.php single-attachment-{slug}.php – For example, if the attachment slug is holiday, WordPress would look for single-attachment-holiday.php. single-attachment.php single.php singular.php index.php As of WordPress 6.4, attachment pages are no longer enabled by default on new installations. Users can enable them with a plugin, so it is still good practice to test your theme and ensure it properly displays content when viewing an attachment page. Embeds The embed template file is used to render a post which is being embedded. Since 4.5, WordPress uses the following path: embed-{post-type}-{post_format}.php – First, WordPress looks for a template for the specific post. For example, if its post type is post and it has the audio format, WordPress would look for embed-post-audio.php. embed-{post-type}.php – If the post type is product, WordPress would look for embed-product.php. embed.php – WordPress then falls back to embed .php. Finally, WordPress ultimately falls back to its own wp-includes/theme-compat/embed.php template. Non-ASCII Character Handling Since WordPress 4.7, any dynamic part of a template name which includes non-ASCII characters in its name actually supports both the un-encoded and the encoded form, in that order. You can choose which to use. Here’s the page template hierarchy for a page named “Hello World 😀” with an ID of 6: page-hello-world-😀.php page-hello-world-%f0%9f%98%80.php page-6.php page.php singular.php The same behaviour applies to post slugs, term names, and author nicenames. Filter Hierarchy The WordPress template system lets you filter the hierarchy. This means that you can insert and change things at specific points of the hierarchy. The filter (located in the get_query_template() function) uses this filter name: "{$type}_template" where $type is the template type. Here is a list of all available filters in the template hierarchy: embed_template 404_template search_template frontpage_template home_template privacypolicy_template taxonomy_template attachment_template single_template page_template singular_template category_template tag_template author_template date_template archive_template index_template Example For example, let’s take the default author hierarchy: author-{nicename}.php author-{id}.php author.php To add author-{role}.php before author.php, we can manipulate the actual hierarchy using the ‘author_template’ template type. This allows a request for /author/username where username has the role of editor to display using author-editor.php if present in the current themes directory. function author_role_template( $templates = '' ) { $author = get_queried_object(); $role = $author->roles[0]; if ( ! is_array( $templates ) && ! empty( $templates ) ) { $templates = locate_template( array( "author-$role.php", $templates ), false ); } elseif ( empty( $templates ) ) { $templates = locate_template( "author-$role.php", false ); } else { $new_template = locate_template( array( "author-$role.php" ) ); if ( ! empty( $new_template ) ) { array_unshift( $templates, $new_template ); } } return $templates; } add_filter( 'author_template', 'author_role_template' ); Changelog: Updated 2022-02-15. Added a notice explaining that the template hierarchy is the same for classic and block themes, but that the examples uses .php files and block themes use .html files. Template Tags Template tags are used within themes to retrieve content from your database. The content could be anything from a blog title to a complete sidebar. Template tags are the preferred method to pull content into your theme because: they can print dynamic content; they can be used in multiple theme files; and they separate the theme into smaller, more understandable, sections. What is a Template Tag? A template tag is simply a piece of code that tells WordPress to get something from the database. It is broken up into three components: A PHP code tag A WordPress function Optional parameters You can use a template tag to call another theme file or some information from the database. For example, the template tag get_header() tells WordPress to get the header.php file and include it in the current theme file. Similarly, get_footer() tells WordPress to get the footer.php file. There are also other kinds of template tags: the_title() – tells WordPress to get the title of the page or post from the database and include it. bloginfo( 'name' ) – tells WordPress to get the blog title out of the database and include it in the template file. If you look closely at the last example, you will also see that there is a parameter between the parenthesis. Parameters let you do two things: ask for specific pieces of information and format the information in a certain way. Parameters are covered extensively below, but it’s useful to be aware that you can send WordPress-specific instructions for how you want the data presented. Why Use Template Tags By encapsulating all of the code for a particular chunk of content, template tags make it very easy to include various pieces of a template in a theme file and also to maintain the theme. It is far easier to create one  header.php file and have all of your theme templates like single.php, page.php, front-page.php, etc. reference that one theme file using get_header() than copying and pasting the code into each theme file. It also makes maintenance easier. Whenever you make a change in your header.php file, the change is automatically carried over into all of your other theme files. Another reason to use template tags is to display dynamic data, i.e. data from the database. In your header, you could manually include the title tag, like so: My Personal Website However, doing this means manually editing your theme any time you want to change the title of your website. Instead, it’s easier to include the bloginfo( 'name' ) template tag, which automatically fetch the site title from the database. Now, you can change the title of your site in WordPress, rather than having to hard code your theme templates. How to Use Template Tags Using template tags is very simple. In any template file you can use a template tag by simply printing one line of php code to call the template tag. Printing the header.php file is as simple as: get_header(); Parameters Some template tags let you pass parameters. Parameters are extra pieces of information that determine what is retrieved from the database. For example, the  bloginfo() template tag allows you to give it a parameter telling WordPress the specific piece of information you want. To print the blog name, you just pass along the parameter “name,” like so: bloginfo( 'name' ); To print the version of WordPress that the blog is running on, you would pass a parameter of “version”: bloginfo( 'version' ); For each template tag, the parameters differ. A list of the parameters and what they can do can be found on specific template tag pages located throughout the code reference. Using Template Tags Within the Loop Many template tags work within the WordPress Loop. This means that they are included in the template files as part of the php “loop” that generates the pages users see based upon the instructions inside of the loop. The WordPress loop begins with: if ( have_posts() ) : while ( have_posts() ) : the_post(); Template tags that work within the loop must be in the middle area, before the ending section of the loop below: endwhile; else : _e( 'Sorry, no posts matched your criteria.', 'devhub' ); endif; Some of template tags that need to be inside of the loop include the_content() the_excerpt() next_post() previous_post() The main reason why some functions require the loop is because they require the global post object to be set. If the template tag you want to use doesn’t have to be within the loop wp_list_cats() wp_list_pages() then you can put it in any file you’d like, for instance in the sidebar, header, or footer template files. These are functions that typically do not require the global post object. See Also Conditional Tags Complete list of Template Tags Plugin API Hooks The Loop The Loop is the default mechanism WordPress uses for outputting posts through a theme’s template files. How many posts are retrieved is determined by the number of posts to show per page defined in the Reading settings. Within the Loop, WordPress retrieves each post to be displayed on the current page and formats it according to your theme’s instructions. The Loop extracts the data for each post from the WordPress database and inserts the appropriate information in place of each template tag. Any HTML or PHP code in The Loop will be processed for each post. To put it simply, the Loop is true to its name: it loops through each post retrieved for the current page one at a time and performs the action specified in your theme. You can use the Loop for a number of different things, for example to: display post titles and excerpts on your blog’s homepage; display the content and comments on a single post; display the content on an individual page using template tags; and display data from Custom Post Types and Custom Fields. You can customize the Loop across your template files to display and manipulate different content. The Loop in Detail The basic loop is: This loop says that when there are posts, loop through and display the posts. Broken down into more detail: The have_posts() function checks whether there are any posts. If there are posts, a while loop continues to execute as long as the condition in the parenthesis is logically true. As long as have_posts() continues to be true, the loop will continue. Using The Loop The Loop should be placed in index.php, and in any other templates which are used to display post information. Because you do not want to duplicate your header over and over, the loop should always be placed after the call to get_header(). For example: In the above example, the end of the Loop is shown with an endwhile and endif. The Loop must always begin with the same if and while statements, as mentioned above and must end with the same end statements. Any template tags that you wish to apply to all posts must exist between the beginning and ending statements. You can include a custom 404 “not found” message that will be displayed if no posts matching the specified criteria are available. The message must be placed between the endwhile and endif statements, as seen in examples below. An extremely simple index.php file would look like: What the Loop Can Display The Loop can display a number of different elements for each post. For example, some common template tags used in many themes are: next_post_link() – a link to the post published chronologically after the current post previous_post_link() – a link to the post published chronologically before the current post the_category() – the category or categories associated with the post or page being viewed the_author() – the author of the post or page the_content() – the main content for a post or page the_excerpt() – the first 55 words of a post’s main content followed by an ellipsis (…) or read more link that goes to the full post. You may also use the “Excerpt” field of a post to customize the length of a particular excerpt. the_ID() – the ID for the post or page the_meta() – the custom fields associated with the post or page the_shortlink() – a link to the page or post using the url of the site and the ID of the post or page the_tags() – the tag or tags associated with the post the_title() – the title of the post or page the_time() – the time or date for the post or page. This can be customized using standard php date function formatting. You can also use conditional tags, such as: is_home() – Returns true if the current page is the homepage is_admin() – Returns true if inside Administration Screen, false otherwise is_single() – Returns true if the page is currently displaying a single post is_page() – Returns true if the page is currently displaying a single page is_page_template() – Can be used to determine if a page is using a specific template, for example: is_page_template('about-page.php') is_category() – Returns true if page or post has the specified category, for example: is_category('news') is_tag() – Returns true if a page or post has the specified tag is_author() – Returns true if inside author’s archive page is_search() – Returns true if the current page is a search results page is_404() – Returns true if the current page does not exist has_excerpt() – Returns true if the post or page has an excerpt Examples Let’s take a look at some examples of the Loop in action: Basic Examples Blog Archive Most blogs have a blog archive page, which can show a number of things including the post title, thumbnail, and excerpt. The example below shows a simple loop that checks to see if there are any posts and, if there are, outputs each post’s title, thumbnail, and excerpt. If no posts exists, it displays the message in parentheses. ', '' ); the_post_thumbnail(); the_excerpt(); endwhile; else: _e( 'Sorry, no posts matched your criteria.', 'textdomain' ); endif; ?> Individual Post In WordPress, each post has its own page, which displays the relevant information for that post. Template tags allow you to customize which information you want to display. In the example below, the loop outputs the post’s title and content. You could use this example in a post or page template file to display the most basic information about the post. You could also customize this template to add more data to the post, for example the category. ', '' ); the_content(); endwhile; else: _e( 'Sorry, no pages matched your criteria.', 'textdomain' ); endif; ?> Intermediate Examples Style Posts from Some Categories Differently The example below does a couple of things: First, it displays each post with its title, time, author, content, and category, similar to the individual post example above. Next, it makes it possible for posts with the category ID of “3” to be styled differently, utilizing the in_category() template tag. Code comments in this example provide details throughout each stage of the loop:
', ';' ); // Display a link to other posts by this posts author. printf( __( 'Posted by %s', 'textdomain' ), get_the_author_posts_link() ); // Display the post's content in a div. ?>
Multiple Loops In some situations, you may need to use more than one loop. For example you may want to display the titles of the posts in a table of content list at the top of the page and then display the content further down the page. Since the query isn’t being changed we simply need to rewind the loop when we need to loop through the posts for a second time. For that we will use the function rewind_posts() . Using rewind_posts You can use rewind_posts() to loop through the same query a second time. This is useful if you want to display the same query twice in different locations on a page. Here is an example of rewind_posts() in use: Creating secondary queries and loops Using two loops with the same query was relatively easy but not always what you will need. Instead, you will often want to create a secondary query to display different content on the template. For example, you might want to display two groups of posts on the same page, but do different things to each group. A common example of this, as shown below, is displaying a single post with a list of posts from the same category below the single post. have_posts() ) echo ''; endif; wp_reset_postdata(); ?> As you can see in the example above, we first display a regular loop. Then we define a new variable that uses WP_Query to query a specific category; in our case, we chose the example-category slug. Note that the regular loop in the example above has one difference: it calls wp_reset_postdata() to reset the post data. Before you can use a second loop, you need to reset the post data. There are two ways to do this: By using the rewind_posts() function; or By creating new query objects. Resetting multiple loops It’s important when using multiple loops in a template that you reset them. Not doing so can lead to unexpected results due to how data is stored and used within the global $post variable. There are three main ways to reset the loop depending on the way they are called. wp_reset_postdata() wp_reset_query() rewind_posts() Using wp_reset_postdata Use wp_reset_postdata() when you are running custom or multiple loops with WP_Query. This function restores the global $post variable to the current post in the main query. If you’re following best practices, this is the most common function you will use to reset loops. To properly use this function, place the following code after any loops with WP_Query: Here is an example of a loop using WP_Query that is reset with wp_reset_postdata(). 3 ); // Variable to call WP_Query. $the_query = new WP_Query( $args ); if ( $the_query->have_posts() ) : // Start the Loop while ( $the_query->have_posts() ) : $the_query->the_post(); the_title(); the_excerpt(); // End the Loop endwhile; else: // If no posts match this query, output this text. _e( 'Sorry, no posts matched your criteria.', 'textdomain' ); endif; wp_reset_postdata(); ?> Using wp_reset_query Using wp_reset_query() restores the WP_Query and global $post data to the original main query. You MUST use this function to reset your loop if you use query_posts() within your loop. You can use it after custom loops with WP_Query because it actually calls wp_reset_postdata() when it runs. However, it’s best practice to use wp_reset_postdata() with any custom loops involving WP_Query. query_posts() is not best practice and should be avoided if at all possible. Therefore, you shouldn’t have much use for wp_reset_query(). To properly use this function, place the following code after any loops with query_posts(). Theme Functions Functions.php can be used by both classic themes, block themes, and child themes. The functions.php file is where you add unique features to your WordPress theme. It can be used to hook into the core functions of WordPress to make your theme more modular, extensible, and functional. What is functions.php? The functions.php file behaves like a WordPress plugin, adding features and functionality to a WordPress site. You can use it to call WordPress functions and to define your own functions. The same result can be produced using either a plugin or functions.php. If you are creating new features that should be available no matter what the website looks like, it is best practice to put them in a plugin. There are advantages and tradeoffs to either using a WordPress plugin or using functions.php. A WordPress plugin: requires specific, unique header text; is stored in wp-content/plugins, usually in a subdirectory; only executes on page load when activated; applies to all themes; and should have a single purpose – for example, offer search engine optimization features or help with backups. Meanwhile, a functions.php file: requires no unique header text; is stored in theme’s subdirectory in wp-content/themes; executes only when in the active theme’s directory; applies only to that theme (if the theme is changed, the features can no longer be used); and can have numerous blocks of code used for many different purposes. Each theme has its own functions file, but only code in the active theme’s  functions.php is actually run. If your theme already has a functions file, you can add code to it. If not, you can create a plain-text file named functions.php to add to your theme’s directory, as explained below. A child theme can have its own functions.php file. Adding a function to the child functions file is a risk-free way to modify a parent theme. That way, when the parent theme is updated, you don’t have to worry about your newly added function disappearing. Although the child theme’s functions.php is loaded by WordPress right before the parent theme’s functions.php, it does not override it. The child theme’s functions.php can be used to augment or replace the parent theme’s functions. Similarly,  functions.php is loaded after any plugin files have loaded. With functions.php you can: Use WordPress hooks. For example, with the excerpt_length filter you can change your post excerpt length (from default of 55 words). Enable WordPress features with add_theme_support(). For example, turn on post thumbnails, post formats, and navigation menus. Define functions you wish to reuse in multiple theme template files. In WordPress, naming conflicts can occur when two or more functions, classes, or variables have the same name. This can cause errors or unexpected behavior in a WordPress site. It is the responsibility of both the theme developer and plugin developer to avoid naming conflicts in their respective code. Theme developers should ensure that their functions, classes, and variables have unique names that do not conflict with those used by WordPress core or other plugins. They should also prefix their function and class names with a unique identifier, such as the theme name or abbreviation, to minimize the chances of a naming conflict. Examples Below are a number of examples that you can use in your functions.php file to support various features. Each of these examples are allowed in your theme if you choose to submit it to the WordPress.org theme directory. Theme Setup A number of theme features should be included within a “setup” function that runs initially when your theme is activated. As shown below, each of these features can be added to your functions.php file to activate recommended WordPress features. It’s important to namespace your functions with your theme name. All examples below use  myfirsttheme_ as their namespace, which should be customized based on your theme name. To create this initial function, start a new function entitled myfirsttheme_setup(), like so: if ( ! function_exists( 'myfirsttheme_setup' ) ) : /** * Sets up theme defaults and registers support for various WordPress * features. * * It is important to set up these functions before the init hook so * that none of these features are lost. * * @since MyFirstTheme 1.0 */ function myfirsttheme_setup() { ... } Note: In the above example, the function myfirsttheme_setup is started but not closed out. Be sure to close out your functions. Automatic Feed Links Automatic feed links enables post and comment RSS feeds by default. These feeds will be displayed in automatically. They can be called using add_theme_support() in classic themes. This feature is automatically enabled for block themes, and does not need to be included during theme setup. add_theme_support( 'automatic-feed-links' ); Navigation Menus In classic themes, custom navigation menus allow users to edit and customize menus in the Menus admin panel, giving users a drag-and-drop interface to edit the various menus in their theme. You can set up multiple menus in functions.php. They can be added using register_nav_menus() and inserted into a theme using wp_nav_menu(), as discussed later in this handbook. If your theme will allow more than one menu, you should use an array. While some themes will not have custom navigation menus, it is recommended that you allow this feature for easy customization. register_nav_menus( array( 'primary' => __( 'Primary Menu', 'myfirsttheme' ), 'secondary' => __( 'Secondary Menu', 'myfirsttheme' ) ) ); Each of the menus you define can be called later using wp_nav_menu() and using the name assigned (i.e. primary) as the theme_location parameter. In block themes, you use the navigation block instead. Load Text Domain Themes can be translated into multiple languages by making the strings in your theme available for translation. To do so, you must use  load_theme_textdomain(). For more information on making your theme available for translation, read the internationalization section. load_theme_textdomain( 'myfirsttheme', get_template_directory() . '/languages' ); Post Thumbnails Post thumbnails and featured images allow your users to choose an image to represent their post. Your theme can decide how to display them, depending on its design. For example, you may choose to display a post thumbnail with each post in an archive view. Or, you may want to use a large featured image on your homepage. This feature is automatically enabled for block themes, and does not need to be included during theme setup. add_theme_support( 'post-thumbnails' ); Post Formats Post formats allow users to format their posts in different ways. This is useful for allowing bloggers to choose different formats and templates based on the content of the post. add_theme_support() is also used for Post Formats. This is recommended. add_theme_support( 'post-formats', array( 'aside', 'gallery', 'quote', 'image', 'video' ) ); Learn more about post formats. Theme support in block themes In block themes, HTML5 markup as well as the following theme supports are enabled automatically: add_theme_support( 'post-thumbnails' ); add_theme_support( 'responsive-embeds' ); add_theme_support( 'editor-styles' ); add_theme_support( 'automatic-feed-links' ); Initial Setup Example Including all of the above features will give you a functions.php file like the one below. Code comments have been added for future clarity. As shown at the bottom of this example, you must add the required add_action() statement to ensure the myfirsttheme_setup function is loaded. if ( ! function_exists( 'myfirsttheme_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. */ function myfirsttheme_setup() { /** * Make theme available for translation. * Translations can be placed in the /languages/ directory. */ load_theme_textdomain( 'myfirsttheme', get_template_directory() . '/languages' ); /** * Add default posts and comments RSS feed links to . */ add_theme_support( 'automatic-feed-links' ); /** * Enable support for post thumbnails and featured images. */ add_theme_support( 'post-thumbnails' ); /** * Add support for two custom navigation menus. */ register_nav_menus( array( 'primary' => __( 'Primary Menu', 'myfirsttheme' ), 'secondary' => __( 'Secondary Menu', 'myfirsttheme' ), ) ); /** * Enable support for the following post formats: * aside, gallery, quote, image, and video */ add_theme_support( 'post-formats', array( 'aside', 'gallery', 'quote', 'image', 'video' ) ); } endif; // myfirsttheme_setup add_action( 'after_setup_theme', 'myfirsttheme_setup' ); Content Width In classic themes, a content width is added to your functions.php file to ensure that no content or assets break the container of the site. The content width sets the maximum allowed width for any content added to your site, including uploaded images. In the example below, the content area has a maximum width of 800 pixels. No content will be larger than that. if ( ! isset ( $content_width) ) { $content_width = 800; } Themes that include a theme.json configuration file does not need to include the variable in functions.php. Instead, the content width is added to the layout setting in theme.json. You can learn more about using theme.json in the advanced section. Other Features There are other common features you can include in functions.php. Listed below are some of the most common features. Click through and learn more about each of these features. Custom Headers -Classic themes Sidebars (widget areas) -Classic themes Custom Background -Classic themes Title tag -Classic themes Add Editor Styles HTML5 -Classic themes Your functions.php File If you choose to include all the functions listed above, this is what your functions.php might look like. It has been commented with references to above. /** * MyFirstTheme's functions and definitions * * @package MyFirstTheme * @since MyFirstTheme 1.0 */ /** * First, let's set the maximum content width based on the theme's * design and stylesheet. * This will limit the width of all uploaded images and embeds. */ if ( ! isset( $content_width ) ) { $content_width = 800; /* pixels */ } if ( ! function_exists( 'myfirsttheme_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. */ function myfirsttheme_setup() { /** * Make theme available for translation. * Translations can be placed in the /languages/ directory. */ load_theme_textdomain( 'myfirsttheme', get_template_directory() . '/languages' ); /** * Add default posts and comments RSS feed links to . */ add_theme_support( 'automatic-feed-links' ); /** * Enable support for post thumbnails and featured images. */ add_theme_support( 'post-thumbnails' ); /** * Add support for two custom navigation menus. */ register_nav_menus( array( 'primary' => __( 'Primary Menu', 'myfirsttheme' ), 'secondary' => __( 'Secondary Menu', 'myfirsttheme' ), ) ); /** * Enable support for the following post formats: * aside, gallery, quote, image, and video */ add_theme_support( 'post-formats', array( 'aside', 'gallery', 'quote', 'image', 'video' ) ); } endif; // myfirsttheme_setup add_action( 'after_setup_theme', 'myfirsttheme_setup' ); Tools & Resources Whether you’re building your very first theme or your tenth, the following resources are meant to help ease the process. Keep in mind that there are various community tools not mentioned here as well but that still might aid in your efforts. Block themes A block theme is a type of WordPress theme built using blocks. You can read more about these themes in the Block Theme section. Create Block Theme plugin This plugin was created by various community members. This tool can create standalone block themes and child themes, depending on your needs. Here are the high-level steps: Install and activate the Create Block Theme plugin. You will also need to be running the latest version of the Gutenberg plugin. Make changes to your site design using the Customizer and Site Editor. Edit your templates using the Site Editor. For some things, you might need to edit the template files again later. In the WordPress Admin Dashboard, under Appearance there will be a new page called “Create Block Theme”. You can add the details for the theme here. These details will be used in the style.css file. Click the “Create Block Theme” button. From there, a zip file will be downloaded which will contain all the files for your theme. Theme Generator This tool was created by Carolina Nymark and it allows you to create three different types of themes to start from: No Code: for non-developers who want to start from a blank theme and build directly in the Site Editor. Empty: for developers to make their own with six templates and a theme.json with empty settings for you to complete. Basic: for developers to explore with six templates, two template parts, three block patterns, and two custom block styles alongside some initial theme.json settings. Advanced: for developers to explore with seven templates, five template parts, seven patterns, various block styles, and a more robust theme.json. It’s common to want to remove some of the examples. Comparison Chart Tool Child theme options? Template creation? Theme.json Controls Demo content Create Block Theme plugin Yes Yes No No Theme Generator No Yes Yes Yes Classic themes A classic theme is built with PHP templates, functions.php, and more. You can read more about these themes in the Classic Theme section. The _s (Underscores) starter theme is a tool for initializing and creating a classic theme. Tools WordPress Coding Standards for PHP_CodeSniffer This project is a collection of PHP_CodeSniffer rules (sniffs) that are used to validate code developed for WordPress, but can also be used when developing themes and plugins. They encompass coding style along with established best practices regarding interoperability, translatability, and security in the WordPress ecosystem, according to the official WordPress Coding Standards. WordPress Coding Standards for PHP_CodeSniffer The WPThemeReview Standards for PHP_CodeSniffer are a collection of sniffs that aim to automate the code analysis part of the Theme Review Process as much as possible using static code analysis. The WPThemeReview Standards require the WordPress Coding Standards. WPThemeReview Standards for PHP_CodeSniffer Theme Check Plugin The theme check plugin is an easy way to test your theme and make sure it’s up to spec with the latest theme review standards. With it, you can run all the same automated testing tools on your theme that WordPress.org uses for theme submissions. This allows you to resolve any issues that might come up before trying to submit your theme to the theme repository. Training material Simple Site Design and Site Editing: Part 1, Part 2, Part 3 Anatomy of a Block Theme Creating a landing page with a block theme Building a home page with a block theme Using Schema with WordPress theme.json Create a Basic Child Theme for Block Themes Find more theme lessons on learn.wordpress.org. Advanced Usage The customize API is actively developed; this page contains additional more advanced topics. Additional discussion of advanced topics cab be found by searching the archives for the #core-customize channel in Slack. Allow Non-administrators to Access the Customizer Customizer access is controlled by the customize meta capability (mapped to edit_theme_options by default), which is assigned only to administrators by default. This allows for wider use of the Customizer’s extensive capability-access options, which are built into panels, sections, and settings. Additionally, this makes it possible to allow non-administrators to use the customizer for, for example, customizing posts. This change is an important step toward expanding the scope of the Customizer beyond themes. add_panel(); $wp_customize->get_panel(); $wp_customize->remove_panel(); $wp_customize->add_section(); $wp_customize->get_section(); $wp_customize->remove_section(); $wp_customize->add_setting(); $wp_customize->get_setting(); $wp_customize->remove_setting(); $wp_customize->add_control(); $wp_customize->get_control(); $wp_customize->remove_control(); } Note: themes generally should not modify core sections and panels with the get methods, since themes should not modify core, theme-agnostic functionality. Plugins are encouraged to use these functions where necessary. Themes should not “reorganize” customizer sections that aren’t added by the theme. Settings Settings handle live-previewing, saving, and sanitization of your customizer objects. Each setting is managed by a control object. There are several parameters available when adding a new setting: $wp_customize->add_setting( 'setting_id', array( 'type' => 'theme_mod', // or 'option' 'capability' => 'edit_theme_options', 'theme_supports' => '', // Rarely needed. 'default' => '', 'transport' => 'refresh', // or postMessage 'sanitize_callback' => '', 'sanitize_js_callback' => '', // Basically to_json. ) ); Important: Do not use a setting ID that looks like widget_*, sidebars_widgets[*], nav_menu[*], or nav_menu_item[*]. These setting ID patterns are reserved for widget instances, sidebars, nav menus, and nav menu items respectively. If you need to use “widget” in your setting ID, use it as a suffix instead of a prefix, for example “ homepage_widget”. There are two primary types of settings: options and theme modifications. Options are stored directly in the wp_options table of the WordPress database and apply to the site regardless of the active theme. Themes should rarely if ever add settings of the option type. Theme mods, on the other hand, are specific to a particular theme. Most theme options should be theme_mods. For example, a custom CSS plugin could register a custom theme css setting as a theme_mod, allowing each theme to have a unique set of CSS rules without losing the CSS when switching themes then switching back. Theme_mod vs. option setting type example. It is usually most important to set the default value of the setting as well as its sanitization callback, which will ensure that no unsafe data is stored in the database. Typical theme usage: $wp_customize->add_setting( 'accent_color', array( 'default' => '#f72525', 'sanitize_callback' => 'sanitize_hex_color', ) ); Typical plugin usage: $wp_customize->add_setting( 'myplugin_options[color]', array( 'type' => 'option', 'capability' => 'manage_options', 'default' => '#ff2525', 'sanitize_callback' => 'sanitize_hex_color', ) ); Note that the Customizer can handle options stored as keyed arrays for settings using the option type. This allows multiple settings to be stored in a single option that isn’t a theme mod. To retrieve and use the values of your Customizer options, use get_theme_mod() and get_option() with the setting id: function my_custom_css_output() { echo ''; echo ''; } add_action( 'wp_head', 'my_custom_css_output'); Note that the second argument for get_theme_mod() and get_option() is the default value, which should match the default you set when adding the setting. Controls Controls are the primary Customizer object for creating UI.  Specifically, every control must be associated with a setting, and that setting will save user-entered data from the control to the database (in addition to displaying it in the live-preview and sanitizing it). Controls can be added by the Customizer Manager and provide a robust set of UI options with minimal effort: $wp_customize->add_control( 'setting_id', array( 'type' => 'date', 'priority' => 10, // Within the section. 'section' => 'colors', // Required, core or custom. 'label' => __( 'Date' ), 'description' => __( 'This is a date control with a red border.' ), 'input_attrs' => array( 'class' => 'my-custom-class-for-js', 'style' => 'border: 1px solid #900', 'placeholder' => __( 'mm/dd/yyyy' ), ), 'active_callback' => 'is_front_page', ) ); The most important parameter when adding a control is its type — this determines what type of UI the Customizer will display. Core provides several built-in control types:  elements with any allowed type (see below) checkbox textarea radio (pass a keyed array of values => labels to the choices argument) select (pass a keyed array of values => labels to the choices argument) dropdown-pages (use the allow_addition argument to allow users to add new pages from the control) For any input type supported by the html input element, simply pass the type attribute value to the type parameter when adding the control. This allows support for control types such as text, hidden, number, range, url, tel, email, search, time, date, datetime, and week, pending browser support. Controls must be added to a section before they will be displayed (and sections must contain controls to be displayed). This is done by specifying the section parameter when adding the control. Here is an example for adding a basic textarea control: $wp_customize->add_control( 'custom_theme_css', array( 'label' => __( 'Custom Theme CSS' ), 'type' => 'textarea', 'section' => 'custom_css', ) ); And here’s an example of a basic range (slider) control. Note that most browsers will not display the numeric value of this control because the range input type is designed for settings where the exact value is unimportant. If the numeric value is important, consider using the number type. The input_attrs parameter will map a keyed array of attributes => values to attributes on the input element, and can be used for purposes ranging from placeholder text to data- JavaScript-referenced data in custom scripts. For number and range controls, it allows us to set the minimum, maximum, and step values. $wp_customize->add_control( 'setting_id', array( 'type' => 'range', 'section' => 'title_tagline', 'label' => __( 'Range' ), 'description' => __( 'This is the range control description.' ), 'input_attrs' => array( 'min' => 0, 'max' => 10, 'step' => 2, ), ) ); Core Custom Controls If none of the basic control types suit your needs, you can easily create and add custom controls. Custom controls are explained more fully later in this post, but they are essentially subclasses of the base  WP_Customize_Control object that allow any arbitrary html markup and functionality that you might need. Core features several built-in custom controls that allow developers to implement rich JavaScript-driven features with ease. A color picker control can be added as follows: $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'color_control', array( 'label' => __( 'Accent Color', 'theme_textdomain' ), 'section' => 'media', ) ) ); WordPress 4.1 and 4.2 also added support for any type of multimedia content, with the Media control. The media control implements the native WordPress media manager, allowing users to select files from their library or upload new ones. By specifying the mime_type parameter when adding the control, you can instruct the media library show to a specific type such as images or audio: $wp_customize->add_control( new WP_Customize_Media_Control( $wp_customize, 'image_control', array( 'label' => __( 'Featured Home Page Image', 'theme_textdomain' ), 'section' => 'media', 'mime_type' => 'image', ) ) ); $wp_customize->add_control( new WP_Customize_Media_Control( $wp_customize, 'audio_control', array( 'label' => _( 'Featured Home Page Recording', 'theme_textdomain' ), 'section' => 'media', 'mime_type' => 'audio', ) ) ); Note that settings associated with WP_Customize_Media_Control save the associated attachment ID, while all other media-related controls (children of WP_Customize_Upload_Control) save the media file URL to the setting. More information is available on Make WordPress Core. Additionally, WordPress 4.3 introduced the WP_Customize_Cropped_Image_Control, which provides an interface for cropping an image after selecting it. This is useful for instances where a particular aspect ratio is needed. Sections Sections are UI containers for Customizer controls. While you can add custom controls to the core sections, if you have more than a few options you may want to add one or more custom sections. Use the  add_section method of the WP_Customize_Manager object to add a new section: $wp_customize->add_section( 'custom_css', array( 'title' => __( 'Custom CSS' ), 'description' => __( 'Add custom CSS here' ), 'panel' => '', // Not typically needed. 'priority' => 160, 'capability' => 'edit_theme_options', 'theme_supports' => '', // Rarely needed. ) ); You only need to include fields that you want to override the default values of. For example, the default priority (order of appearance) is typically acceptable, and most sections shouldn’t require descriptive text if your options are self-explanatory. If you do want to change the location of your custom section, the priorities of the core sections are below: Title ID Priority (Order) Site Title & Tagline title_tagline 20 Colors colors 40 Header Image header_image 60 Background Image background_image 80 Menus (Panel) nav_menus 100 Widgets (Panel) widgets 110 Static Front Page static_front_page 120 default 160 Additional CSS custom_css 200 In most cases, sections can be added with only one or two parameters being specified. Here’s an example for adding a section for options that pertain to a theme’s footer: // Add a footer/copyright information section. $wp_customize->add_section( 'footer' , array( 'title' => __( 'Footer', 'themename' ), 'priority' => 105, // Before Widgets. ) ); Panels The Customizer Panels API was introduced in WordPress 4.0, and allows developers to create an additional layer of hierarchy beyond controls and sections. More than simply grouping sections of controls, panels are designed to provide distinct contexts for the Customizer, such as Customizing Widgets, Menus, or perhaps in the future, editing posts. There is an important technical distinction between the section and panel objects. Themes should not register their own panels in most cases. Sections do not need to be nested under a panel, and each section should generally contain multiple controls. Controls should also be added to the Sections that core provides, such as adding color options to the colors Section. Also make sure that your options are as streamlined and efficient as possible; see the WordPress philosophy. Panels are designed as contexts for entire features such as Widgets, Menus, or Posts, not as wrappers for generic sections. If you absolutely must use Panels, you’ll find that the API is nearly identical to that for Sections: $wp_customize->add_panel( 'menus', array( 'title' => __( 'Menus' ), 'description' => $description, // Include html tags such as

. 'priority' => 160, // Mixed with top-level-section hierarchy. ) ); $wp_customize->add_section( $section_id , array( 'title' => $menu->name, 'panel' => 'menus', ) ); Panels must contain at least one Section, which must contain at least one Control, to be displayed. As you can see in the above example, Sections can be added to Panels similarly to how Controls are added to Sections. However, unlike with controls, if the Panel parameter is empty when registering a Section, it will be displayed on the main, top-level Customizer context, as most sections should not be contained with a panel. Custom Controls, Sections, and Panels Custom Controls, Sections, and Panels can be easily created by subclassing the PHP objects associated with each Customizer object:  WP_Customize_Control,  WP_Customize_Section, and  WP_Customize_Panel (this can also be done for WP_Customize_Setting, but custom settings are typically better implemented using custom setting types, as outlined in the next section). Here’s an example for a basic custom control: class WP_New_Menu_Customize_Control extends WP_Customize_Control { public $type = 'new_menu'; /** * Render the control's content. */ public function render_content() { ?> add_control( new WP_Customize_Color_Control( $wp_customize, // WP_Customize_Manager 'accent_color', // Setting id array( // Args, including any custom ones. 'label' => __( 'Accent Color' ), 'section' => 'colors', ) ) ); Parameters passed when adding controls are mapped to class variables within the control class, so you can add and use custom ones where certain parts of your custom object are different across different instances. When creating custom Controls, Sections, or Panels, it is strongly recommended to reference the core code, in order to fully understand the available functionality that can be overridden. Core also includes examples of custom objects of each type. This can be found in wp-includes/class-wp-customize-control.php, wp-includes/class-wp-customize-section.php, and wp-includes/class-wp-customize-panel.php. There is also a JavaScript API for each Customizer object type, which can be extended with custom objects; see the Customizer JavaScript API section for more details. Customizer UI Standards Custom customizer controls, sections, and panels should match core UI practices wherever possible. This includes relying on standards from wp-admin, such as using the .button and .button-primary classes, for example. There are also a few standards specific to the customizer (as of WordPress 4.7): White background colors are used only to indicate navigation and actionable items (such as inputs) The general #eee background color provides visual contrast against the white elements 1px #ddd borders separate navigational elements from background margins and from each other 15px of spacing is provided between elements where visual separation is desired 4px borders are used on one side of a navigation element to show hover or focus, with a color of #0073aa Customizer text uses  color: #555d66, with #0073aa for hover and focus states on navigation elements Custom Setting Types By default, the Customizer supports saving settings as options or theme modifications. But this behavior can be easily overwritten to manually save and preview settings outside of the wp_options table of the WordPress database, or to apply other custom handling. To get started, specify a type other than option or theme_mod when adding your setting (you can use pretty much any string): $wp_customize->add_setting( $nav_menu_setting_id, array( 'type' => 'nav_menu', 'default' => $item_ids, ) ); The setting will no longer be saved or previewed when its value is changed in the associated control. Now, you can use the customize_update_$setting->type and customize_preview_$setting->type actions to implement custom saving and previewing functionality. Here is an example for saving a menu item’s order property from the Menu Customizer project (the value of the setting is an ordered array of menu ids): function menu_customizer_update_nav_menu( $value, $setting ) { $menu_id = str_replace( 'nav_menu_', '', $setting->id ); // ... $i = 0; foreach( $value as $item_id ) { // $value is ordered array of item ids. menu_customizer_update_menu_item_order( $menu_id, $item_id, $i ); $i++; } } add_action( 'customize_update_nav_menu', 'menu_customizer_update_nav_menu', 10, 2 ); And here is how the same plugin implements previewing for nav menu items (note that this example requires PHP 5.3 or higher): function menu_customizer_preview_nav_menu( $setting ) { $menu_id = str_replace( 'nav_menu_', '', $setting->id ); add_filter( 'wp_get_nav_menu_items', function( $items, $menu, $args ) use ( $menu_id, $setting ) { $preview_menu_id = $menu->term_id; if ( $menu_id == $preview_menu_id ) { $new_ids = $setting->post_value(); foreach ( $new_ids as $item_id ) { $item = wp_setup_nav_menu_item( $item ); $item->menu_order = $i; $new_items[] = $item; $i++; } return $new_items; } else { return $items; } }, 10, 3 ); } add_action( 'customize_preview_nav_menu', 'menu_customizer_preview_nav_menu', 10, 2 ); JavaScript/Underscore.js-Rendered Custom Controls WordPress 4.1 also added support for rendering JavaScript-heavy and/or high-quantity controls entirely with JavaScript. This allows for more dynamic behavior, especially related to dynamically-added controls. The core Color and Media controls currently leverage this API, and all core Controls will eventually use it in the future. The PHP-based control API is not going away, but in the future most controls will likely use the new API since it provides a faster experience for users and developers. Similar APIs for JS-templated Sections and Panels were introduced WordPress 4.3; however, there remain some gaps in the ease of dynamically-creating objects in JS as of WordPress 4.7, see #30741. Registered Control Types In order to introduce a concept of having one template for multiple Customizer controls of the same type, we needed to introduce a way to register a type of control with the Customize Manager. Previously, custom control objects were only encountered when custom controls were added using WP_Customize_Manager::add_control(). But detecting added control types to render one template per type wouldn’t allow new controls to be created dynamically if no other instances of that type were loaded.  WP_Customize_Manager::register_control_type() solves this: add_action( 'customize_register', 'prefix_customize_register' ); function prefix_customize_register( $wp_customize ) { // Define a custom control class, WP_Customize_Custom_Control. // Register the class so that its JS template is available in the Customizer. $wp_customize->register_control_type( 'WP_Customize_Custom_Control' ); } All registered control types have their templates printed to the customizer by WP_Customize_Manager::print_control_templates(). Sending PHP Control Data to JavaScript While Customizer control data has always been passed to the control JS models, and this has always been able to be extended, you’re much more likely to need to send data down when working with JS templates. Anything that you would want access to in render_content() in PHP will need to be exported to JavaScript to be accessible in your control template. WP_Customize_Control exports the following control class variables by default: type label description active (boolean state) You can add additional parameters specific to your custom control by overriding WP_Customize_Control::to_json() in your custom control subclass. In most cases, you’ll want to call the parent class’ to_json() method also, to ensure that all core variables are exported as well. Here’s an example from the core color control: public function to_json() { parent::to_json(); $this->json['statuses'] = $this->statuses; $this->json['defaultValue'] = $this->setting->default; } JS/Underscore Templating Once you’ve registered your custom control class as a control type and exported any custom class variables, you can create the template that will render the control UI. You’ll override  WP_Customize_Control::content_template() (empty by default) as a replacement for WP_Customize_Control::render_content(). Render content is still called, so be sure to override it with an empty function in your subclass as well. Underscore-style custom control templates are very similar to PHP. As more and more of WordPress core becomes JavaScript-driven, these templates are becoming increasingly more common. Some sample template code in core can be found in media, revisions, the theme browser, and even in the Twenty Fifteen theme, where a JS template is used to both save the color scheme data and instantly preview color scheme changes in the Customizer. The best way to learn how these templates work is to study similar code in core and, accordingly, here is a brief example: class WP_Customize_Color_Control extends WP_Customize_Control { public $type = 'color'; // ... /** * Render a JS template for the content of the color picker control. */ public function content_template() { ?> <# var defaultValue = ''; if ( data.defaultValue ) { if ( '#' !== data.defaultValue.substring( 0, 1 ) ) { defaultValue = '#' + data.defaultValue; } else { defaultValue = data.defaultValue; } defaultValue = ' data-default-color=' + defaultValue; // Quotes added automatically. } #>

register_control_type( 'WP_Customize_Color_Control' );. The PHP-only parts of the Customize API are still fully supported and perfectly fine to use. But given long term goals for making the customizer more flexible for doing things like switching themes in the customizer without a pageload, it is strongly encouraged to use JS/Underscore templates for all custom customizer objects where feasible. The Customizer JavaScript API In WordPress 4.1, newly-expanded JavaScript APIs were introduced for all customizer objects. The entire JavaScript API is currently located in a single file, wp-admin/js/customize-controls.js, which contains models for all objects, core custom controls, and more. Preview JS and Controls JS The customizer app is currently split into two distinct areas: the customizer controls “pane” and the customize preview. The preview is currently in an iframe, meaning that all JS runs either in the controls pane or in the preview. The postMessage API is used to communicate between the preview and the controls. Most themes only implement JavaScript in the customize preview, and use it to implement instant previewing of settings via postMessage. However, JS on the controls side can be used for many things, such as dynamically showing and hiding controls based on the values of other settings, changing the previewed URL, focusing parts of the preview, and more. Here’s an example from core of controls-side JS that interacts with the preview, in this case changing the previewed URL when the page for posts changes: // Change the previewed URL to the selected page when changing the page_for_posts. wp.customize( 'page_for_posts', function( setting ) { setting.bind( function( pageId ) { pageId = parseInt( pageId, 10 ); if ( pageId > 0 ) { api.previewer.previewUrl.set( api.settings.url.home + '?page_id=' + pageId ); } }); } ); Similar logic can be used to activate UI objects based on the value of a setting. The Twenty Seventeen theme includes some useful examples for leveraging the customize JS API for improved user experience. Note that there is one JS file for the controls pane, named customize-controls.js and one file for the customize preview, named customize-preview.js. For clarity, all themes and plugins are recommended to follow this naming convention, even if customize JS is only provided in the controls or preview but not both. The rest of this page is dedicated primarily to the controls-side JS API that was built-out in WordPress 4.1. Models for Controls, Sections, and Panels As in PHP, each Customizer object type has a corresponding object in JavaScript. There are  wp.customize.Control,  wp.customize.Panel, and wp.customize.Sectionmodels, as well as  wp.customize.panel,  wp.customize.section, and``wp.customize.control collections (yes, they are singular) that store all control instances. You can iterate over panels, sections, and controls via: wp.customize.panel.each( function ( panel ) { /* ... */ } ); wp.customize.section.each( function ( section ) { /* ... */ } ); wp.customize.control.each( function ( control ) { /* ... */ } ); Relating Controls, Sections, and Panels together When registering a new control in PHP, you pass in the parent section ID: add_control( 'blogname', array( 'label' => __( 'Site Title' ), 'section' => 'title_tagline', ) ); ?> In the JavaScript API, a control’s section can be obtained predictably: id = wp.customize.control( 'blogname' ).section(); // returns title_tagline by default To get the section object from the ID, look up the section by the ID as normal: wp.customize.section( id ). You can move a control to another section using this section state as well, here moving it to the Navigation section: wp.customize.control( 'blogname' ).section( 'nav' ); Likewise, you can get a section’s panel ID in the same way: id = wp.customize.section( 'sidebar-widgets-sidebar-1' ).panel(); // returns widgets by default You can go the other way as well, to get the children of panels and sections: sections = wp.customize.panel( 'widgets' ).sections();controls = wp.customize.section( 'title_tagline' ).controls(); You can use these to move all controls from one section to another: _.each( wp.customize.section( 'title_tagline' ).controls(), function ( control ) { control.section( 'nav' ); } ); Contextual Panels, Sections, and Controls Control,  Panel, and Section instances have an active state (a wp.customize.Value instance). When the active state changes, the panel, section, and control instances invoke their respective onChangeActive method, which by default slides the container element up and down, if false and true respectively. There are also activate() and deactivate() methods now for manipulating this active state, for panels, sections, and controls. The primary purpose of these states is to show or hide the object without removing it entirely from the Customizer. wp.customize.section( 'nav' ).deactivate(); // slide up wp.customize.section( 'nav' ).activate({ duration: 1000 }); // slide down slowly wp.customize.section( 'colors' ).deactivate({ duration: 0 }); // hide immediately wp.customize.section( 'nav' ).deactivate({ completeCallback: function () { wp.customize.section( 'colors' ).activate(); // show after nav hides completely } } ); Note that manually changing the active state would only stick until the preview refreshes or loads another URL. The activate()/ deactivate() methods are designed to follow the pattern of the new expanded state. Focusing UI Objects Building upon the expand()/ collapse() methods for panels, sections, and controls, these models also support a focus() method which not only expands all of the necessary elements, but also scrolls the target container into view and puts the browser focus on the first focusable element in the container. For instance, to expand the “Static Front Page” section and focus on select dropdown for the “Front page”: wp.customize.control( 'page_on_front' ).focus() The focus functionality is used to implement autofocus: deep-linking to panels, sections, and controls inside of the customizer. Consider these URLs: …/wp-admin/customize.php?autofocus[panel]=widgets …/wp-admin/customize.php?autofocus[section]=colors …/wp-admin/customize.php?autofocus[control]=blogname This is used in WordPress core to add a link on the widgets admin page to link directly to the widgets panel within the customizer, as well as to connect visible edit shortcuts in the customize preview with the associated controls in the customize pane. Priorities When registering a panel, section, or control in PHP, you can supply a priority parameter. This value is stored in a wp.customize.Value instance for each respective Panel, Section, and Control instance. For example, you can obtain the priority for the widgets panel via: priority = wp.customize.panel( 'widgets' ).priority(); // returns 110 by default You can then dynamically change the priority and the Customizer UI will automatically re-arrange to reflect the new priorities: wp.customize.panel( 'widgets' ).priority( 1 ); // move Widgets to the top Custom Controls, Panels, and Sections When working with custom Customizer objects in JS, it is usually easiest to examine the custom objects in WordPress core to understand the code structure. See wp-admin/js/customize-controls.js, particularly the wp.customize.Panel|Section|Control models. Note several examples in the core code, particularly in the media controls, which build on each others’ functionality though object hierarchy. Tools for Improved User Experience Contextual Controls, Sections, and Panels WordPress 4.0 and 4.1 also added support for making parts of the Customizer UI be visible or hidden depending on the part of the site that the user was previewing within the Customizer preview window. A simple contextual control example would be that your theme only displays the header image and the site tagline on the front page. This is a perfect use case for the Customizer Manager’s get_ methods, as we can modify the core controls for these settings directly to make them contextual to the front page: // Hide core sections/controls when they aren't used on the current page. $wp_customize->get_section( 'header_image' )->active_callback = 'is_front_page'; $wp_customize->get_control( 'blogdescription' )->active_callback = 'is_front_page'; In this contextual control example, the theme only displays the site tagline on the front page, so the corresponding field in the Customizer is hidden when the user navigates to a different page within the preview window. The active_callback parameter for Panels, Sections, and Controls takes a callback function name, either core or custom. This parameter can also be set when registering the object for objects that you add. Here’s an example from the Twenty Fourteen Theme: $wp_customize->add_section( 'featured_content', array( 'title' => __( 'Featured Content', 'twentyfourteen' ), 'description' => //... 'priority' => 130, 'active_callback' => 'is_front_page', ) ); In the previous example, is_front_page is used directly. But for more complex logic, such as checking if the current view is a page (or even a specific page, by id), custom functions can be used (see #30251 for details on why this is needed). If you don’t need to support PHP 5.2, this can be done inline: 'active_callback' => function () { return is_page(); } PHP 5.2 support is as simple as creating a named function and referencing it with the active_callback parameter: //... 'active_callback' => 'prefix_return_is_page'; //... function prefix_return_is_page() { return is_page(); } Within Custom Controls, Sections, and Panels, there is also an option to override the  active_callback function directly within the custom Customizer object class: class WP_Customize_Greeting_Control extends WP_Customize_Control { // ... function active_callback() { return is_front_page(); } } Finally, there is a filter that can be used to override all other  active_callback behavior: // Hide all controls without a description when previewing single posts. function title_tagline_control_filter( $active, $control ) { if ( '' === $control->description ) { $active = is_singular(); } return $active; } add_filter( 'customize_control_active', 'title_tagline_control_filter', 10, 2 ); Note that the  active_callback API works exactly the same for all of the Customizer object types (Controls, Sections, and Panels). As an added bonus, sections will automatically be hidden if all of the controls within them are contextually hidden, and the same works for panels. Selective Refresh: Fast, Accurate Updates Introduced in WordPress 4.5, Selective Refresh updates in the Customizer “preview” only refresh areas whose associate settings are changed. By only updating the elements that have changed, it’s much faster and less disruptive than a full-iframe refresh. Some other benefits, as noted in Selective Refresh In The Customizer, are: Don’t Repeat Yourself (DRY) logic Accurate preview update Association between parts of the preview and associated settings and controls, along with visible edit shortcuts as of WordPress 4.7 The logic in pure-JavaScript postMessage updates is duplicated. The JavaScript in the Customizer must mirror the PHP that produces the markup, or take shortcuts to approximate it. But Selective Refresh is DRY as there’s no duplication of JavaScript and PHP. An Ajax request retrieves the new markup for the preview. And because of this Ajax call, the refresh is accurate. It uses the filters that can alter the markup. It shows the same result that appears on the front end. Additionally, selective refresh partials provide an association between areas of the preview and their corresponding settings. The customizer leverages this relationship to provide visible edit shortcuts that help users find controls associated with a particular part of their site. In the future the partials API could expand to facilitate editing settings directly within the preview and to include a structured JS API for previewing settings with partials. For these reasons, all settings are strongly recommended to leverage selective refresh transport for improved user experience, with the option of providing additional JavaScript-based transport to further enhance setting previewing. Registering Partials Setting previews need to opt-in to use Selective Refresh by registering the necessary partials. In this example, largely taken from the them Twenty Sixteen, Selective Refresh is added for the blogdescription setting by adding a partial with the same name. function foo_theme_customize_register( WP_Customize_Manager $wp_customize ) { $wp_customize->selective_refresh->add_partial( 'blogdescription', array( 'selector' => '.site-description', 'container_inclusive' => false, 'render_callback' => function() { bloginfo( 'description' ); }, ) ); } add_action( 'customize_register', 'foo_theme_customize_register' ); If the settings argument is not supplied, it defaults to be the same as the partial ID, in the same way as the settings for controls default to the control ID. Here are some of the key arguments for partials: Variable Type Description settings array Setting IDs associated with the partial. selector string Targets the element(s) in the page markup to be refreshed. container_inclusive boolean If true, a refresh replaces the entire container. Otherwise, it only replaces the container’s children. Defaults to false. render_callback function Produces the markup to be rendered on refresh. fallback_refresh bool Whether or not a full page refresh should occur if the partial is not found in the document. Selective Refresh JavaScript Events These fire on wp.customize.selectiveRefresh: partial-content-rendered When the placement is rendered. As mentioned, JavaScript-driven widgets can re-build on this event. render-partials-response When data is returned, after a request for partial rendering. The server filters this data with ‘customize_render_partials_response’. partial-content-moved When a widget has moved in its sidebar. As shown above, JavaScript-driven widgets can refresh on this event. widget-updated When the WidgetPartial is refreshed with its renderContent method. sidebar-updated When a sidebar has a widget that’s refreshed or updated. Or when a sidebar’s widgets are sorted, using reflowWidgets(). Widgets: Opting-In To Selective Refresh Both themes and widgets need to opt-in to use Selective Refresh. All core widgets and themes have already enabled this. Theme Support In Sidebars In order to allow partial refreshes of widgets in a theme’s sidebars: add_theme_support( 'customize-selective-refresh-widgets' ); Important: Selective refresh for widgets requires that the theme include a before_widget/ after_widget wrapper element around each widget that contains the widget’s ID. Such wrappers are the default when you register_sidebar(). For example: function example_widgets_init() { register_sidebar( array( 'name' => esc_html__( 'Sidebar', 'example' ), 'id' => 'sidebar-1', 'description' => esc_html__( 'Add widgets here.', 'example' ), 'before_widget' => '
', // <= Key for selective refresh. 'after_widget' => '
', 'before_title' => '

', 'after_title' => '

', ) ); } add_action( 'widgets_init', 'example_widgets_init' ); Widget Support Even if a theme supports Selective Refresh, widgets also have to opt-in. All core widgets have already enabled it. Here’s an example widget adding support for Selective Refresh: class Foo_Widget extends WP_Widget { public function __construct() { parent::__construct( ‘foo’, __( 'Example', 'bar-plugin' ), array( 'description' => __( ‘An example widget’, ‘bar-plugin’ ), 'customize_selective_refresh' => true, ) ); if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) { add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); } } ... Line 9 above enables Selective Refresh: 'customize_selective_refresh' => true, Line 13 above ensures the widget’s stylesheet always appears in Customizer sessions. Adding the widget won’t cause a full-page refresh to retrieve the styling: if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) { add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); } See Implementing Selective Refresh Support for Widgets. JavaScript-Driven Widget Support Widgets that rely on JavaScript for their markup will need additional steps, as shown in Implementing Selective Refresh Support for Widgets: Enqueue any JavaScript files based on is_customize_preview(), as shown above for stylesheets. Add a handler for the partial-content-rendered event, and refresh the widget as needed: wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) { // logic to refresh } ); If the widget includes an iframe, add a handler to refresh the partial: wp.customize.selectiveRefresh.bind( 'partial-content-moved', function( placement ) { // logic to refresh, perhaps conditionally } Using PostMessage For Improved Setting Previewing The Customizer automatically handles previewing all settings out-of-the-box. This is done by silently reloading the entire preview window, with settings being filtered by PHP in that Ajax call. While this works just fine, it can be very slow since the entire front-end must be reloaded for every single setting change. Selective Refresh improves this experience by refreshing only the elements that have changed, but due to the Ajax call, there is still a delay in seeing the changes in the preview. To further improve the user experience, the Customizer offers an API for managing setting changes directly in JavaScript, allowing for truly-live previewing. The below images show a comparison of a Custom CSS option that leverages this technology, called postMessage, versus the standard refresh option: Custom CSS setting in the Customizer with the postMessage setting transport. Custom CSS setting in the Customizer with the default refresh setting transport. To use postMessage, first set the transport parameter to postMessage when adding your setting. Many themes also modify core settings such as the title and tagline to leverage postMessage by modifying the transport property of those settings: $wp_customize->get_setting( 'blogname' )->transport = 'postMessage'; $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; Once the setting’s transport is set to postMessage, the setting will no longer trigger a refresh of the preview when its value changes. To implement the JavaScript to update the setting within the preview of the front-end, first create and enqueue a JavaScript file: function my_preview_js() { wp_enqueue_script( 'custom_css_preview', 'path/to/file.js', array( 'customize-preview', 'jquery' ) ); } add_action( 'customize_preview_init', 'my_preview_js' ); Your JavaScript file should look something like this: ( function( $ ) { wp.customize( 'setting_id', function( value ) { value.bind( function( to ) { $( '#custom-theme-css' ).html( to ); } ); } ); wp.customize( 'custom_plugin_css', function( value ) { value.bind( function( to ) { $( '#custom-plugin-css' ).html( to ); } ); } ); } )( jQuery ); Note that you don’t necessarily need to be great with JavaScript to use postMessage – most of the code is boilerplate. The types of settings that benefit most from postMessage transport require simple JS changes such as using jQuery’s .html() or .text() methods, or swapping out a class on the or another element to trigger a different set of CSS rules. Doing this, or simplifying the instant preview logic with fully-accurate changes updating with selective refresh, the user experience can be fast without duplicating all of the PHP logic in JS. Setting Validation WordPress 4.6 includes new APIs related to validation of Customizer setting values. The Customizer has had sanitization of setting values since it was introduced. Sanitization involves coercing a value into something safe to persist to the database: common examples are converting a value into an integer or stripping tags from some text input. As such, sanitization is a lossy operation. With the addition of setting validation: All modified settings are validated up-front before any of them are saved. If any setting is invalid, the Customizer save request is rejected: a save thus becomes transactional with all the settings left dirty to try saving again. (The Customizer transactions proposal is closely related to setting validation here.) Validation error messages are displayed to the user, prompting them to fix their mistake and try again. Sanitization and validation are also both part of the REST API infrastructure via WP_REST_Request::sanitize_params() and WP_REST_Request::validate_params(), respectively. A setting’s value goes through validation before it goes through sanitization. For more information on the validation behavior, and additional code examples, see the feature announcement post. Validating Settings in PHP Just as you can supply a sanitize_callback when registering a setting, you can also supply a validate_callback arg: $wp_customize->add_setting( 'established_year', array( 'sanitize_callback' => 'absint', 'validate_callback' => 'validate_established_year' ) ); function validate_established_year( $validity, $value ) { $value = intval( $value ); if ( empty( $value ) || ! is_numeric( $value ) ) { $validity->add( 'required', __( 'You must supply a valid year.' ) ); } elseif ( $value < 1900 ) { $validity->add( 'year_too_small', __( 'Year is too old.' ) ); } elseif ( $value > gmdate( 'Y' ) ) { $validity->add( 'year_too_big', __( 'Year is too new.' ) ); } return $validity; } Just as supplying a sanitize_callback arg adds a filter for customize_sanitize_{$setting_id}, so too supplying a validate_callback arg will add a filter for customize_validate_{$setting_id}. Assuming that the WP_Customize_Setting instances apply filters on these in their validate methods, you can add this filter if you need to add validation for settings that have been previously added. The validate_callback and any customize_validate_{$setting_id} filter callbacks take a WP_Error instance is its first argument (which initially is empty of any errors added), followed by the $value being sanitized, and lastly the WP_Customize_Setting instance that is being validated. Custom setting classes can also override the validate method of the setting class directly. Client-side Validation If you have a setting that is previewed purely via JavaScript (and the postMessage transport without selective refresh), you should also add client-side validation. Otherwise, any validation errors will persist until a full refresh happens or a save is attempted. Client-side validation must not take the place of server-side validation, since malicious users could bypass the client-side validation to save an invalid value if corresponding server-side validation is not in place. There is a validate method available on the wp.customize.Setting JS class (actually, the wp.customize.Value base class). Its name is a bit misleading, as it actually behaves very similarly to the WP_Customize_Setting::sanitize() PHP method, but it can be used to both sanitize and validate a value in JS. Note that this JS runs in the context of the Customizer pane not the preview, so any such JS should have customize-controls as a dependency (not customize-preview) and enqueued during the customize_controls_enqueue_scripts action. Some example JS validation: wp.customize( 'established_year', function ( setting ) { setting.validate = function ( value ) { var code, notification; var year = parseInt( value, 10 ); code = 'required'; if ( isNaN( year ) ) { notification = new wp.customize.Notification( code, {message: myPlugin.l10n.yearRequired} ); setting.notifications.add( code, notification ); } else { setting.notifications.remove( code ); } code = 'year_too_small'; if ( year < 1900 ) { notification = new wp.customize.Notification( code, {message: myPlugin.l10n.yearTooSmall} ); setting.notifications.add( code, notification ); } else { setting.notifications.remove( code ); } code = 'year_too_big'; if ( year > new Date().getFullYear() ) { notification = new wp.customize.Notification( code, {message: myPlugin.l10n.yearTooBig} ); setting.notifications.add( code, notification ); } else { setting.notifications.remove( code ); } return value; }; } ); Notifications Notifications provide user feedback, typically based on the value of a control’s setting. An error notification is added to a setting’s notifications collection when a setting’s validation routine returns a WP_Error instance. Each error added to a PHP WP_Error instance is represented as a wp.customize.Notification in JavaScript: A WP_Error‘s code is available as notification.code in JS. A WP_Error‘s message is available as notification.message in JS. Note that if there are multiple messages added to a given error code in PHP they will be concatenated into a single message in JS. A WP_Error‘s data is available as notification.data in JS. This is useful to pass additional error context from the server to the client. Any time that a WP_Error is returned from a validation routine on the server it will result in a wp.customize.Notification being created with a type property of “error”. While setting non-error notifications from PHP is not currently supported (see #37281), you can also add non-error notifications with JS as follows: wp.customize( 'blogname', function( setting ) { setting.bind( function( value ) { var code = 'long_title'; if ( value.length > 20 ) { setting.notifications.add( code, new wp.customize.Notification( code, { type: 'warning', message: 'This theme prefers title with max 20 chars.' } ) ); } else { setting.notifications.remove( code ); } } ); } ); You can also supply “info” as a notification’s type. The default type is “error”. Custom types may also be supplied, and the notifications can be styled with CSS selector matching notice.notice-foo where “foo” is the type supplied. A control may also override the default behavior for how notifications are rendered by overriding the wp.customize.Control.renderNotifications method. 404 Pages A 404 page is important to add into your theme in case a user stumbles upon a page that doesn’t exist or hasn’t been created yet. It is also important that your 404 page gives your visitors a way to arrive at the right place. These next few steps will help you build a useful 404 page for your WordPress theme. Creating the 404.php file As the 404.php file is used on a page not found error, the first step is to create a file named 404.php and add it to your WordPress theme folder. Often times a great starting point for your 404.php is your index.php Add a file header To use your theme’s header.php file, open your 404.php file. At the top, add a comment describing what the file is and make sure you include your theme’s header. For example: /** * The template for displaying 404 pages (Not Found) */ get_header(); Adding the body to your 404 Page To make the 404 page functional you have to add the body content to your template: Example:

This example is from the Twenty Thirteen theme that comes with WordPress. This adds some text and a search form in the 404 page. You can to add your own text to make your 404 page look better. Adding the footer and sidebar. The final step when creating a 404 page is to add the footer. You may also add a sidebar if you want. Example: get_sidebar(); get_footer(); Now you have a functional 404 page with a search form and some text in case a user stumbles upon the wrong page. Once you make sure the 404.php has been uploaded, you can test your 404 page. Just type a URL address for your website that doesn’t exist. You can try something like http://example.com/fred.php. This is sure to result in a 404 error unless you actually have a PHP file called fred.php. Accessibility A WordPress theme should generate pages everyone can use, including those who cannot see or use a mouse. To create an accessible theme, you need to have knowledge of web standards for HTML, CSS, and JavaScript. You also need to be aware of best practices for web accessibility and have basic knowledge of the Web Content Accessibility Guidelines, WCAG. To succeed in making your theme accessible, accessibility should be considered from the start of your project as part of your project specification. By making the right decisions from the beginning, you can avoid making last-minute adjustments that can be costly, time-consuming, and of low quality. The Accessibility Team have documented many of the best practices and resources for development, design, and content in their handbook. In the handbook, you can also learn about testing for accessibility. The Themes Team has two sets of accessibility requirements for themes submitted to the WordPress.org theme directory: Requirements for all themes Requirements for using the “‘accessibility-ready” tag The accessibility-ready requirements are based on WCAG but adapted for WordPress themes. “Accessibility Ready” does not mean that the theme meets the WCAG guidelines AA-level. It means that the theme reaches the minimum standards that the theme review team has set. The four principles of web accessibility Although web accessibility can be a complex subject, it boils down to only four principles. The content must be: Perceivable Content must be available to all. It should not depend on a specific device or browser or require a specific physical sense, such as sight or sound. Operable Users must be able to move around and operate the final site effectively, whether they’re using a keyboard, a mouse, or assistive technology. Understandable The content should be presented in a manner that supports understanding, including supporting the construction of a mental model of the site for screen reader users. Similarly, the site’s operation (navigation menus, links, forms, etc.) should be easily understandable. Building a theme that incorporates known user behaviors (such as underlining links within the main content area) helps in this respect. Robust Content must be equally available across a wide range of user agents. Disabled users may employ a range of hardware and software solutions (commonly referred to as “assistive technology”) to allow them to access the Web—including screen reading & voice recognition software, braille readers, and switches (single input devices). A theme designed with these four principles in mind eases the creation of an accessible website. Perceivable and understandable Color and color contrast Having a high enough color contrast between background and foreground colors makes content easier to read. Theme authors must ensure that all background/foreground color contrasts for plain content text are within the level AA contrast ratio (4.5:1) specified in the Web Content Accessibility Guidelines (WCAG) 2.0 for color luminosity. Color may not be the only way to identify controls, links in text content, or error messages. If there is no text decoration on linked text, there must be a 3:1 color contrast between the link text color and the surrounding non-link text color, in addition to the other color contrast requirements. There are separate requirements for links in content (links surrounded by other text) and links that are grouped together in navigation menus. Groups of links do not need to be underlined if it is obvious from the context that they are links. Best practices for the use of color Accessibility-ready requirements for contrast Resizable text Users have many means to resize text, including browser settings. All content and functionality must remain available if the user resizes the text up to 200% of the original size. Resizing text must not trigger multi-dimensional scrolling Enlarged texts must not cause overflows or overlaps To avoid these issues, it is recommended to: Use a relative unit for font sizes and line heights Test your theme in different browsers and screen widths Best practices for font sizes and resized text Images Non-decorative images Example: A header image that replaces header text Images used in place of text for navigation Non-decorative images included with  img elements should have an  alt attribute. Decorative images Example: A header image used alongside header text Images and icons accompanying navigation text links When possible, decorative images should be included using CSS. Decorative images included with  img elements should have an empty  alt attribute: alt="". Decorative images that are displayed together with text should be hidden from screen readers using  aria-hidden. Featured images The alt attribute for featured images is defined in the media library. If the featured image is unlinked, the alt attribute should describe the image If the featured image is linked to a post, the alt text should use the post title Best practices for alt texts Accessibility-ready requirement for images Operable Controls All controls must be usable with the keyboard on all screen sizes, including but not limited to buttons for opening and closing menus, submenus, any type of dialog, modal, and popup. Best practices for dialog modals Accessibility-ready requirements for controls Headings Headings are an essential way of breaking content down into logical sub-sections. Heading levels indicate the importance of the content. Screen reader users can scan the contents of a page by reading the headings, and navigating to a section via its heading. That is why it is important that headings are used logically and not for presentational purposes. Best practices for Heading structure in theme development Accessibility-ready requirements for headings Links Link text Link text should describe the resource that it links to, even when the text is read out of context. Some assistive software scans a page for links and presents them to the user as a simple list. In these situations, all the links will be read out of context. So it is important the text used in a link is descriptive. Bare URLs should never be used as links. Good link texts Accessibility-ready requirements: Avoiding repetitive Read More or Continue reading texts. Link underlining and styling link states Generally speaking, links should be underlined if they are outside navigation menus and lists. Using color alone to distinguish links is insufficient as not everyone can perceive color. Users must be able to tell if a text is linked if they are hovering over a link, if they are focusing on a link, and if they have already visited a link. The default browser style for the focus state should not be removed unless replaced with a more visible focus style. Accessibility-ready requirements for underlining links in the content Skip Links Skip links provide a mechanism that enables users to navigate directly to content or navigation on entering any given page. For example, a skip to content link might allow a user to skip a header area and go directly to the main content. In designs with multiple menus and content areas, multiple skip links can be used: Skip to the main navigation Skip to content Skip to footer These links may be positioned off-screen initially using an appropriate CSS technique but should remain available to screen reader users and be visible on focus for sighted keyboard navigators. Best practices for Skip Links Accessibility-ready requirements for Skip Links Forms Provide enough information for the user to be able to complete the form. All input fields must have a label. A placeholder text is not a replacement for the label. Input fields must also have a visible focus style. Group controls that belong together, for example, a set of related checkboxes, with a fieldset and legend. Make sure that the tab order in the form matches the visual order of the input fields: Do not move focus unexpectedly or skip past input fields. On Form Submission Post-submission responses—including any error messages—should always be perceivable. If possible, error messages should be generated at the top of the post-submission page so the user is immediately aware of any issues. Error messages should also make sense when read out of context. Best practices for forms Accessibility-ready requirements for forms Robust Use the HTML element that is the best match for the content. Use buttons when performing an action, and links when navigating to a part of a page or a new page. The content of the website should be available even if the user disables both JavaScript and CSS Establish which browsers your theme supports and test your theme with these browsers on different screen sizes Resources Make WordPress Accessible is the official blog for the WordPress Accessibility Team, dedicated to making WordPress accessible to as many people as possible. Anyone can join in the discussions, bug scrubs, and meetings. You can also follow discussions via email or subscribe to feeds for posts and comments. Test for web accessibility Development tools WCAG 2 (external link) Changelog: Rewritten and published 2023-02-16 Administration Menus This is no longer the recommended way to work with theme options. The Customizer API is the recommended way to give more control and flexibility to your users Theme authors might need to provide a settings screen, so users can customize how their theme is used or works. The best way to do this is to create an administration menu item that allows the user to access that settings screen from all the administration screens. Function Reference Menu Pages add_menu_page() add_object_page() add_utility_page() remove_menu_page() Sub-menu Pages add_submenu_page() remove_submenu_page() WordPress Administration Menus add_dashboard_page() add_posts_page() add_media_page() add_links_page() add_pages_page() add_comments_page() add_theme_page() add_plugins_page() add_users_page() add_management_page() add_options_page() Every Plot Needs a Hook To add an administration menu, there are three things you need to do: Create a function that contains the menu-building code. Register the above function using the admin_menu action hook – or network_admin_menu, if you are adding a menu for the Network. Create the HTML output for the screen, displayed when the menu item is clicked. Most developers overlook the second step in this list. You can’t simply call the menu code. You need to put it inside a function, and then register this function. Here is a simple example of these three steps described. This will add a sub-level menu item under the Settings top-level menu. When selected, that menu item will show a very basic screen.
';
}
In this example, the function 
my_menu() adds a new item to the Settings administration menu via the 
add_options_page() function.
Note: Note that the add_action() call in Step 2 registers the my_menu() function under the admin_menu hook. Without that, add_action() call, a PHP error for undefined function will be thrown. Finally, the 
add_options_page() call refers to the 
my_options() function which contains the actual page to be displayed (and PHP code to be processed) when someone clicks the menu item.
These steps are described in more detail in the sections below. Remember to enclose the creation of the menu and the page in functions, and use the 
admin_menu hook to get the whole process started at the right time.
Determining Location for New Menus
Before creating a new menu, first decide if the menu should be a top-level menu, or a sub-level menu item. A top-level menu displays as new section in the administration menus and contains sub-level menu items. This means a sub-level menu item is a member of an existing top-level menu.
It is rare that a theme would require the creation of a new top-level menu. If the theme introduces an entirely new concept to WordPress and needs many screens to do it, then that theme may warrant a new top-level menu. Adding a top-level menu should only be considered if you really need multiple, related screens to make WordPress do something it was not originally designed to accomplish. Examples of new top-level menus might include job management or conference management. Please note that, with the native post type registration, WordPress automatically creates top-level menus to manage this kind of features.
If the creation of a top-level menu is not necessary, you need to decide under what top-level menu to place your new sub-level menu item. As a point of reference, several themes add sub-level menu items underneath existing WordPress top-level menus.
Use this guide of the WordPress top-level menus to determine the correct location for your sub-level menu item:
Dashboard – information central for your site and include the Updates option for updating WordPress core, plugins, and themes.
Posts – displays tools for writing posts (time oriented content).
Media – uploading and managing your pictures, videos, and audio.
Links – manage references to other blogs and sites of interest.
Pages – displays tools for writing your static content called pages.
Comments – controlling and regulation reader to responses to posts.
Appearance – displays controls for manipulation of theme/style files, sidebars, etc.
Plugins – displays controls dealing with plugin management, not configuration options for a plugin itself.
Users – displays controls for user management.
Tools – manage the export, import, and even backup of blog data.
Settings – displays plugin options that only administrators should view.
Network Admin – displays plugin options that are set on the Network. Instead of 
admin_menu, you should use 
network_admin_menu (see also Create A Network)
Top-Level Menus
If you have decided your theme requires a brand-new top-level menu, the first thing you’ll need to do is to create one with the 
add_menu_page() function. Note: skip to Sub-Level Menus if you don’t need a top-level menu.
Parameter values:
page_title – the text to be displayed in the title tags of the page when the menu is selected.
menu_title – the on-screen name text for the menu.
capability – the capability required for this menu to be displayed to the user. When using the Settings API to handle your form, you should use 
manage_options here as the user won’t be able to save options without it. User levels are deprecated and should not be used here.
menu_slug – the slug name to refer to this menu by (should be unique for this menu). Prior to Version 3.0 this was called the file (or handle) parameter. If the function parameter is omitted, the 
menu_slug should be the PHP file that handles the display of the menu page content.
function – the function that displays the page content for the menu page.
icon_url – the URL to the icon to be used for this menu. This parameter is optional.
position – the position in the menu order this menu should appear. By default, if this parameter is omitted, the menu will appear at the bottom of the menu structure. To see the current menu positions, use 
print_r( $GLOBALS[ 'menu' ] ) after the menu has loaded.
Sub-Level Menus – once your top-level menu is defined, or you have chosen to use an existing WordPress top-level menu, you are ready to define one or more sub-level menu items using the 
add_submenu_page() function.
Sub-Level Menus
If you want your new menu item to be a sub-menu item, you can create it using the 
add_submenu_page() function instead.
Parameter values:
parent_slug – the slug name for the parent menu, or the file name of a standard WordPress admin file that supplies the top-level menu in which you want to insert your sub-menu, or your plugin file if this sub-menu is going into a custom top-level menu. Examples:
Dashboard – 
add_submenu_page('index.php', ...)
Posts – 
add_submenu_page('edit.php', ...)
Media – 
add_submenu_page('upload.php', ...)
Links – 
add_submenu_page('link-manager.php', ...)
Pages – 
add_submenu_page('edit.php?post_type=page', ...)
Comments – 
add_submenu_page('edit-comments.php', ...)
Custom Post Types – 
add_submenu_page('edit.php?post_type=your_post_type', ...)
Appearance – 
add_submenu_page('themes.php', ...)
Plugins – 
add_submenu_page('plugins.php', ...)
Users – 
add_submenu_page('users.php', ...)
Tools – 
add_submenu_page('tools.php', ...)
Settings – 
add_submenu_page('options-general.php', ...)
page_title – text that will go into the HTML page title for the page when the submenu is active.
menu_title – the text to be displayed in the title tags of the page when the menu is selected.
capability – the capability required for this menu to be displayed to the user. User levels are deprecated and should not be used here.
menu_slug – for existing WordPress menus, the PHP file that handles the display of the menu page content. For sub-menus of a custom top-level menu, a unique identifier for this sub-menu page.
function – the function that displays the page content for the menu page. Technically, as in the 
add_menu_page function, the function parameter is optional, but if it is not supplied, then WordPress will basically assume that including the PHP file will generate the administration screen, without calling a function.
Using Wrapper Functions
Since most sub-level menus belong under the Settings, Tools, or Appearance menus, WordPress supplies wrapper functions that make adding a sub-level menu items to these top-level menus easier. Note that the function names may not match the names seen in the admin UI as they have changed over time:
Dashboard

' . __( 'Test Settings', 'menu-test' ) . '

';
}
// mt_tools_page() displays the page content for the Test Tools sub-menu.
function mt_tools_page() {
	echo '

' . __( 'Test Tools', 'menu-test' ) . '

';
}
// mt_toplevel_page() displays the page content for the custom Test Top-Level menu.
function mt_toplevel_page() {
	echo '

' . __( 'Test Top-Level', 'menu-test' ) . '

';
}
// mt_sublevel_page() displays the page content for the first sub-menu of the custom Test Toplevel menu.
function mt_sublevel_page() {
	echo '

' . __( 'Test Sub-Level', 'menu-test' ) . '

';
}
// mt_sublevel_page2() displays the page content for the second sub-menu of the custom Test Top-Level menu.
function mt_sublevel_page2() {
	echo '

' . __( 'Test Sub-Level 2', 'menu-test' ) . '

';
}
Sample Menu Page
Note: See the Settings API for information on creating settings pages.
The previous example contains several dummy functions, such as 
mt_settings_page(), as placeholders for actual page content. Let’s expand on them. What if you wanted to create an option called 
mt_favorite_color that allows the site owner to type in their favorite color via a Settings page? The 
mt_options_page() function will need to output a data entry form on the screen, as well as to process the entered data.
Here is a function that does this:

		
' . __( 'Menu Test Settings', 'menu-test' ) . ''; ?>

My Plugin is not configured yet. Please do it now.
'; } function my_options() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( __( 'You do not have sufficient permissions to access this page.' ) ); } echo '
'; echo 'Here is where the form would go if I actually had options.'; echo '
';
}
Resources
Top Level Menu discussion on wp-hackersAdmin Menu Editor Plugin

Block theme accessibility
Block themes support accessibility and simplify the process for adding accessibility.
Landmark
Group, Template part, and Query blocks can become a landmark. There are two ways to create landmark.
Using block markup
”tagName":"header” creates header landmark.

Using site editor HTML element under Advanced section in the Block panel provides the following landmark options. HTML element under Advanced section in the Block panel provides the following landmark options.
Function Reference get_attachment_template() : Retrieve path of attachment template in current or parent template. Custom Post Type Template Files The WordPress theme system supports custom templates for custom post types. Custom templates for the single display of posts belonging to custom post types have been supported since WordPress Version 3.0 and the support for custom templates for archive displays was added in Version 3.1. Custom Post Type – Template Hierarchy WordPress will work through the template hierarchy and use the template file it comes across first. So if you want to create a custom template for your acme_product custom post type, a good place to start is by copying the single.php file, saving it as single-acme_product.php and editing that. However if you don’t want to create custom template files, WordPress will use the files already present in your theme, which would be archive.php and single.php and index.php files. Single posts and their archives can be displayed using the single.php and archive.php template files respectively, single posts of a custom post type will use single-{post_type}.php and their archives will use archive-{post_type}.php and if you don’t have this post type archive page you can pass BLOG_URL?post_type={post_type} where {post_type} is the $post_type argument of the register_post_type() function. So for the above example, you could create single-acme_product.php and archive-acme_product.php template files for single product posts and their archives. Alternatively, you can use the is_post_type_archive() function in any template file to check if the query shows an archive page of a given post types(s), and the post_type_archive_title() to display the post type title. Custom Post Type templates single-{post-type}.php The single post template used when a visitor requests a single post from a custom post type. For example, single-acme_product.php would be used for displaying single posts from a custom post type named acme_product. archive-{post-type}.php The archive post type template is used when visitors request a custom post type archive. For example, archive-acme_product.php would be used for displaying an archive of posts from the custom post type named acme_product. The archive.php template file is used if the archive-{post-type}.php is not present. index.php The index.php is used if a specific query template ( single-{post-type}.php, single.php, archive-{post-type}.php, archive.php, search.php) for the custom post type is not present. Function Reference register_post_type() : Registers a post type. is_post_type_archive() : Checks if the query for an existing post type archive page. post_type_archive_title() : Display or retrieve title for a post type archive. Page Templates Page templates are a specific type of template file that can be applied to a specific page or groups of pages. As of WordPress 4.7 page templates support all post types. For more details how to set a page template to specific post types see example below. Since a page template is a specific type of template file, here are some distinguishing features of page templates: Page templates are used to change the look and feel of a page. A page template can be applied to a single page, a page section, or a class of pages. Page templates generally have a high level of specificity, targeting an individual page or group of pages. For example, a page template named  page-about.php is more specific than the template files page.php or index.php as it will only affect a page with the slug of “about.” If a page template has a template name, WordPress users editing the page have control over what template will be used to render the page. Uses for Page Templates Page templates display your site’s dynamic content on a page, e.g., posts, news updates, calendar events, media files, etc. You may decide that you want your homepage to look a specific way, that is quite different to other parts of your site. Or, you may want to display a featured image that links to a post on one part of the page, have a list of latest posts elsewhere, and use a custom navigation. You can use page templates to achieve these things. This section shows you how to build page templates that can be selected by your users through their admin screens. For example, you can build page templates for: full-width, one-column two-column with a sidebar on the right two-column with a sidebar on the left three-column Page Templates within the Template Hierarchy When a person browses to your website, WordPress selects which template to use for rendering that page. As we learned earlier in the Template Hierarchy, WordPress looks for template files in the following order: Page Template — If the page has a custom template assigned, WordPress looks for that file and, if found, uses it. page-{slug}.php — If no custom template has been assigned, WordPress looks for and uses a specialized template that contains the page’s slug. page-{id}.php — If a specialized template that includes the page’s slug is not found, WordPress looks for and uses a specialized template named with the page’s ID. page.php — If a specialized template that includes the page’s ID is not found, WordPress looks for and uses the theme’s default page template. singular.php — If page.php is not found, WordPress looks for and uses the theme’s template used for a single post, irregardless of post type. index.php — If no specific page templates are assigned or found, WordPress defaults back to using the theme’s index file to render pages. There is also a WordPress-defined template named  paged.php. It is not used for the page post-type but rather for displaying multiple pages of archives. Page Templates Purpose & User Control If you plan on making a custom page template for your theme, you should decide a couple of things before proceeding: Whether the page template will be for one specific page or for any page; and What type of user control you want available for the template. Every page template that has a template name can be selected by a user when they create or edit a page. The list of available templates can be found at Pages > Add New > Attributes > Template. Therefore, a WordPress user can choose any page template with a template name, which might not be your intention. For example, if you want to have a specific template for your “About” page, it might not be appropriate to name that page template “About Template” as it would be globally available to all pages (i.e. the user could apply it to any page). Instead, create a single use template and WordPress will render the page with the appropriate template, whenever a user visits the “About” page. Conversely, many themes include the ability to choose how many columns a page will have. Each of these options is a page template that is available globally. To give your WordPress users this global option, you will need to create page templates for each option and give each a template name. Dictating whether a template is for global use vs. singular use is achieved by the way the file is named and whether or not is has a specific comment. Sometimes it is appropriate to have a template globally available even if it appears to be a single use case. When you’re creating themes for release, it can be hard to predict what a user will name their pages. Portfolio pages are a great example as not every WordPress user will name their portfolio the same thing or have the same page ID and yet they may want to use that template. File Organization of Page Templates As discussed in Organizing Theme Files, WordPress can recognize page templates stored in the theme’s root folder or in a first-level subdirectory of the theme folder. The page-templates/ folder is a common convention for organizing global page templates, but it is not required. Page templates can also be stored in other first-level subdirectories, such as templates/ or page_templates/. Nested subdirectories, such as pages/templates/, are not supported for page templates. Note: A specialized page template file, meaning one created for a single specific page, cannot be stored in a subfolder. If you are using a Child Theme, the specialized page template also cannot be stored in the parent theme’s folder. Creating Custom Page Templates for Global Use Sometimes you’ll want a template that can be used globally by any page, or by multiple pages.  Some developers will group their templates with a filename prefix, such as  page_two-columns.php Important! Do not use page- as a prefix, as WordPress will interpret the file as a specialized template, meant to apply to only one page on your site. For information on theme file-naming conventions and filenames you cannot use, see reserved theme filenames. A quick, safe method for creating a new page template is to make a copy of  page.php and give the new file a distinct filename. That way, you start off with the HTML structure of your other pages and you can edit the new file as needed. To create a global template, write an opening PHP comment at the top of the file that states the template’s name. It’s a good idea to choose a name that describes what the template does as the name is visible to WordPress users when they are editing the page. For example, you could name your template Homepage, Blog, or Portfolio. This example from the TwentyFourteen theme creates a page template called Full Width Page: Edit screen in your admin dashboard. On the right hand side under attributesyou’ll see template.  This is where users are able to access your global page templates. The select list has a maximum width of 250px, so longer names may be cut off. Creating a Custom Page Template for One Specific Page As mentioned in the Template Hierarchy page, you can create a template for a specific page.  To create a template for one specific page, copy your existing page.php file and rename it with your page’s slug or ID: page-{slug}.php page-{ID}.php For example: Your About page has a slug of ‘about’ and an ID of 6. If your active theme’s folder has a file named  page-about.php or  page-6.php, then WordPress will automatically find and use that file to render the About page. To be used, specialized page templates must be in your theme’s folder (i.e. /wp-content/themes/my-theme-name/ ). Creating page templates for specific post types By default, a custom page template will be available to the “page” post type. To create a page template to specific post types, add a line under the template name with the post types you would like the template to support. Example: A specialized template ( page-{slug}.php or  page-{ID}.php) also gets the  page-template-default class rather than its own body class. When using a custom page template, the class  page-template will print, along with a class naming the specific template. For example, if your custom page template file is named as follows: Then then rendered HTML generated will be as follows: Notice the page-template-my-custom-page-php class that is applied to the body tag. Page Template Functions These built-in WordPress functions and methods can help you work with page templates: get_page_template() returns the path of the page template used to render the page. wp_get_theme()->get_page_templates() returns all custom page templates available to the currently active theme ( get_page_templates() is a method of the WP_Theme class). is_page_template() returns true or false depending on whether a custom page template was used to render the page. get_page_template_slug() returns the value of custom field _wp_page_template ( null when the value is empty or “default”).If a page has been assigned a custom template, the filename of that template is stored as the value of a custom field named  '_wp_page_template' (in the  wp_postmeta database table). (Custom fields starting with an underscore do not display in the edit screen’s custom fields module.) Partial and Miscellaneous Template Files Introduction Not all template files generate the entire content that will be rendered by the browser. Some template files are pulled in by other template files such as comments.php, header.php, footer.php, sidebar.php and content-{$slug}.php. You’ll walk through each of these template files to get an understanding of the purpose and how to build them. Header.php The header.php file does exactly what you would expect.  It contains all the code that the browser will render for the header. This is a partial template file because unless a different template file calls the template tag, get_header(), the browser will not render the contents of this file. Often sites have the same header regardless of the page or post you’re on.  However, some sites have slight variations such as a secondary navigation or different banner image depending on the page. Your header.php file can handle all these variations if you use conditional tags. Almost all themes have a header.php file as the functionality and maintainability of this file pretty much demands its creation. Below is an example of a header.php found in the twenty fifteen theme. class="no-js"> >
Some of the code may look a little daunting at first, but if we break it down, it becomes simple enough. After the opening commment, the head is created. The template tag wp_head() pulls in all of our styles and any scripts that would appear in the head rather than the footer that we enqueued in our functions.php file. Next, the body is opened and a mix of HTML and PHP are present. You can see some conditional tags in the site branding div that tweak a little bit of what is shown based on the page the user is on. Then the site navigation is pulled in. Lastly, the main site-content div is opened which will be closed most likely in the footer.php file. One important template tag to note is body_class() found in the opening body tag. This is a super handy tag that makes styling your theme a lot easier by giving your body classes depending on the template file and other settings being used. Footer.php Much like the header.php file the footer.php is a very common template file that most themes utilize. The code in the footer.php file will not be rendered unless another template file pulls in the footer.php with get_footer() template tag.  Similarly to headers, you can make variations of footers using conditional tags. Often developers will put widgetized areas in the footer so that the end user can easily drop and drag different content types into the footer. Here is an example of a footer.php file from the Twenty Fifteen theme.
404.php When users try to visit a page on your website that doesn’t exist they’ll be directed to your index.php page unless you’ve created a 404.php template.  It’s a good idea to have some sort of message that the explains the page is missing or no longer available.  Creating this template helps keep the visual aspects of your theme consistent and provides your end users with helpful information. Here is an example of a 404.php template file from the twenty fifteen theme.
Comments.php The comments.php file handles exactly what you would expect, comments. This is a partial template that is pulled into other template files to display comments that users leave on a page or post. Several different pages and posts show comments so it makes sense to have one file that can be pulled in when needed. The code involved in creating comments is expanded upon on the comment template page. Sidebar.php A lot of themes utilize sidebars to display widgets.  For a sidebar to work in a theme it must be registered and then a template file for the sidebar must be created.  You’ll learn more about registering sidebars in a later chapter. Sidebar files often have conditional statements and the is_active_sidebar( 'sidebar-name' ) function in them to ensure a widget is in use within the sidebar so that empty HTML isn’t added to a page unnecessarily. Here is an example of a sidebar template file from the twenty fifteen theme. Notice at the bottom the sidebar is pulled in using . Now whatever, widgets are put into that sidebar will display on the page that is using this pulling in this template.
Content-{$slug}.php Many theme developers break their template files into small bite sized pieces.  They’ll often put wrappers and page architecture elements in template files like page.php, home.php, comments.php etc but then they put the code displaying the content of those pages in another template file. Enter content-{$slug}.php: common examples would be content-page.php, content-post.php, content-portfolio.php, content-none.php.  These are not file names that WordPress recognizes and will interpret a certain way, rather they are a common approach to display specific types of content. For example, often on blog posts you want to display the author’s name, the date of the post, and possibly the category of the post.  You’d also likely have links to previous and next posts. That information wouldn’t be appropriate on a regular page. Similarly on a portfolio page you would likely have a featured image or gallery you would want to display in a way differently than say a blog post’s or page’s featured images. You’ll want to use the get_template_part() template tag to pull in the content-{$slug}.php file. To pull in your content-page.php file you would call get_template_part( 'content', 'page' ); Here is twenty fifteen’s example of a content-page.php template file.
>
', '' ); ?>
'', 'link_before' => '', 'link_after' => '', 'pagelink' => '' . __( 'Page', 'twentyfifteen' ) . ' %', 'separator' => ', ', ) ); ?>
', '' ); ?>
Post Template Files There are many template files that WordPress uses to display the Post post type. Any content dealing with a blog or its posts are within the Post post type. Index.php index.php will display Post post types if there is no other template file in place. As stated in many places, every theme must have an index.php file to be valid. Many basic themes can get away with just using the index.php to display their Post post types, but the use cases given above would justify creating other template files. Often you will want unique content structure or layout depending on what is being displayed. There are many templates you can use to customize content structure based on the context within the site. The two most notable post template files are home.php and single.php which display a feed of posts and a single post respectively. Home.php When a static front page is used and the site has a page defined for the blog list the home.php file is used for the designated blog list page. Use of this template is encouraged over creating a custom page template because blog pagination on a custom page template will not work properly. If there is no home.php in the theme index.php will be used instead. Single.php It’s good sense to build as simply as possible in your template structure and not make more templates unless you have real need for them. Therefore, most theme developers don’t create a single-post.php file because single.php is specific enough. For the most part, all themes should have a single.php. Below is an example of a single.php file from the theme Twenty Fifteen.
' ' . '' . __( 'Next post:', 'twentyfifteen' ) . ' ' . '%title', 'prev_text' => ' ' . '' . __( 'Previous post:', 'twentyfifteen' ) . ' ' . '%title', ) ); // End the loop. endwhile; ?>
In the code example above you can see the header is pulled in with get_header() then there are a two html tags. Next the Loop starts and the template tag get_template_part( 'content'``, get_post_format()); pulls in the appropriate content by determining the post type with get_post_format(). Next, comments are pulled in with the template tag comments_template(). Then there is some pagination. Lastly, the content divs are closed and then footer is pulled in with get_footer(). Singular.php WordPress Version 4.3 added singular.php that comes in the hierarchy after single.php for posts, page.php for pages, and the variations of each. This template follows the rules of is_singular() and is used for a single post, regardless of post type. Themes that used the same code for both of those files (or included one in the other) can now simplify down to the one template. Archive.php Unless a developer includes meta data with permalinks in their templates, the archive.php will not be used. Meta data is information tied to the post. For example the date something was posted on, the author, and any categories, tags, or taxonomies used for the post are all examples of meta data. When a visitor to a website clicks on the meta data, the archive.php will render any posts associated with that piece of meta data. For example, if a visitor clicks on the name of an author, the archive.php will display all posts by that author. Commonly, the title of the page being displayed by archive.php will be the name of the meta data the user clicked on. So if the user clicked on the Author’s name, the page name displaying all the other author’s posts will be the Author’s name and frequently there might be an additional description about the meta data. Here is a code example from Twenty Fifteen on their archive.php file. This snippet is the only piece of code that makes the archive.php file different from a home.php or index.php file. ``` ``` Author.php and Date.php Author.php and date.php are more specific archive type files. If you need a refresher check out where they fit within the template heirarchy. Generally, archive.php will suffice for most themes’ needs and you won’t need to create these templates. Author.php If you are building a theme designed for multiple authors, it might make sense to build an author.php template. In the author.php template you could provide more information about an author, their gravatar, pull in their social media sites, and then all posts written by them. This would be a step up from relying just on the archive.php file. Additionally, you can build specific author.php files for individual author’s by using their author ID or nicename. For example, say John Doe is the head author for a site with many guest authors. You may want all the guest authors’ information to display with author.php but you might build a specific author page with more information for John Doe by creating author-johndoe.php or author-3.php if his author ID is 3. Date.php Similarly, if you are building a theme directed at magazine or news websites, a date.php file might make sense to build as these websites frequently organize their articles and posts by date or issue. Additionally, you could build a day.php, month.php, or year.php if you found enough justification for it. Category.php, Tag.php, and Taxonomy.php If you need a refresher on what categories, tags, & taxonomies are you can look at their page. Often you won’t need to build out these template files. However, in an example of building a theme for food bloggers, there are some use cases for building these specific templates. In a food blogger website, the categories could be Great Restaurants, Beautiful Food, Ethnic Cuisine, and Recipes. You might want most of your blog posts to display the same way except for any blogs that are categorized as recipes, because all recipes have ingredients and instrucitons sections. Therefore, you may want to build a category-recipe.php file to display your recipe blog posts in a grid view with some of the important details about the recipe visible. Additionally, perhaps chocolate is a really important tag for the theme you’re building. It might make sense to build a tag-chocolate.php file so that you can display a specialized banner image of chocolate. Search.php Most themes have a search.php file so it is clear to users that their query went through. It is common to have some sort of header identifying the query results such as this snippet found int twenty fifteen’s theme. This code snippet pulls in the query that was searched with get_search_query(). Often search.php will only pull in the excerpt instead of the full content since the user is trying to determine if the article or page fits their search. Taxonomy Templates When a visitor clicks on a hyperlink to category, tag or custom taxonomy, WordPress displays a page of posts in reverse chronological order filtered by that taxonomy. By default, this page is generated using the index.php template file. You can create optional template files to override and refine the index.php template files. This section explains how to use and create such templates. Taxonomy Template Hierarchy WordPress display posts in the order determined by the Template Hierarchy. The category.php, tag.php, and taxonomy.php templates allow posts filtered by taxonomy to be treated differently from unfiltered posts or posts filtered by a different taxonomy. (Note: post refers to any post type – posts, pages, custom post types, etc.). These files let you target specific taxonomies or specific taxonomy terms. For example: taxonomy-{taxonomy}-{term}.php taxonomy-{taxonomy}.php tag-{slug}.php tag-{id}.php category-{slug}.php category-{ID}.php So you could format all posts in an animal taxonomy named news on a page that looks different from posts filtered in other categories. The archive.php template provides the most general form of control, providing a layout for all archives; that is, a page that displays a list of posts. Category For categories, WordPress looks for the category-{slug}.php file. If it doesn’t exist, WordPress then looks for a file for the next hierarchical level, category-{ID}.php, and so on. If WordPress fails to find any specialized templates or an archive.php template file, it reverts to the default behavior, using index.php. The category hierarchy is listed below: category-{slug}.php: For example, if the category’s slug is named “news,” WordPress would look for a file named category-news.php. category-{ID}.php: For example, if the category’s ID is “6”, WordPress would look for a file named category-6.php. category.php archive.php index.php Tag For tags, WordPress looks for the tag-{slug}.php file. If it doesn’t exist, WordPress then looks for a file for the next hierarchical level, tag-{ID}.php, and so on. If WordPress fails to find any specialized templates or an archive.php template file, it will revert to the default behavior, using index.php. The tag hierarchy is listed below: tag-{slug}.php: For example, if the tag’s slug is named “sometag,” WordPress would look for a file named tag-sometag.php. tag-{id}.php: For example, if the tag’s ID were “6,” WordPress would look for a file named tag-6.php. tag.php archive.php index.php Custom Taxonomy A custom taxonomy hierarchy works similarly to the categories and tags hierarchies described above. WordPress looks for the taxonomy-{taxonomy}-{term}.php file. If it doesn’t exist, WordPress then looks for a file for the next hierarchical level, taxonomy-{taxonomy}.php, and so on. If WordPress fails to find any specialized templates or an archive.php template file, it will revert to the default behavior, using index.php. The hierarchy for a custom taxonomy is listed below: taxonomy-{taxonomy}-{term}.php: For example, if the taxonomy is named “sometax,” and the taxonomy’s term is “someterm,” WordPress would look for a file named taxonomy-sometax-someterm.php. taxonomy-{taxonomy}.php: For example, if the taxonomy is named “sometax,” WordPress would look for a file named taxonomy-sometax.php taxonomy.php archive.php index.php Creating Taxonomy Template Files Now you’ve decided that you need to create custom designs for content based on taxonomies, where do you start? Rather than starting from a blank file, it is good practice to copy the next file in the hierarchy, if it exists. If you’ve already created an archive.php, make a copy called category.php and modify that to suit your design needs. If you don’t have an archive.php file, use a copy of your theme’s index.php as a starting point. Follow the same procedure if you are creating any taxonomy template file. Use a copy of your archive.php, category.php, tag.php, or index.php as a starting point. Examples Now that you’ve selected the template file in your theme’s directory that you need to modify, let’s look at some examples. Adding Text to Category Pages Static Text Above Posts Suppose you want some static text displayed before the list of posts on your category page(s). “Static” is text that remains the same, no matter which posts are displayed below, and no matter which category is displayed. Open your file and above The Loop section of your Template file, insert the following code:

This is some text that will display at the top of the Category page.

This text will only display on an archive page displaying posts in that category. Different Text on Some Category Pages What if you want to display different text based on the category page that the visitor is using? You could add default text to the main category.php file, and create special category-{slug}.php files each with their own version of the text, but this would create lots of files in your theme. Instead, you can use conditional tags. Again, this code would be added before the loop:

This is the text to describe category A.

This is the text to describe category B.

This is some generic text to describe all other category pages, I could be left blank.

This code does the following: Checks to see if the visitor has requested Category A. If yes, it displays the first piece of text. Checks for category B if the user didn’t request category A. If yes, it displays the second piece of text. Displays the default text, if neither was requested. Display Text only on First Page of Archive If you have more posts than fits on one page of your archive, the category splits into multiple pages. Perhaps you want to display static text, if the user is on the first page of the results. To do this, use a PHP if statement that looks at the value of the $paged WordPress variable. Put the following above The Loop:

Text for first page of Category archive.

This code asks whether the page displayed is the first page of the archive. If it is, the text for the first page is displayed. Otherwise, the text for the subsequent pages is displayed. Modify How Posts are Displayed Excerpts vs. Full Posts You can choose whether to display full posts or just excerpts. By displaying excerpts, you shorten the length of your archive page. Open your file and find the loop. Look for: the_content() And replace it with: the_excerpt() And if your theme is displaying excerpts but you want to display the full content, replace the_excerpt with the_content. Comment Template WordPress displays comments in your theme based on the settings and code in the comments.php file within your WordPress theme. Simple comments loop // Get only the approved comments $args = array( 'status' => 'approve', ); // The comment Query $comments_query = new WP_Comment_Query(); $comments = $comments_query->query( $args ); // Comment Loop if ( $comments ) { foreach ( $comments as $comment ) { echo '

' . $comment->comment_content . '

'; } } else { echo 'No comments found.'; } The comments.php template contains all the logic needed to pull comments out of the database and display them in your theme. Before we explore the template file you’ll want to know how to pull in the partial template file on the appropriate pages such as single.php. You’ll wrap the comment template tag in a conditional statement so comments.php is only pulled in if it makes sense to do. // If comments are open or we have at least one comment, load up the comment template. if ( comments_open() || get_comments_number() ) : comments_template(); endif; Another comments.php Example Here’s an example of the comments.php template included with the Twenty Thirteen theme:

' . get_the_title() . '' ); ?>

    'ol', 'short_ping' => true, 'avatar_size' => 74, ) ); ?>
1 && get_option( 'page_comments' ) ) : ?>

Breaking down the comments.php The above comments.php can be broken down to the below parts for better understanding. Template Header Comments Title Comment Listing Comment Pagination Comments are closed message. The End Template Header This template begins by identifying the template. Finally, there’s a test to see if there are comments associated with this post.
Comments Title Prints out the header that appears above the comments. Uses the _nx() translation function so other developers can provide alternative language translations.

' . get_the_title() . '' ); ?>

Comment Listing The following snippet creates an ordered listing of comments using the wp_list_comments() function.
    'ol', 'short_ping' => true, 'avatar_size' => 74, ) ); ?>
Comment Pagination Checks to see if there are enough comments to merit adding comment navigation and, if so, create comment navigation. 1 && get_option( 'page_comments' ) ) : ?> Comments are closed message. If comments aren’t open, displays a line indicating that they’re closed.

The End This section ends the comments loop, includes the comment form, and closes the comment wrapper.
Comments Pagination If you have a lot of comments (which makes your page long), then there are a number of potential benefits to paginating your comments. Pagination helps improve page load speed, especially on mobile devices. Enabling comments pagination is done in two steps. Enable paged comments within WordPress by going to Settings > Discussion , and checking the box “Break comments into pages” . You can enter any number for the “top level comments per page”. Open your comments.php template file and add the following line where you want the comment pagination to appear. Alternative Comment Template On some occasions you may want display your comments differently within your theme. For this you would build an alternate file (ex. short-comments.php) and call it as follows: tag or stylesheets via the or