Skip to content

Serve static content

Small amounts of static content can be served from a WordPress environment. A static file (e.g., *.html, *.txt ) can be added to a directory within an application’s GitHub repository. This method should be used sparingly for files that are small in size.

Static files that are added to an application’s GitHub repository are web-accessible at a URL with a corresponding path underneath /wp-content/. For example, a file that is added to a site’s /themes directory in the GitHub repository will be accessible at a URL similar to:
https://example.com/wp-content/themes/file.html

Note

If a static file is added to the root of the GitHub repository, it will not deploy as expected. The file must be added within one of the supplied directories in the WordPress skeleton codebase, usually within a site’s theme directory.

Depending on the use case for a static file, there may be a requirement for the file to be web-accessible at a specific URL path structure other than a path underneath /wp-content/. To meet this requirement, a custom URL path to access the file can be created by adding a rewrite rule.

Rewrite rules can be useful for serving common static files at custom URL paths including:

  • .well-known/apple-developer-merchantid-domain-association
  • .well-known/apple-app-site-association

Limitations

  • Rewrite rules for serving static files at custom URL paths cannot be applied to files with the extensions .css, .jpg.jpeg, .gif, .png, .swf, .ico.
  • Rewrite rules cannot be applied to static file URLs that include the directory path /wp-content/uploads/. Requests for any file within /wp-content/uploads/ are always directed to the VIP File System and can never be redirected or rewritten with PHP.

JavaScript resource files

Serving a JavaScript (JS) resource file from within an application’s wpcomvip GitHub repository at a custom URL path has additional requirements:

  • The JS resource file must have a .js file extension.
  • The allowed characters in the JS file name are limited to: A–Z a–z _ -.

If a JavaScript resource file meets all of the above requirements—and a rewrite rule has been added—root level requests for the file are automatically routed to PHP .

As an example, service workers are a common JavaScript resource file that must be available at a root level URL path. A service worker uses the Web Worker API to run JavaScript in a background thread. Because JavaScript is executed in a single thread, offloading resource-intensive tasks to a service worker, simulating a second thread, can speed up site performance and offer native-app-like features (such as in-browser push notifications). Service workers are becoming more common as Google has defined them as a key part of Progressive Web Apps.

Example of a URL path that can be routed to PHP

This example file name and file path for a service worker meets all of the above requirements and can be routed automatically to PHP with an added rewrite rule:
https://example.com/service-worker.js

Examples of URL paths that cannot be routed to PHP

These example file paths and file names do not meet the requirements and therefore cannot route to PHP:

  • https://example.com/service-worker-123.js
  • https://example.com/service-worker-v1
  • https://example.com/subdir/service-worker.js

Serve a static file at a custom URL path with a rewrite rule

A static file in an application’s GitHub repository can be served from a custom URL path by adding a rewrite rule with the add_rewrite_rule() WordPress function. The first argument added to add_rewrite_rule() is a regular expression (regex) to match against the requested URL. Any characters added to this regex other than a-z A-Z 0-9 must be escaped with a backslash (\) in order for the rewrite rule to work as expected.

The steps in the example below explain how to serve an ads.txt static file at a custom path, but the instructions can be adapted to serve other static file types at custom URL paths.

The ads.txt specification is an IAB-approved text file for preventing unauthorized sales of inventory. To work as expected, the ads.txt file must be located on a site’s root domain. Though it is possible to configure an ads.txt with a plugin (e.g. Ads.txt Manager), the instructions below explain how to accomplish this without a plugin and with code instead.

  1. Commit the ads.txt file to the application’s active theme directory.
  2. Add a rewrite rule for the file to be accessible at a custom URL.
    In this code example, a rewrite rule is added for the ads.txt file to be served at the site’s root domain: https://example.com/ads.txt
/themes/my-active-theme/functions.php
/**
 * Register the rewrite rule for /ads.txt request.
 */
function my_theme_adstxt_rewrite() {
    add_rewrite_rule( '^ads\.txt$', 'index.php?my_theme_adstxt=true', 'top' );
}
add_action( 'init', 'my_theme_adstxt_rewrite', 10 );
 
/**
 * Filter the list of public query vars in order to allow the WP::parse_request
 * to register the query variable.
 *
 * @param array $public_query_vars The array of public query variables.
 *
 * @return array
 */
function my_theme_adstxt_query_var( $public_query_vars ) {
    $public_query_vars[] = 'my_theme_adstxt';
    return $public_query_vars;
}
add_filter( 'query_vars', 'my_theme_adstxt_query_var', 10, 1 );
 
/**
 * Hook the parse_request action and serve the ads.txt when custom query variable is set to 'true'.
 *
 * @param WP $wp Current WordPress environment instance
 */
function my_theme_adstxt_request( $wp ) {
    if ( isset( $wp->query_vars['my_theme_adstxt'] ) && 'true' === $wp->query_vars['my_theme_adstxt'] ) {
        /*
         * Set proper content-type as per specifications provided by these guides :
         * https://iabtechlab.com/ads-txt/
         *
         * The HTTP Content-type should be ‘text/plain’, and all other Content-types should be treated
         * as an error and the content ignored.
         */
        header( 'Content-Type: text/plain' );
 
        // The code expects an existing ads.txt file in the root of your active theme.
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- The ads.txt spec requires and expects plain text, so no escaping needed.
        echo file_get_contents( get_stylesheet_directory() . '/ads.txt' );
        exit;
    }
}
add_action( 'parse_request', 'my_theme_adstxt_request', 10, 1 );

How to flush rewrite rules

After a new rewrite rule has been added, merged, and deployed, it will not work as expected until rewrite rules have been flushed. Rewrite rules are not flushed when code is deployed to an environment; they must be flushed manually.

To flush rewrite rules:

  1. Log in to the site’s WordPress Admin dashboard.
  2. In the lefthand navigation of the WP Admin, hover over the VIP menu item.
  3. Select Rewrite Rules from the fly-out menu.
  4. Select the button labeled “Flush Rules” at the upper right of the Rewrite Rules dashboard.

As an alternative, rewrite rules can also be flushed by using VIP-CLI to run the WP-CLI command wp rewrite flush.

Last updated: July 25, 2024

Relevant to

  • WordPress