kovshenin / surge Goto Github PK
View Code? Open in Web Editor NEWSurge is a very simple and fast page caching plugin for WordPress.
License: GNU General Public License v3.0
Surge is a very simple and fast page caching plugin for WordPress.
License: GNU General Public License v3.0
=== Surge === Contributors: kovshenin Donate link: https://github.com/kovshenin/surge Tags: cache, performance, caching Requires at least: 5.7 Tested up to: 6.4 Requires PHP: 7.3 Stable tag: 1.1.0 License: GPLv3 or later License URI: https://www.gnu.org/licenses/gpl-3.0.en.html Surge is a very simple and fast page caching plugin for WordPress. == Description == Surge generates and serves static HTML files for your WordPress site, causing quicker requests, faster load times and a shorter time to first byte (TTFB). Surge does not require configuration, and has no options. It works out of the box on any well-configured hosting platform. Cached files are stored on disk, and automatically invalidated when your site is updated. In various load tests, Surge has shown to easily handle 1000-2500 requests per second at 100 concurrent, on a small single-core server with only 1 GB of RAM. That's over 70 times faster than a stock WordPress install. == Installation == Via the WordPress Dashboard: navigate to Plugins - Add New. In the search bar type "surge" and hit Enter. Find the Surge plugin in the search results, hit Install, then Activate. Manually: download the Surge plugin .zip file from WordPress.org. In your WordPress admin navigate to Plugins - Add New - Upload. Select the .zip file and hit Upload. Activate the plugin after upload is successful. Manually via FTP: download the Surge plugin .zip file from WordPress.org, extract the archive, make sure the directory is called "surge". Use your FTP/SFTP client to upload the "surge" directory to wp-content/plugins. Then activate the plugin in your WordPress admin from the Plugins section. Using WP-CLI: wp plugin install surge --activate == Frequently Asked Questions == = Where is the plugin configuration screen? = There isn't one. = How do I clear the cache? = Toggle the plugin activation or run `wp surge flush` using WP-CLI. = Is my cache working? = Visit the Site Health screen under Tools in your WordPress dashboard. Common caching errors, like installation problems, etc. will appear there. Otherwise, open your site in an Incognito window to see the cached version. You could also look for the "X-Cache" header in the server response. = Why am I getting cache misses? = Below are a few common reasons: * You are logged into your WordPress site * You have a unique cookie set in your browser * A unique query parameter will also cause a cache miss, except common marketing parameters, such as utm_campaign, etc. * Request methods outside of GET and HEAD are not cached = Can I exclude page X from being cached? = Of course. If you pass a "Cache-Control: no-cache" header (or max-age=0) the request will automatically be excluded from cache. Note that most WordPress plugins will already do this where necessary. = fpassthru() has been disabled for security reasons = It seems like your hosting provider disabled the fpassthru() function, likely by mistake. This is a requirement for Surge. Please get in touch with them and kindly ask them to enable it. = How can I support Surge? = If you like Surge, consider giving us a [star on GitHub](https://github.com/kovshenin/surge) and a review on WordPress.org. == Changelog == = 1.1.0 = * Improved Multisite compatibility * Fixed occasional stat() warnings in cleanup routines * Fixed expiration by path being too broad * Added a filter for flush actions * Feature: added a simple events system for s-maxage and stale-while-revalidate support = 1.0.5 = * Fix woocommerce_product_title compatibility * Honor DONOTCACHEPAGE constant * Use built-in is_ssl() WordPress function for better compatibility = 1.0.4 = * Add a WP-CLI command to invalidate/flush page cache * Fix redirect loop with Core's redirect_canonical for ignore_query_vars * Fix warnings for requests with empty headers * Fix warnings when cron cleanup attempts to read a file that no longer exists * Add a filter to disable writing to wp-config.php = 1.0.3 = * Invalidate cache when posts_per_page is changed * Fix redirect loop with unknown query vars caused by Core's redirect_canonical * Ignore X-Cache and X-Powered-By headers from cache metadata * Allow multiple headers with the same name = 1.0.2 = * Fix PHP notice in invalidation * Protect against race conditions when writing flags.json * Add support for more post statuses in transition_post_status invalidation = 1.0.1 = * Add support for custom user configuration * Various invalidation enhancements and fixes * Remove advanced-cache.php when plugin is deactivated * Add a note about fpassthru() in FAQ * Minor fix in Site Health screen tests = 1.0.0 = * Anonymize requests to favicon.ico and robots.txt * Improve cache expiration, add cache expiration by path = 0.1.0 = * Initial release
My error logs are getting a couple dozen of these a day, and was wondering if you knew what might be going on. They cover a large variety of subsites and different files in the /wp-content/cache/surge/ directory.
PHP WARNING: [stat(): stat failed for /home/account_name/public_html/wp-content/cache/surge/72/d3277e3b90f60fd2f6b08d9628a4a272.VJgk7M.php] in file /home/account_name/public_html/wp-content/plugins/surge/include/cron.php:50 at https://mynetwork.com/subsite/wp-cron.php?doing_wp_cron=1690921598.2740859985351562500000
Found the issue pluginkollektiv/cachify#265 and noticed that it also applies to Surge.
This can be reproduced with the ActivityPub plugin active which serves different content based on the accept header. Example:
$ curl 'https://dominikschilling.de/notes/author/dominik/?123' -H 'Accept: application/activity+json'
# Output: {"@context":["https:\/\/www.w3.org\/ns\/activitystreams","ht ...
$ curl 'https://dominikschilling.de/notes/author/dominik/?123' -H 'Accept: text/html'
# Unexpected output: {"@context":["https:\/\/www.w3.org\/ns\/activitystreams","ht ...
$ curl 'https://dominikschilling.de/notes/author/dominik/?456' -H 'Accept: text/html'
# Output: <html lang="en-US">
$ curl 'https://dominikschilling.de/notes/author/dominik/?456' -H 'Accept: application/activity+json'
# Unexpected output: <html lang="en-US">
@kovshenin Should the accept header be added to the cache key or should the cache be skipped for non-HTML requests somewhere here? Or something else?
Need to invalidate caches when the posts_per_page
option is changed in the Dashboard.
Sometimes, you want to prepare for a massive influx of users that is known in advance. In these scenarios, it would be helpful to have the option to disable cache invalidation altogether with a filter.
I'm testing the ActivityPub plugin (https://wordpress.org/plugins/activitypub/) on my blog. Sometimes I see the ActivityPub JSON instead of the regular page when visiting the site in a browser. This probably means that the JSON is cached and served to regular visitors. Is it possible to add a "variant" for this?
Steps to reproduce (assuming Surge is active with no custom configuration):
This does not happen to me every time, but the steps above should give you a decent chance.
Related: https://wordpress.org/support/topic/caching-conflict-between-wordpress-post-and-other-output/
Hi there,
Surge has been working awesomely for me, but I just realized it breaks ours sites that require users be logged in to view, which are handled by Shibboleth: https://www.shibboleth.net/about-us/the-shibboleth-project/
We run MultiSites, and per your suggestions, have been Network Activating Surge. (https://wordpress.org/support/topic/multisite-636/)
Again, in most cases, it's been working awesomely. However, on the sites that have front-ends that require users to be logged in, users end up in an infinite redirect loop.
I'm assuming that figuring out WHY it's not working with Shibboleth is out of scope for support, though I'd be happy to connect with you directly and chat about that. Here are some questions that I do have, however:
You wrote "The plugin should be network-activated to work correctly." In my basic testing, it appears to work fine when activated on a site-by-site basis. Are you able to elaborate on what does or might not work correctly if it's not network activated? The ability to control which sites it's actually used on would be AMAZING for our environments, where some sites are being updated almost constantly, and some haven't been updated in years.
If it's not possible to use it on a site-by-site basis per above, might it be possible to hook into part of the cache loading process and opt out if certain conditions are met? Something like:
add_action( 'something_super_duper_early', 'maybe_not_use_surge');
function maybe_not_use_surge( ) {
if ( $this_site_requires_being_logged_in_to_view ) {
dont_use_surge_for_this_request();
}
}
Thank you so much for your time and knowledge!
Hi!
While playing around with Surge, I noticed the plugin makes changes to PHP globals at various places:
Is it intended?
Since key()
is called on every request, you may end up messing with third party code that relies on those globals and not only on edge cases.
I've been loving the performance improvements that come with Surge, and I've been digging into it more and more. I've got a couple questions, especially as it pertains to MultiSite.
You said that it's supported out of the box (https://wordpress.org/support/topic/multisite-636/). However, the more that I learn about how everything works, I'm wondering if there might be some ways to improve MultiSite performance.
Just for reference, our MultiSites contain several hundred sites - not a small handful.
It seems that if any site on the network does any of the things in $flush_actions, the entire network's cache is immediately invalidated. So, one site changing themes, activating a plugin, etc will expire the cache for several hundred other sites which were not impacted at all by the change. This means our cache is getting expired very frequently, and well in advance of the longer time I'm trying to support.
I was wondering if there's any compelling reason why subsites don't operate more independently. For example, if each subsite maintained its own /wp-content/cache/surge/flags.json.{$blog_id}.php file, and then only flush the cache for the impacted subsite during those actions. Of course, there are still SOME actions that should likely flush the entire network's cache, such as WP itself updating or a plugin being network activated/deactivated.
I'm trying out Surge on a low-traffic site and it doesn't seem like crawling is enough to negate the need for preloading. I visited the homepage, recent posts, and main-menu items periodically over the course of an hour, and frequently got cache-misses.
I bumped the TTL to a week as a workaround, but I'm worried that'll still result in a lot of misses. This type of site has ~300 posts, but isn't updated frequently, and is on shared hosting. So I'm more worried about slow load times on the long tail of older posts than I am about edge cases where the cache isn't invalidated fast enough.
I believe that most caching plugins of this nature add an HTML comment such as:
<!-- served by Surge: {timestamp of when page was cached} -->
to the end of each page. I was hoping you'd consider adding it here. It would make it easier to verify the cache is working as expected, as well as help debug issues or answer questions about when a page was cached.
Great plugin! It's the first of its kind that I'm giving serious consideration to using in a Production environment.
PHP version 7.4.30
Surge version 1.0.4
This combination results in the following PHP warnings
PHP Warning: Use of undefined constant DIR - assumed 'DIR' (this will throw an Error in a future version of PHP) in /var/www/doma.in/config/application.php on line 70
PHP Warning: include(DIR/cache-config.php): failed to open stream: No such file or directory in /var/www/doma.in/content/plugins/surge/include/common.php on line 56
We are using bedrock based structure, hence the content/plugins.
Hey 👋🏻 I noticed this:
Line 239 in e68d4be
FYI, I dug into that recently for another project, and it seems like it's not possible
I'd be happy to be wrong if you found something I missed, though!
Spotted by @roytanck. Publishing a new post does not invalidate the home page cache (or other related archives) because it's not been flagged with this new post ID. Untrashing a post has the same problem for the same reasons.
Reproduce:
The published post permalink will still work immediately as it's invalidated correctly by post ID, but things like "latest posts" widgets, etc. will also have a hard time picking up the new post until it expires due to TTL.
Some users reported a PHP warning in foreach() in include/serve.php on line 76, which is the loop through the headers, saved in the cache metadata. It seems like in some cases, when WordPress doesn't send any headers at all, or only ones that we choose to skip:
https://github.com/kovshenin/surge/blob/main/include/cache.php#L39
The $headers
variable is never defined as an array, and is thus saved as null
in the metadata, which then causes the warning on display.
Working with a theme with a built-in AJAX search feature. When Surge is active, the search function doesn't work (JS error "Uncaught TypeError: Cannot read properties of null").
Looking at the data returned by the AJAX request - the product titles are null
. Looks related to:
https://github.com/kovshenin/surge/blob/1.0.4/include/invalidate.php#L18
Is this an issue with the theme? Or, should this filter return the $title
?
Hey, first of all thanks for the excellent plugin, it works incredibly well out of the box!
I have been poking through the plugin source code and I can't seem to find the logic that disables/prevents caching for logged in users.
What I am hoping is possible is that I can create a custom config file like this Surge Configuration Example. And setup some logic to enable caching for logged in users with a certain custom role (essentially a role that only has frontend access).
If you could point me in the direction of how Surge currently identifies logged in users I'd really appreciate it.
We have a custom plugin called "Content Blocks" (which are basically re-usable Blocks from 10 years before the block editor was even a thing). It's a custom post type, and they can be included on other Pages and Posts.
I noticed that when someone updates a Content Block, the cached entries that use it don't become invalidated.
Surge will automatically invalidate cached entries on various different events, so you shouldn’t have to worry about that.
Is there any way to hook into Surge's behavior to modify it so that affected cache entries are invalidated?
Alternatively, is there any way we can programmatically just clear all of Surge's cache?
Given how much content across our sites can be impacted when ANYTHING changes (content blocks, other plugins that list recent posts, widgets, etc), we actually just clear our own custom cache stuff every time ANY post is updated, and that works well for us. If possible, I'd simply add a call to surge_clear_complete_cache() to that same function.
I do realize I could probably use deactive_plugin() and activate_plugin(), but that seems like a lot of unnecessary overhead for when I'm just trying to clear the cache.
Thanks as always!
This get_post_type_object() call in some cases can return null
when transitioning objects of unknown types (auto-draft if I had to guess), causing a PHP notice: Trying to get property 'public' of non-object.
Reported on the forums here.
Should check the $obj
variable prior to accessing its properties.
Upon install, whatever the value of WP_CACHE
is in wp-config.php
is removed it would be good to be able to disable this behaviour, useful for cases where config is configured from env vars and plugins are installed as part of a build process for example.
I'm happy to provide a PR, but just wanted to run it by you first. Would you be happy with wrapping in a conditional with a filter?
I'm trying to cache a WP Rest API response that calls to a 3rd party API, the 3rd party API takes few seconds to query.
Surge caches the response by default, everything is fine, except if I want the Rest API to hit the 3rd party API again after the max-age expires.
Looks like Surge only checks for no-cache
and max-age=0
, are there any plans to support variable number of max-age like header( 'Cache-Control: max-age=60' );
?
It would be convenient to have wp-cli commands, in particular lacking a command to completely clear the cache.
No client caching response headers were detected.
Would you consider adding a filter to $flush_actions so that we can easily add our own actions to this?
In case you're curious, I'd be looking to add things like:
wp_update_nav_menu
wp_update_nav_menu_item
wp_add_nav_menu_item
delete_widget // (I wish I could also flush the cache on add/edit a widget, but that doesn't seem possible at the moment - https://core.trac.wordpress.org/ticket/59908 )
Hi!
First impressions about this plugin are great.
I have a setup, where content on pages are managed by ACF flexible layout, where each section is essentially its own block.
So Classic Editor, not Gutenberg.
Everything seems to be working fine, except for these above mentioned blocks on a custom taxonomy.
Saving content on language A on this taxonomy, causes the content to go blank on language B. The data is still available in the Database. By "going blank", I mean that the fields on the admin panel are empty. This problem is visible on the frontend also, no content is being displayed.
No errors on Query Monitor or in the browser console, on either side.
Multilinguality is handled by Polylang.
The site is quite big and complex, so I'll try to create a small reproduction where all other possible variables have been removed.
But currently, disabling Surge makes the problem go away.
I'm creating this issue now, if you happen to have an idea on what could cause the problem. I'll get back here with a small reproduction.
failed to obtain WP configuration for `/var/www/html': PHP Warning: Undefined array key "path" in /var/www/html/wp-content/plugins/surge/include/common.php on line 80 PHP Warning: Undefined array key "REQUEST_METHOD" in /var/www/html/wp-content/plugins/surge/include/common.php on line 124 PHP Warning: Undefined array key "HTTP_HOST" in /var/www/html/wp-content/plugins/elegant-age-verification/elegant-age-verification.php on line 137 PHP Warning: Undefined array key "REQUEST_METHOD" in /var/www/html/wp-content/plugins/surge/include/cache.php on line 59 PHP Warning: Undefined array key "REQUEST_METHOD" in /var/www/html/wp-content/plugins/surge/include/cache.php on line 59 sh: line 1: 482484 Segmentation fault (core dumped) /usr/bin/php -d display_errors=off -d mysqli.default_socket='/var/lib/mysql/mysql.sock' -d date.timezone=Europe/Prague -d memory_limit=512M -r 'ob_start(); register_shutdown_function(static function() { global $table_prefix; file_put_contents("php://fd/3", serialize(array("user" => DB_USER, "password" => DB_PASSWORD, "db" => DB_NAME, "host" => DB_HOST, "prefix" => $table_prefix))); ob_get_level() && ob_clean(); die(); }); include("./wp-config.php"); die();' 3>&1-
I noticed Surge has some benchmarks in the plugin's description.
In various load tests, Surge has shown to easily handle 1000-2500 requests per second at 100 concurrent, on a small single-core server with only 1 GB of RAM. That’s over 70 times faster than a stock WordPress install.
It seems to me a natural follow up question would be how does it compare to other caching solutions, either plugin based (WP Super Cache, WP Fastest Cache, WP Rocket, etc.), or server based (OpenLiteSpeed Cache, or propietary caches like Kinsta's).
Is the point of Surge to be a performant plug and play cache plugin (as opposed to the configurable options), or the best performing cache plugin (which also happens to be plug and play)? I suspect its somewhere in between, but I'm not entirely sure.
Would love to hear about how you've done the benchmarks and, if at all possible, contribute in the "comparison" department.
Let me know if I can help, thanks.
Seems like there is some code in Core that converts / to %2F in unknown query arguments performing a redirect, but the redirect is cached under the same cache key as the %2F version, resulting in a redirect loop. Ideally these requests are cached under different keys.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.