Support » Fixing WordPress » Recurring 404 error for all pages (but not posts or bbPress topics)

  • I have been tearing my hair out trying to solve an infuriating bug for the past few weeks, and after gathering as much info about this demon-bug as I can, I’m appealing to any higher powers in this forum to help me squash this. Please help…

    The problem:

    • Every 1-2 days, Pages of my WordPress site throw a 404 error.
    • This seems to affect most/all Pages, but not Posts or forum Topics.
    • The homepage, which I understand is also a Page, however, loads fine.
    • So far I have been unable to reproduce the issue on demand, but it has been reliably cropping up every 1-2 days as mentioned.

    Temporary solution: This seems to be temporarily resolved by simply clicking to Settings > Permalinks. I don’t need to actually DO anything at the permalinks settings menu, it seems that just clicking to it is somehow enough. However, the 404 errors come back again after 1-2 days.

    Solutions researched / tried so far:

    • Google searches usually suggest .htaccess edits, but I’m on an Nginx server so I’m not sure if .htaccess solutions are still relevant since Nginx supposedly doesn’t use them…?
    • Googling permalinks nginx issues suggests to modify Nginx try_files to try_files $uri $uri/ /index.php?$args;, e.g. solution #2 here. I have tried this, but it does not seem to help.
    • Disabling and enabling plugins does not seem to work, although I’m finding it difficult to definitively debug as I have to wait 1-2 days for the issue to crop up.

    Possible relevant information:

    Server setup: Linux [Ubuntu 20.04] + Nginx [1.18.0] + Mariadb [10.3.25] + PHP [7.4.3]

    I’m using the Post Name permalink structure for my posts, e.g. https://DOMAIN.com/sample-post/

    My .htaccess is as follows:

    # BEGIN WP Rocket v3.8.3
    # Use UTF-8 encoding for anything served text/plain or text/html
    AddDefaultCharset UTF-8
    # Force UTF-8 for a number of file formats
    <IfModule mod_mime.c>
    AddCharset UTF-8 .atom .css .js .json .rss .vtt .xml
    </IfModule>
    # FileETag None is not enough for every server.
    <IfModule mod_headers.c>
    Header unset ETag
    </IfModule>
    # Since we’re sending far-future expires, we don’t need ETags for static content.
    # developer.yahoo.com/performance/rules.html#etags
    FileETag None
    <IfModule mod_alias.c>
    <FilesMatch "\.(html|htm|rtf|rtx|txt|xsd|xsl|xml)$">
    <IfModule mod_headers.c>
    Header set X-Powered-By "WP Rocket/3.8.3"
    Header unset Pragma
    Header append Cache-Control "public"
    Header unset Last-Modified
    </IfModule>
    </FilesMatch>
    <FilesMatch "\.(css|htc|js|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">
    <IfModule mod_headers.c>
    Header unset Pragma
    Header append Cache-Control "public"
    </IfModule>
    </FilesMatch>
    </IfModule>
    # Expires headers (for better cache control)
    <IfModule mod_expires.c>
    	ExpiresActive on
    	ExpiresDefault                              "access plus 1 month"
    	# cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
    	ExpiresByType text/cache-manifest           "access plus 0 seconds"
    	# Your document html
    	ExpiresByType text/html                     "access plus 0 seconds"
    	# Data
    	ExpiresByType text/xml                      "access plus 0 seconds"
    	ExpiresByType application/xml               "access plus 0 seconds"
    	ExpiresByType application/json              "access plus 0 seconds"
    	# Feed
    	ExpiresByType application/rss+xml           "access plus 1 hour"
    	ExpiresByType application/atom+xml          "access plus 1 hour"
    	# Favicon (cannot be renamed)
    	ExpiresByType image/x-icon                  "access plus 1 week"
    	# Media: images, video, audio
    	ExpiresByType image/gif                     "access plus 4 months"
    	ExpiresByType image/png                     "access plus 4 months"
    	ExpiresByType image/jpeg                    "access plus 4 months"
    	ExpiresByType image/webp                    "access plus 4 months"
    	ExpiresByType video/ogg                     "access plus 4 months"
    	ExpiresByType audio/ogg                     "access plus 4 months"
    	ExpiresByType video/mp4                     "access plus 4 months"
    	ExpiresByType video/webm                    "access plus 4 months"
    	# HTC files  (css3pie)
    	ExpiresByType text/x-component              "access plus 1 month"
    	# Webfonts
    	ExpiresByType font/ttf                      "access plus 4 months"
    	ExpiresByType font/otf                      "access plus 4 months"
    	ExpiresByType font/woff                     "access plus 4 months"
    	ExpiresByType font/woff2                    "access plus 4 months"
    	ExpiresByType image/svg+xml                 "access plus 1 month"
    	ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    	# CSS and JavaScript
    	ExpiresByType text/css                      "access plus 1 year"
    	ExpiresByType application/javascript        "access plus 1 year"
    </IfModule>
    # Gzip compression
    <IfModule mod_deflate.c>
    # Active compression
    SetOutputFilter DEFLATE
    # Force deflate for mangled headers
    <IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
    SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
    RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
    # Don’t compress images and other uncompressible content
    SetEnvIfNoCase Request_URI \
    \.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?g|mp4|webm|webp|pdf)$ no-gzip dont-vary
    </IfModule>
    </IfModule>
    # Compress all output labeled with one of the following MIME-types
    <IfModule mod_filter.c>
    AddOutputFilterByType DEFLATE application/atom+xml \
    		                          application/javascript \
    		                          application/json \
    		                          application/rss+xml \
    		                          application/vnd.ms-fontobject \
    		                          application/x-font-ttf \
    		                          application/xhtml+xml \
    		                          application/xml \
    		                          font/opentype \
    		                          image/svg+xml \
    		                          image/x-icon \
    		                          text/css \
    		                          text/html \
    		                          text/plain \
    		                          text/x-component \
    		                          text/xml
    </IfModule>
    <IfModule mod_headers.c>
    Header append Vary: Accept-Encoding
    </IfModule>
    </IfModule>
    # END WP Rocket
    RewriteEngine On 
    RewriteCond %{HTTPS} off 
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    # BEGIN WordPress
    # The directives (lines) between "BEGIN WordPress" and "END WordPress" are
    # dynamically generated, and should only be modified via WordPress filters.
    # Any changes to the directives between these markers will be overwritten.
    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </IfModule>
    
    # END WordPress
    # php -- BEGIN cPanel-generated handler, do not edit
    # Set the “ea-php74” package as the default “PHP” programming language.
    <IfModule mime_module>
      AddHandler application/x-httpd-ea-php74 .php .php7 .phtml
    </IfModule>
    # php -- END cPanel-generated handler, do not edit
    # BEGIN cPanel-generated php ini directives, do not edit
    # Manual editing of this file may result in unexpected behavior.
    # To make changes to this file, use the cPanel MultiPHP INI Editor (Home >> Software >> MultiPHP INI Editor)
    # For more information, read our documentation (https://go.cpanel.net/EA4ModifyINI)
    <IfModule php7_module>
       php_flag display_errors Off
       php_value max_execution_time 30
       php_value max_input_time 60
       php_value max_input_vars 1000
       php_value memory_limit 512M
       php_value post_max_size 260M
       php_value session.gc_maxlifetime 1440
       php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
       php_value upload_max_filesize 256M
       php_flag zlib.output_compression Off
    </IfModule>
    <IfModule lsapi_module>
       php_flag display_errors Off
       php_value max_execution_time 30
       php_value max_input_time 60
       php_value max_input_vars 1000
       php_value memory_limit 512M
       php_value post_max_size 260M
       php_value session.gc_maxlifetime 1440
       php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
       php_value upload_max_filesize 256M
       php_flag zlib.output_compression Off
    </IfModule>
    # END cPanel-generated php ini directives, do not edit
    Options -Indexes

    In my server, /etc/nginx/sites-enabled/300h.conf yields:

    server {
        server_name go.DOMAIN.com DOMAIN.com www.DOMAIN.com;
    
        root /var/www/html;
        index index.php;
        charset UTF-8;
    
        client_max_body_size 128m;
    
        ##
        # gzip config
        ##
    add_header Strict-Transport-Security "max-age=31536000";
    
    brotli on;
    brotli_comp_level 6;
    brotli_types text/xml image/svg+xml application/x-font-ttf image/vnd.microsoft.icon application/x-font-opentype application/json font/eot application/vnd.ms-fontobject application/javascript font/otf application/xml application/xhtml+xml text/javascript  application/x-javascript text/plain application/x-font-truetype application/xml+rss image/x-icon font/opentype text/css image/x-win-bitmap;
    
    #  if ($http_host = "ask.DOMAIN.com") {
    #      rewrite ^ https://forum.DOMAIN.com permanent;
    #   }
    
    #  if ($http_host = "forum.DOMAIN.com") {
    #     rewrite ^/(.*)$^ https://DOMAIN.com/forum/$1 permanent;
    # }
    
    #Yoast SEO Sitemaps
    
    location ~ ([^/]*)sitemap(.*).x(m|s)l$ {
    
      ## this rewrites sitemap.xml to /sitemap_index.xml
    
      rewrite ^/sitemap.xml$ /sitemap_index.xml permanent;
    
      ## this makes the XML sitemaps work
    
      rewrite ^/([a-z]+)?-?sitemap.xsl$ /index.php?yoast-sitemap-xsl=$1 last;
    
      rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
    
      rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;
    
      ## The following lines are optional for the premium extensions
    
      ## News SEO
    
      rewrite ^/news-sitemap.xml$ /index.php?sitemap=wpseo_news last;
    
      ## Local SEO
    
      rewrite ^/locations.kml$ /index.php?sitemap=wpseo_local_kml last;
    
      rewrite ^/geo-sitemap.xml$ /index.php?sitemap=wpseo_local last;
    
      ## Video SEO
    
      rewrite ^/video-sitemap.xsl$ /index.php?yoast-sitemap-xsl=video last;
    
    }
        gzip on;
        gzip_static on;
        gzip_vary on;
        gzip_disable "msie6";
        gzip_types text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon;
        gzip_http_version 1.1;
        gzip_comp_level 6;
        gzip_proxied any;
    
        ##
        # Server log config
        ##
    
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log warn;
    
        ##
        # FastCGI cache exceptions
        ##
    
        set $no_cache   0;
        set $cache_uri  $request_uri;
    
        if ($request_method = POST) {
            set $cache_uri  "null cache";
            set $no_cache   1;
        }
    
        if ($query_string != "") {
            set $cache_uri  "null cache";
            set $no_cache   1;
        }
    
        if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
            set $cache_uri  "null cache";
            set $no_cache   1;
        }
    
        if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
            set $cache_uri  "null cache";
            set $no_cache   1;
        }
    
        ##
        # Browser cache config
        ##
    
        location ~ \.(css|htc|js|js2|js3|js4)$ {
            expires max;
            add_header Pragma "public";
            add_header Cache-Control "max-age=31536000, public, must-revalidate, proxy-revalidate";
        }
    
        location ~ \.(html|htm|rtf|rtx|svgz|txt|xsd|xsl|xml)$ {
            try_files $uri $uri/ /index.php?q=$uri&$args;
            
            expires 3600s;
            add_header Pragma "public";
            add_header Cache-Control "max-age=3600, public, must-revalidate, proxy-revalidate";
        }
    
        location ~ \.(webp|woff2|woff|asf|asx|wax|svg|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$ {
            expires max;
            add_header Pragma "public";
            add_header Cache-Control "max-age=31536000, public, must-revalidate, proxy-revalidate";
            log_not_found off;
        }
    
        ##
        # Favicon
        ##
    
        location = /favicon.ico {
            log_not_found off;
            access_log off;
        }
    
        ##
        # robots.txt
        ##
    
        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }
    
        ##
        # Deny access to hidden files
        ##
    
        location ~ /\. {
            deny all;
        }
    
        ##
        # Deny access to uploaded PHP files
        ##
        #
        location ~* /(?:uploads|files)/.*\.php$ {
            deny all;
        }
    
        ##
        # Deny access to WordPress include-only files
        ##
    
        location ~ ^/wp-admin/includes/ {
            deny all;
        }
        location ~ ^/wp-includes/[^/]+\.php$ {
            deny all;
        }
        location ~ ^/wp-includes/js/tinymce/langs/.+\.php {
            deny all;
        }
        location ~ ^/wp-includes/theme-compat/ {
            deny all;
        }
    
        location / {
    #        try_files $uri $uri/ /index.php?q=$uri&$args;
            try_files $uri $uri/ /index.php?$args;
        }
    
        location ~ \.php$ {
            try_files $uri =404;
    
            include fastcgi_params;
            fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_index index.php;
            # fastcgi_intercept_errors on;
            # fastcgi_keep_conn on;
            # fastcgi_read_timeout 300;
    
            # fastcgi_pass   127.0.0.1:9000;
            fastcgi_pass  unix:run/php/php7.4-fpm.sock;
    
            ##
            # FastCGI cache config
            ##
    
            # fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:10m max_size=1000m inactive=60m;
            # fastcgi_cache_key $scheme$host$request_uri$request_method;
            # fastcgi_cache_use_stale updating error timeout invalid_header http_500;
      #      fastcgi_no_cache $no_cache;
     #       fastcgi_cache_bypass $no_cache;
    #        fastcgi_cache WORDPRESS;
    #fastcgi_cache_valid any 30m;
        }
    
        listen 443 ssl http2; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/DOMAIN.com-0001/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/DOMAIN.com-0001/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    }
    server {
        server_name ask.DOMAIN.com;
        return 301 https://DOMAIN.com/forum$request_uri;
    
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/DOMAIN.com-0001/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/DOMAIN.com-0001/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    }
    
    server {
        server_name forum.DOMAIN.com;
        return 301 http://DOMAIN.com/forum$request_uri;
    
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/DOMAIN.com-0001/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/DOMAIN.com-0001/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    }
    
    server {
        if ($host = www.DOMAIN.com) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        if ($host = go.DOMAIN.com) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        if ($host = DOMAIN.com) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        listen 80;
        server_name go.DOMAIN.com DOMAIN.com www.DOMAIN.com;
        return 404; # managed by Certbot
    
    }
    server {
        if ($host = ask.DOMAIN.com) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        listen 80;
        server_name ask.DOMAIN.com;
        return 404; # managed by Certbot
    
    }
    
    server {
        if ($host = forum.DOMAIN.com) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
    
        listen 80;
        server_name forum.DOMAIN.com;
        return 404; # managed by Certbot
    
    }

    The page I need help with: [log in to see the link]

Viewing 6 replies - 1 through 6 (of 6 total)
  • Hi @zee300,

    Finding the actual source of your problem is more complicated than checking your nginx configuration since there could be a lot more rewrites in your WP, especially if you are registering CPTs or custom taxonomies.

    However, you could add a workaround and patch your problem in two ways:

    • You can add a cron job to reset your permalinks (e.g every 6-8 hours), since you’ve already identified the frequency of the issue to 1-2 days. According to the docs, this is an expensive operation so it should only be used when necessary, so
    • You can add a small function that would detect a 404 before the template is loaded, flush rewrite rules and reload. This way you will reset permalinks only when actually needed.

    The first patch is quite simple, here’s an untested example for the second solution to get you going:

    function wpd_do_stuff_on_404(){
        if( is_404() ){
            global $wp;
            if (!$_COOKIE["rewrite_rules"]) {
                flush_rewrite_rules();
                setcookie('rewrite_rules', 'done', time()+20, '/');
                wp_redirect(home_url( $wp->request ));
                exit;
            }
        }
    }
    add_action( 'template_redirect', 'wpd_do_stuff_on_404' );

    template_redirect would be an appropriate hook for intercepting a 404 before the template is loaded. Setting a cookie acts as a flag, for the case a visitor has landed on a real 404, otherwise we would cause a redirect loop.

    Hopes this helps!

    Thread Starter elliesatt

    (@zee300)

    The issue with the first (cronjob) solution is that the pages will still be down until the cronjob runs, so it wouldn’t be ideal. But the second suggestion sounds like a solid workaround if the issue can’t be identified and solved.

    I have a few questions about the code though, hope you don’t mind:

    • Is there a way to ‘log’ when this function runs, by e.g. generating an error log or sending an email, so that I can identify that the problem is still there, and when it happens? This would help me continue to bug-hunt while the workaround is in effect.
    • Would the first person to visit a page after the bug strikes get a 404, or will the template_redirect hook prevent that as well?
    • Would this cause an issue if I legitimately delete a page, therefore intentionally causing a 404 error if visitors attempt to view a deleted page? Looking at the code I’m guessing it won’t, but just wanted to confirm.

    Thanks!

    1. Of course and that would be a smart thing to do. You can get as much info about the incident as possible and, just before the wp_redirect, save it to a text file or email it to yourself.
    2. The first person that is about to land to a 404 will not, there will be a permalinks reset and a refresh without him even noticing. Some ms on loading time will be added of course but better than a 404. The template_redirect is what does the trick, it fires before a template is loaded so user does not see all these happening.
    3. As I explained we set a cookie to only do this function once. So if a user visits a real 404, a non-existent page, he will go through our quick function and if the 404 status is still there then he will see 404. The function will not run twice because of the cookie check. If we didn’t have this flag, then the user would get locked up in a constant refresh (redirect loop).

    Alternatively if you don’t want to rely on cookies you can use transients. Set a transient as soon as you run this function so on refresh it won’t run again. The transient is great for storing temporary data by giving it a custom name and a timeframe after which it will expire and be deleted.

    Let us know if it works, thanx!

    Thread Starter elliesatt

    (@zee300)

    OK, so this is the first time I’m going beyond copying and pasting PHP code, so please excuse any newbie errors.

    The code below seems to work (assuming it is actually flushing rewrite rules):

    function wpd_do_stuff_on_404(){
        if( is_404() ){
            global $wp;
            if ( false === ( $flushed = get_transient( '404_demon_bug'.home_url( $wp->request ) ) ) ) { //if rewrite rules not flushed yet for this 
                flush_rewrite_rules();  //flush rewrite rules
    			$flushed = 1;
    			set_transient( '404_demon_bug'.home_url( $wp->request ), $flushed, 20 ); //set transient to say 'flushed' for 20 secs
    			error_log('['.date("F j, Y, g:i a e O").']'.home_url( $wp->request )."\n", 3, "/var/www/html/404-demon-bug.log"); //log date, time and offending URL
                wp_redirect(home_url( $wp->request )); //reload URL
                exit;
            }
        }
    }
    add_action( 'template_redirect', 'wpd_do_stuff_on_404' );

    There are however still some issues / concerns:

    1. Currently the script logs an entry every time flush_rewrite_rules() is triggered. I would prefer it to log an entry only if flush_rewrite_rules() succeeded in eliminating the 404, i.e. when it actually was resetting the bug issue. I’m not sure how that would work in the script’s current form.
    2. The error log also seems to be picking up a lot of ‘false’ 404 errors, e.g. when a “/” is missing from the end of the URL.
    3. The error log shows that this is firing several times a minute on average. Is that rate of flushing advisable?

    Here is a small grab of the error log output for context. I’ve commented [/] where these URLs exist, but I think they’re being flagged just because they’re missing a “/” at the end and my setup doesn’t like it for some reason.

    [April 7, 2021, 8:45 pm UTC +0000]https://DOMAIN.com/members/USERNAME/achievements
    [April 7, 2021, 8:47 pm UTC +0000]https://DOMAIN.com/login [/]
    [April 7, 2021, 8:49 pm UTC +0000]https://DOMAIN.com/t/pips/page/2
    [April 7, 2021, 8:49 pm UTC +0000]https://DOMAIN.com/members/discussions/USERNAME/profile
    [April 7, 2021, 8:49 pm UTC +0000]https://DOMAIN.com/forum/hud/general [/]
    [April 7, 2021, 8:49 pm UTC +0000]https://DOMAIN.com/forum/hud/general [/]
    [April 7, 2021, 8:50 pm UTC +0000]https://DOMAIN.com/t/hud-is-not-as-tough-as-it-seems/page/2 
    [April 7, 2021, 8:50 pm UTC +0000]https://DOMAIN.com/forum/hud/level-s/page/2
    [April 7, 2021, 8:50 pm UTC +0000]https://DOMAIN.com/t/best-video-game-console/page/3
    [April 7, 2021, 8:51 pm UTC +0000]https://DOMAIN.com/forum/robots.txt
    [April 7, 2021, 8:51 pm UTC +0000]https://DOMAIN.com/forum/robots.txt
    [April 7, 2021, 8:51 pm UTC +0000]https://DOMAIN.com/forum/robots.txt
    [April 7, 2021, 8:51 pm UTC +0000]https://DOMAIN.com/members/USERNAME/achievements [/]
    [April 7, 2021, 8:51 pm UTC +0000]https://DOMAIN.com/forum/login
    [April 7, 2021, 8:53 pm UTC +0000]https://DOMAIN.com [/]
    [April 7, 2021, 8:53 pm UTC +0000]https://DOMAIN.com/forum/hud/level-s [/]
    [April 7, 2021, 8:54 pm UTC +0000]https://DOMAIN.com/login [/]
    [April 7, 2021, 8:55 pm UTC +0000]https://DOMAIN.com/t/stuff-as-thanks/page/3
    [April 7, 2021, 8:55 pm UTC +0000]https://DOMAIN.com/forum/discussions/tagged/hud/feed.rss
    [April 7, 2021, 8:56 pm UTC +0000]https://DOMAIN.com/thisisatest

    Any suggested code modifications to minimise rate of flushing and ‘false’ error logging would be very welcome!

    • This reply was modified 5 months, 2 weeks ago by elliesatt.

    Looks good, you are almost there. Here’s my take, it would not allow the function to fire again, for at least 5 minutes, thus reducing that log of yours tremendously. Also, flushing rewrite rules (permalinks reset) affects all your links so this is not something to check per URL and definitely not something to do every 20s. One transient as a flag would be enough imo:

    function do_stuff_on_404(){
        if( is_404() ){
            global $wp;
            $check = get_transient( 'permalinks_flushed_recently' );
            if ( $check === false ) {
                flush_rewrite_rules();
    	    set_transient( 'permalinks_flushed_recently', 'yes', 5 * MINUTE_IN_SECONDS );
    	    error_log('['.date("F j, Y, g:i a e O").']'.home_url( $wp->request )."\n", 3, "/var/www/html/404-demon-bug.log");
                wp_redirect(home_url( $wp->request ));
                exit;
            }
        }
    }
    add_action( 'template_redirect', 'do_stuff_on_404' );

    If you are having many 404 errors maybe you should look at a plugin like this one to help you keep track of them and hopefully reduce them.

    As for the trailing slash missing you would need a redirect fix to always append it to your links. Check this out, it has the snippet for Apache and NGINX.

    Thread Starter elliesatt

    (@zee300)

    Thanks for this. I implemented your version of the code but I feel like the bug is now occurring more often! It goes away after a minute as expected, but given it’s occurred something like 4-5 times today already, either a recent change or the code itself is causing the bug to occur more often.

    Given transients don’t actually work like cookies, am I right in thinking that an every-minute cron job would probably be a more elegant solution at this point? I couldn’t find a good solution that would fire flush_rewrite_rules(); every minute. Any suggestions?

    I’ve reverted back to my version of the code for now, which seemed to work well and report back…

    • This reply was modified 5 months, 2 weeks ago by elliesatt.
Viewing 6 replies - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.