Title: Serve static content
Author: WordPress VIP Documentation
Published: September 29, 2020
Last modified: October 16, 2025

---

 1. [WordPress VIP skeleton](https://docs.wpvip.com/wordpress-skeleton/)
 2. Serve static 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](https://docs.wpvip.com/wpcomvip-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](https://docs.wpvip.com/wordpress-skeleton/),
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](https://developer.wordpress.org/reference/functions/add_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`
 * An HTML file for [Google Search Console site verification](https://support.google.com/webmasters/answer/9008080?hl=en#html_verification)

## Limitations

 * Rewrite rules for serving static files at custom URL paths cannot be applied 
   to files with the extensions `.jpeg`, `.jpg`, `.gif`, `.png`, `.swf`, `.css`,`.
   js`, `.manifest`, `opensearch.xml`, `.xml`, `.webp`, `.svg`, `.ico`, `.eot`, `.
   ttf`, `.otf`, `.woff`, `.woff2`.
 * 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](https://docs.wpvip.com/vip-file-system/)
   and can never be redirected or rewritten with PHP. It is possible to use a [reverse proxy](https://docs.wpvip.com/reverse-proxy/)
   to make this redirect before the request reaches a WordPress application.

## 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](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)
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](https://developers.google.com/web/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()](https://developer.wordpress.org/reference/functions/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](https://iabtechlab.com/ads-txt/)
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](https://wordpress.org/plugins/ads-txt/)),
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

    ```lang-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:

 3. Log in to the site’s WordPress Admin dashboard.
 4. In the lefthand navigation of the WP Admin, hover over the **VIP** menu item.
 5. Select **Rewrite Rules** from the fly-out menu.
 6. 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](https://docs.wpvip.com/wp-cli-with-vip-cli/)`
[wp rewrite flush](https://developer.wordpress.org/cli/commands/rewrite/flush/)`.

Last updated: October 16, 2025