GithubHelp home page GithubHelp logo

kovshenin / surge Goto Github PK

View Code? Open in Web Editor NEW
149.0 10.0 12.0 431 KB

Surge is a very simple and fast page caching plugin for WordPress.

License: GNU General Public License v3.0

PHP 100.00%
wordpress wordpress-plugin wordpress-plugins

surge's Introduction

=== 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

surge's People

Contributors

doiftrue avatar kovshenin avatar nlemoine avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

surge's Issues

Add filter to disable invalidation

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.

PHP error logs have numerous: stat failed...

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

Manipulating PHP globals

Hi!

While playing around with Surge, I noticed the plugin makes changes to PHP globals at various places:

  • unset( $_COOKIE[ $key ] );
  • surge/include/common.php

    Lines 115 to 118 in e68d4be

    $_SERVER['REQUEST_URI'] = preg_replace( "#(\?)?&?({$unset_vars_regex})=[^&]+#", '\\1', $_SERVER['REQUEST_URI'] );
    $_SERVER['REQUEST_URI'] = str_replace( '?&', '?', $_SERVER['REQUEST_URI'] );
    if ( $_SERVER['REQUEST_URI'] == '/?' ) {
    $_SERVER['REQUEST_URI'] = '/';
  • surge/include/common.php

    Lines 107 to 108 in e68d4be

    unset( $_REQUEST[ $key ] );
    unset( $_GET[ $key ] );

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.

Enable cache for logged in users

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.

Cache-Control: max-age not honored

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' ); ?

Add support for content negotiation

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?

Redirect loop on / to %2F conversion in unknown query arguments

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.

Getting these errors...

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-

Conflict with Shibboleth SSO; use on select sites in MultiSite?

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:

  1. 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.

  2. 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!

Add a way of disabling overwriting `WP_CACHE` value in wp-config.php

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?

<!-- served by Surge: timestamp -->

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.

WP_CLI commands

It would be convenient to have wp-cli commands, in particular lacking a command to completely clear the cache.

Warning when looping through metadata headers

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.

Publishing a new post or untrashing a post does not invalidate cache correctly

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:

  • Make sure home is set to list latest 10 posts
  • Prime the home page cache in incognito mode
  • Publish a new post
  • Check home page, the new post will be missing until the TTL runs out

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.

Issue with the ActivityPub plugin

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):

  1. Install the ActivityPub plugin.
  2. Configure at least one author profile in its settings.
  3. Visit the Fediverse account (i.e. @[email protected]) using your favorite Mastodon client.
  4. immediately after that visit the WordPress author page (example.com/author/user).

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/

ACF content doesn't load on custom taxonomies

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.

MultiSite Questions

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.

Invalidating Cache Entries (or entire cache programmatically)

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!

Can't clean `php://input`

Hey 👋🏻   I noticed this:

// TODO: Clean php://input too.

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!

Preloading pages

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.

How does it compare to other caching solutions?

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.

PHP warnings

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.