2

I have a custom rewrite rule which rewrites /wp-content/themes/my-theme/manifest.json to /index.php?manifest=true. This generates some JSON code for progressive web app functionality, and generally works great.

On a multisite install, however, the manifest loads correctly, but still sends a 404 header. I verified that this specific theme does work fine with a normal WordPress site, but in a multisite install, it always seems to send the 404 header.

enter image description here

Some notes:

  • I've tried using status_header(200), and header("HTTP/1.1 200 OK") manually, but neither of those make a difference
  • I've tried setting $wp->is_404 to false, but that does nothing
  • I've flushed the permalinks, but that does nothing

Rewrite Rule PHP:

// set up rewirte rules for PWA functionality
function fvpd_pwa_rewrite_rules() {
    add_rewrite_endpoint("manifest", EP_NONE);
    add_rewrite_rule(substr(parse_url(get_template_directory_uri(), PHP_URL_PATH), 1) . "/manifest\.json$", "index.php?manifest=true", "top");
}
add_action("init", "fvpd_pwa_rewrite_rules");

manifest.json PHP:

// construct a manifest when the user visits {theme_folder}/manifest.json
function fvpd_construct_manifest() {
    if (get_query_var("manifest")) {
        header("Content-Type: application/json");

        $name             = fvpd_get_field("full_name", "pwa");
        $short_name       = fvpd_get_field("short_name", "pwa");
        $background_color = fvpd_get_field("background_color", "pwa");
        $theme_color      = fvpd_get_field("theme_color", "pwa");

        $manifest = array(
            "start_url"        => "/",
            "display"          => "standalone",
            "name"             => $name ? $name : "Fox Valley Park District - DEV",
            "short_name"       => $short_name ? $short_name : "FVPD",
            "background_color" => $background_color ? $background_color : "#E58F1A",
            "theme_color"      => $theme_color ? $theme_color : "#E58F1A",
            "icons"            => array(
                array(
                    "src"   => get_theme_file_uri("assets/media/android/splash-icon-512x512.png"),
                    "type"  => "image/png",
                    "sizes" => "512x512",
                ),
                array(
                    "src"   => get_theme_file_uri("assets/media/android/launcher-icon-192x192.png"),
                    "type"  => "image/png",
                    "sizes" => "192x192",
                ),
                array(
                    "src"   => get_theme_file_uri("assets/media/android/launcher-icon-144x144.png"),
                    "type"  => "image/png",
                    "sizes" => "144x144",
                ),
                array(
                    "src"   => get_theme_file_uri("assets/media/android/launcher-icon-96x96.png"),
                    "type"  => "image/png",
                    "sizes" => "96x96",
                ),
                array(
                    "src"   => get_theme_file_uri("assets/media/android/launcher-icon-72x72.png"),
                    "type"  => "image/png",
                    "sizes" => "72x72",
                ),
                array(
                    "src"   => get_theme_file_uri("assets/media/android/launcher-icon-48x48.png"),
                    "type"  => "image/png",
                    "sizes" => "48x48",
                ),
            ),
        );

        echo json_encode($manifest); exit;
    }
}
add_action("wp", "fvpd_construct_manifest");

URL in questions:

https://www.foxvalleyparkdistrict.org/wp-content/themes/fox-valley-park-district/manifest.json

This does not affect my other custom rewrite, which points /offline/ to load a custom template.

https://www.foxvalleyparkdistrict.org/offline/

Why is the 404 header being sent, and how can I fix it?


UPDATE 1:

I tried some of the advice below, but to no avail. I do have some additional information that may help, however. I tested changing the rewrite to /manifest.json instead of /wp-content/themes/my-theme/manifest.json, and that actually worked! This gave me an idea, and so I tried the following:

| URL                        | Status | Folder Exists | WordPress Folder |
|:--------------------------:|:------:|:-------------:|:----------------:|
| /manifest.json             | 200    | N/A           | N/A              |
| /wp-admin/manifest.json    | 404    | true          | true             |
| /wp-content/manifest.json  | 404    | true          | true             |
| /wp-includes/manifest.json | 404    | true          | true             |
| /cgi-bin/manifest.json     | 403    | true          | false            |
| /custom/manifest.json      | 200    | false         | false            |
| /custom/manifest.json      | 200    | true          | false            |

It seems that if the rewrite is returning a 404 header only when set to an existing WordPress folder. My suspicion is that the rewrite engine is partially ignoring rules to /wp-* folders.

I may end up just keeping the rewrite at /manifest.json, but that creatures a problem if in the future we where to set up additional sites like https://example.com/second-site/, although that could probably be fixed by rewriting to the WordPress root instead of the server root.

UPDATE 2: .htaccess contents is visible here: https://gist.github.com/JacobDB/1531b75c8b8c79117516019225bb7732

  • Would each user get a unique manifest.json file? Or is it the same manifest.json file going out to everyone and if so, how often is that data changing? – ChristopherJones Jun 13 at 14:58
  • 1
    It's one manifest for everyone that visits the site, but it's editable by the admins -- they can change the color or name in the back-end. – JacobTheDev Jun 14 at 16:25
  • @JacobTheDev are you using nginx or apache? If it's Apache, please paste your .htaccess file here. Also, let me know if you are allowed to ssh into your server. – filipecsweb Jun 17 at 16:01
  • Using apache, added a link to my .htaccess. I don't have SSH access directly, but I may be able to get it if it's absolutely necessary. – JacobTheDev Jun 17 at 18:56
  • FYI, the original URL to the manifest.json in you question is working for me. – Nathan Powell Jun 17 at 19:56
1
+50

Basically, you are doing one thing wrong, which is actually having a file named manifest.json inside /wp-content/themes/your-theme.

So, first, delete your file /wp-content/themes/your-theme/manifest.json.

Then, in your functions.php file you can have your rewrite rule as:

function fvpd_pwa_rewrite_rules() {
    add_rewrite_endpoint( "manifest", EP_NONE );
    add_rewrite_rule( substr( parse_url( get_template_directory_uri(), PHP_URL_PATH ), 1 ) . "/manifest.json/?$", "index.php?manifest=true", "top" );
}

add_action( "init", "fvpd_pwa_rewrite_rules" );

And your json content as:

// construct a manifest when the user visits {theme_folder}/manifest.json
function fvpd_construct_manifest() {
    if ( get_query_var( "manifest" ) ) {
        $name             = fvpd_get_field( "full_name", "pwa" );
        $short_name       = fvpd_get_field( "short_name", "pwa" );
        $background_color = fvpd_get_field( "background_color", "pwa" );
        $theme_color      = fvpd_get_field( "theme_color", "pwa" );

        $manifest = array(
            "start_url"        => "/",
            "display"          => "standalone",
            "name"             => $name ? $name : "Fox Valley Park District - DEV",
            "short_name"       => $short_name ? $short_name : "FVPD",
            "background_color" => $background_color ? $background_color : "#E58F1A",
            "theme_color"      => $theme_color ? $theme_color : "#E58F1A",
            "icons"            => array(
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/splash-icon-512x512.png" ),
                    "type"  => "image/png",
                    "sizes" => "512x512",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-192x192.png" ),
                    "type"  => "image/png",
                    "sizes" => "192x192",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-144x144.png" ),
                    "type"  => "image/png",
                    "sizes" => "144x144",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-96x96.png" ),
                    "type"  => "image/png",
                    "sizes" => "96x96",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-72x72.png" ),
                    "type"  => "image/png",
                    "sizes" => "72x72",
                ),
                array(
                    "src"   => get_theme_file_uri( "assets/media/android/launcher-icon-48x48.png" ),
                    "type"  => "image/png",
                    "sizes" => "48x48",
                ),
            ),
        );

        wp_send_json( $manifest );
    }
}

add_action( "wp", "fvpd_construct_manifest" );

Notice the usage of the WordPress function wp_send_json() which handles for you necessary headers, json converting, etc.

Make sure you flush your permalinks and test the URL which will be something like http://localhost/wp-content/themes/your-theme/manifest.json.

If the above still doesn't solve your issue it means you are also having trouble setting your web server correctly, NGINX or APACHE, following WordPress standards.

  • Thanks, this is a lot of good information! I made these changes, but I'm still having trouble. I updated my question with the results of more tests, as well as details on my current theory. Would appreciate your thoughts! EDIT: Also, there is no manifest.json in my theme folder. – JacobTheDev Jun 17 at 14:34
  • Accepted this, even though it doesn't technically solve my problem. You provided good information as to improving the code, and got me thinking about alternate paths, so that's good enough for me. I ended up just rewriting /manifest.json instead of the full theme path, which does the trick, although ideally I'd still like to get it to work within the theme folder. – JacobTheDev Jun 19 at 15:45
  • @JacobTheDev we're kind of out of options here regarding WordPress related solutions. I know the feeling, and considering this issue is not related to a horrible plugin, your problem is really about Apache. Do you have a .htaccess inside your theme folder? Or inside any other directories that are not the root web dir? – filipecsweb Jun 19 at 16:01
  • @JacobTheDev considering you have access to your files in your server, you could try the following just to see whether it works or not: Copy the original .htaccess file contents by visiting yoursite.com/wp-admin/network/setup.php. Backup your current .htaccess file and overwrite it with the original content you copied previously. Flush your permalinks, just in case, and test if you can access your manifest using the theme directory. – filipecsweb Jun 19 at 16:09
0

I ran into a similar issue some time back. I came up with an answer that does not fix the 404 issue, but takes a different approach in solving the issue, assuming your content of this json file is not set per user.

Rather than having PHP run inside of that json file and changing the header of the file to reflect as much, why not have a manifest.php file sit next and write the manifest.json file for you:

themes/fox-valley-park-district/
  \__ manifest.php
  \__ manifest.json

Do all the work laid out above in your php file and remove the add_action hook call in there. Maybe your php file looks like like:

<?php
  function fvpd_construct_manifest() {

    // Compile what you need

    return $manifest_output;
  }

  $manifest_json_file = 'manifest.json';
  $json_data = fvpd_construct_manifest();
  $json_data_encoded = json_encode($json_data);

  // You may need to deal with permission issues on that .json file
  file_put_contents(__DIR__ .'/'.$manifest_json_file, $json_data_encoded);

And then run a cron to hit that manifest.php. Again, it's a different approach and answer, but does not answer the specific 404 question. If I am way off here....I'd be happy to remove the answer.

Hope it helps, Good luck!!

  • Interesting solution, if I don't get anything that truly solves the problem, I may accept this one. Thanks! – JacobTheDev Jun 14 at 16:24
0

I think you just have a typo. Changing the following made this work for me on multisite.

Try changing this:

    add_rewrite_rule(substr(parse_url(get_template_directory_uri(), PHP_URL_PATH), 1) . "/manifest\.json$", "index.php?manifest=true", "top");

to this:

    add_rewrite_rule(substr(parse_url(get_template_directory_uri(), PHP_URL_PATH), 1) . "/manifest.json", "index.php?manifest=true", "top");
  • I'd like to know if this was tested and works. Seems simple, but like I said, I think this was the problem all along. – Nathan Powell Jun 17 at 14:57
-1

I think that's because .json is considered to be a "static file". Which means PHP isn't triggered with the request. This kind of routing likely needs to occur at a server level.

  • Can you elaborate on "This kind of routing likely needs to occur at a server level"? I'm not sure what you mean by that. – JacobTheDev Jun 14 at 16:26
  • Use .htaccess or apache/nginx configs – Michael Ecklund Jun 16 at 14:24
  • PHP is triggered for sure. I got this working. See my answer above. – Nathan Powell Jun 17 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.