Using and Customizing WordPress Starter Content

Starter content allows themes to define suggested settings, pages, widgets, and menus on new WordPress installations. You can customize the starter content in order to best suit your theme.

Introduced with the release of WordPress 4.7, the best example that exists right now is in Twenty Seventeen’s codebase.

From a new WordPress 4.7+ installation, enter the customizer and you’ll notice:

  • The primary navigation is pre-populated with Home, About, Blog, and Contact pages
  • The front page is set to the Home page, the posts page is set to the Blog page
  • There are placeholder featured images assigned to pages
  • Starter text widgets

Twenty Seventeen customizer

Starter content will be most useful for themes that are for distribution or for sale, as opposed to a theme or site build you’re doing for a client project. You can setup your starter content in a way that will mimic your theme demo.

If you’re trying to jumpstart your own theme development on client projects, consider using scripts and WP-CLI to craft your ideal starting point after spinning up a project.

In older versions of the Roots starter theme we included theme activation functionality that offered a lot of the same features that come with WordPress starter content. It was moved to a wp-cli command and mostly forgotten about.

What’s missing

The current starter content functionality is off to a great start, but there’s a couple of key features that are currently missing:

  • Ability to reset, revert, or undo changes made to site after starter content is applied

  • Ability to apply starter content after site changes are made (in progress, see WordPress Trac ticket #38624)

There’s room for PHP frameworks to step in and make starter content easier to work with. For instance, writing HTML inside of PHP arrays for customizing starter content isn’t a developer friendly workflow.

Setting up starter content

Start out by defining the add_theme_support for starter content within the after_setup_theme hook. In Sage based themes, you can use the existing after_setup_theme hook in setup.php.

I’m going to opt for creating a new starter-content.php file to separate things and for better organization.

add_action('after_setup_theme', function () {
    add_theme_support('starter-content', [
    	// Starter content defined here
    ]);
});

Your options for starter content include:

  • options — An array of options that match up with names in the options table, such as show_on_front, page_for_posts, page_for_posts, permalink_structure, posts_per_page, etc.
  • theme_mods — An array of theme mods, same setup as options.
  • posts — An array of posts or pages. Options are limited, see the accepted arguments. Core included pages include:

    • Home, about, and contact pages with one short sentence
    • Blog and news pages
    • A homepage section page
  • widgets — An array of widgets. Core included widgets include:

    • text_business_info — Text widget with address and hours
    • text_about — Text widget with one short sentence
    • archives, calendar, categories, meta, recent-comments, recent-posts, search
  • nav_menus — An array of navigation menus with items. Core included nav menu items include page links for the core starter pages as well as social links.
  • attachments — An array of media items. Twenty Seventeen uses this to include placeholder feature images for several pages.

The example below is similar to Twenty Seventeen’s, although a bit simpler:

add_action('after_setup_theme', function () {
    add_theme_support('starter-content', [
        // Static front page set to Home, posts page set to Blog
        'options' => [
            'show_on_front' => 'page',
            'page_on_front' => '{{home}}',
            'page_for_posts' => '{{blog}}',
        ],
        // Starter pages to include
        'posts' => [
            'home',
            'about',
            'contact',
            'blog'
        ],
        // Add pages to primary navigation menu
        'nav_menus' => [
            'primary_navigation' => [
                'name' => __('Primary Navigation', 'id'),
                'items' => [
                    'home_link',
                    'page_about',
                    'page_blog',
                    'page_contact',
                ],
            ]
        ],
        // Add test widgets to footer sidebar
        'widgets' => [
            'sidebar-footer' => [
                'text_business_info',
                'search'
            ]
        ]
    ]);
});

Custom page content

Below we’re changing the content of the About page that’s provided by core. The about page content from core is:

You might be an artist who would like to introduce yourself and your work here or maybe you’re a business with a mission to describe.

Rather than a one liner, we’d like to add some additional text and a placeholder demo image.

About page starter content

add_action('after_setup_theme', function () {
    add_theme_support('starter-content', [
        'posts' => [
            'home',
            'about' => [
                'post_content' => '<p class="lead">Babybel cheese slices say cheese. Pepper jack red leicester macaroni cheese.</p><p>Cheese triangles caerphilly manchego cheese triangles fromage frais gouda melted cheese red leicester. Hard cheese port-salut caerphilly cheese slices cottage cheese fromage frais pecorino.</p><p><img src="https://unsplash.it/1600/500/?random" alt="Placeholder image"></p><blockquote class="blockquote"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p></blockquote><p><b>Cheesecake boursin cheese and wine. Ricotta swiss cheese strings fromage cheese and wine red leicester emmental croque monsieur.</b> Fondue smelly cheese red leicester lancashire when the cheese comes out everybodys happy emmental babybel when the cheese comes out everybodys happy.</p>'
            ],
            'contact',
            'blog'
        ]
    ]);
});

Don’t want to mix HTML in your PHP? Consider placing your HTML in a different file and using file_get_contents to include it.

// Grab 'About' page content from theme-name/content/pages/about.html

add_action('after_setup_theme', function () {
    add_theme_support('starter-content', [
        'posts' => [
            'home',
            'about' => [
                'post_content' => file_get_contents(get_template_directory_uri() . 'content/pages/about.html')
            ],
            'contact',
            'blog'
        ]
    ]);
});

Custom text widgets

The core provided text widgets might not be the right fit for your site, but including custom text widgets is as easy as customizing page content.

Below we’re adding a new text widget for a call to action and including it in the footer sidebar.

add_action('after_setup_theme', function () {
    add_theme_support('starter-content', [
        'widgets' => [
            'sidebar-footer' => [
                'text_cta_contact' => [
                    'text', [
                        'title' => '', // Blank title
                        'text' => '<a class="btn btn-primary" href="/contact/">Contact Us</a>'
                    ]
                ]
            ]
        ]
    ]);
});

Wait, do I even need this?

Remember, starter content is useful for themes meant for distribution as opposed to most typical client based projects.

I’ll [finally] be releasing some themes in 2017 and plan to use starter content to allow customers to get their themes setup similar to the theme demo as quickly as possible.

Based on comments on the Make WordPress Core post, the current user experience for starter content can be confusing to both developers and users.

Keep in mind that this feature is brand new and will hopefully improve in future releases as more theme authors adopt starter content.

Read the discussion on our Discourse

Subscribe to our newsletter to get the latest Roots updates, along with occasional tips on building better WordPress sites.

Looking for WordPress plugin recommendations, the newest modern WordPress projects, and general web development tips and articles?

Follow @rootswp on Twitter