Probably related to https://github.com/wp-media/wp-rocket/issues/771 which was closed in 2.11.7 (see @xbuzz’ kind comment), here’s the latest episode of WP Rocket’s _“Indefinite URL-to-path hiccups”_.
Starring: rocket_ _“I ain’t going home for money”_ get_home_path()
With: rocket_url_to_path() as _“Slash Bomb”_
Featuring: rocket_realpath() as himself
Fade-in, we find ourselves in the middle of a landscape rarely gazed upon by human eyes. Our virtual host is presenting a well-tended garden for us to explore and make sense of:
/{web root}
┣ /app {a.k.a. wordpress root}
┃ ┣ /media {a.k.a. uploads}
┃ ┣ /wp-admin
┃ ┣ /wp-includes
┃ ┣ index.php {not used}
┃ ┣ wp-blog-header.php
┃ ┣ wp-config.php
┃ ┗ {etc}
┃
┣ /assets
┃ ┣ /cache {a.k.a. wp-content}
┃ ┣ /mu-plugins
┃ ┣ /themes
┃ ┣ {etc}
┃ ┣ /wp-rocket-config
┃ ┗ advanced-cache.php
┃
┣ /plugins {a.k.a. wp-content/plugins}
┃ ┣ /wp-rocket
┃ ┗ {etc}
┃
┣ .htaccess
┗ index.php {copy of app/index.php, manually edited}
Entering the homely warmth of wp-config.php, we’re met with fair lines that explain the surroundings we’ve been blessed to feast our eyes upon:
define( 'WP_SITEURL', 'https://example.com/app' );
define( 'WP_HOME', 'https://example.com' );
define( 'WP_CONTENT_DIR', '/var/www/vhosts/example.com/httpdocs/assets' );
define( 'WP_CONTENT_URL', 'https://example.com/assets' );
define( 'WP_PLUGIN_DIR', '/var/www/vhosts/example.com/httpdocs/plugins' );
define( 'WP_PLUGIN_URL', 'https://example.com/plugins' );
define( 'UPLOADS', 'media' );
And … action!
Minification used to work, but it don’t no more, it don’t no more, it don’t no more.
_Time-lapse of an anonymous pair of hands typing away on a computer keyboard at ever increasing pace, accompanied by Otis Day and the Knights “Shout (You Make me Wanna)”_
rocket__“I ain’t going home for money”_get_home_path() must find its way home. In a perhaps half-assed, but desperate attempt of making it so, we’re throwing the if towel, right before the pre-existing if condition closes its gates:
if ( ! $home_path ) {
$home_path = untrailingslashit( dirname( $wp_index_php ) );
}
Meanwhile, rocket_url_to_path() is passing slash bombs like candy to poor rocket_realpath(). What in the name of …?!
Eagerly, we’re sneaking in a conditional to check if $url is actually based on site_url(), or if the two are entirely _not_ related—in which case we decide to have opinions and default to home_url():
if ( isset( $site_components['path'] ) && isset( $url_components['path'] ) ) {
$pos = strripos( $site_components['path'], trailingslashit( $url_components['path'] ) );
if ( false === $pos ) {
$site_url = trailingslashit( set_url_scheme( home_url() ) );
}
}
… which surprisingly works smoothly like a charm from a stoned fairy, and resolves our plot.
This needs testing, and a lot.
Below are my annotated version of our two villains. This tamed them on the aforementioned scene, but I’m far from declaring victory. Please kindly come to rescue, @Tabrisrp or @arunbasillal!
/**
* Converts an URL to an absolute path.
*
* @since 2.11.7
* @author Remy Perona
* @author Caspar Hübinger
*
* @param string $url URL to convert.
* @param array $hosts An array of possible hosts for the URL.
* @return string
*/
function rocket_url_to_path( $url, $hosts = '' ) {
$url_components = get_rocket_parse_url( $url );
// sample log:
// array (
// 'host' => 'www.example.com',
// 'path' => '/plugins/contact-form-7/includes/css/styles.css',
// 'scheme' => 'https',
// 'query' => '',
// )
$site_components = get_rocket_parse_url( site_url() );
// sample log:
// array (
// 'host' => 'www.example.com',
// 'path' => '/app',
// 'scheme' => 'https',
// 'query' => '',
// )
$site_url = trailingslashit( set_url_scheme( site_url() ) );
// Check if $url is actually based on site_url()
if ( isset( $site_components['path'] ) && isset( $url_components['path'] ) ) {
$pos = strripos( $site_components['path'], trailingslashit( $url_components['path'] ) );
// log: false
if ( false === $pos ) {
// This is pure guesswork at this point, sorry.
// I’m just assuming home_url() is the only alternative here,
// because my brain is toast. Should be verified.
$site_url = trailingslashit( set_url_scheme( home_url() ) );
}
}
// Whatever this was for, didn’t touch it.
if ( isset( $hosts[ $url_components['host'] ] ) && 'home' !== $hosts[ $url_components['host'] ] ) {
$site_url = trailingslashit( rocket_add_url_protocol( $url_components['host'] ) );
if ( ≈ !== $site_components['path'] ) {
$site_url .= ltrim( $site_components['path'], '/' );
}
}
$home_path = rocket_get_home_path();
$file = str_replace( $site_url, $home_path, rocket_set_internal_url_scheme( $url ) );
return rocket_realpath( $file );
}
/**
* Get the absolute filesystem path to the root of the WordPress installation.
*
* @since 2.11.7 copy function get_home_path() from WP core.
* @since 2.11.5
* @author Chris Williams
* @author Caspar Hübinger
*
* @return string Full filesystem path to the root of the WordPress installation.
*/
function rocket_get_home_path() {
$home = set_url_scheme( get_option( 'home' ), 'http' );
// log: 'http://www.example.com/app'
$siteurl = set_url_scheme( get_option( 'siteurl' ), 'http' );
// log: 'http://www.example.com'
$home_path = ABSPATH; // shouldn’t this be wp_normalize_path() ?
// log: '/var/www/vhosts/example.com/httpdocs/app/'
if ( ! empty( $home ) && 0 !== strcasecmp( $home, $siteurl ) ) {
$wp_path_rel_to_home = str_ireplace( $home, '', $siteurl ); /* $siteurl - $home */
// log: '/app'
$wp_index_php = $_SERVER['SCRIPT_FILENAME'];
// log: '/var/www/vhosts/example.com/httpdocs/index.php' because index.php has been moved up 1 level!
// should be: '/var/www/vhosts/example.com/httpdocs/app/index.php'
$pos = strripos( str_replace( '\\', '/', $wp_index_php ), trailingslashit( $wp_path_rel_to_home ) );
// log: 'false'
// should be: '46'
$home_path = substr( $wp_index_php, 0, $pos );
// log: '' (empty)
// Safety line if $home_path does not exist by now:
if ( ! $home_path ) {
// Not sure if this is indeed the only possible conclusion here,
// but I thought is was fair to assume at this poing that WordPress’
// root index.php lives in the parent directory of ABSPATH.
$home_path = untrailingslashit( dirname( $wp_index_php ) );
}
$home_path = trailingslashit( $home_path );
// log before: '/'
// log now: '/var/www/vhosts/example.com/httpdocs/'
}
return str_replace( '\\', '/', $home_path );
}
rocket_get_home_path() is an exact copy of https://developer.wordpress.org/reference/functions/get_home_path/, so if it works for core, it should work for us.
The changes need to be in rocket_url_to_path(), but home_url() is unreliable because of multilingual plugins: depending on their configuration, home_url() will not return the expected URL, but the URL with the lang folder appended.
@Tabrisrp Thanks! If support allows, I’ll look into it further, particularly regarding what you said about rocket_url_to_path(). If not, @arunbasillal will probably be more effective than me anyways when he’s back. 😉
Just a note to say that it also affects sites where WordPress is in a sub-folder, even without any fancy virtual host defines or other shenanigans in wp-config.php. I have a local site where I can reproduce the symptoms - no minify/combine/remove query strings, but page caching works.
Adding related tickets here so that we can update them once this issue is taken care of.
Guess this ticket too has the same issue: https://secure.helpscout.net/conversation/545486283/63070?folderId=273761
Has there been an influx of these tickets since 2.11.7? If so perhaps this change should be reverted in the next point release unless a more robust fix can be put in place in the meantime.
Update: Actually that never shipped. A number of other commits between v2.11.6...v2.11.7 changed up the flow a bit. Ignore the revert suggestion there.
Here is an updated version of the rocket_url_to_path version that should solve the issue. I tested it with:
@AliceOrru @glueckpress @arunbasillal @webtrainingwheels : if you have access to the customers websites with this issue, you can test the function below and see if it works.
@xbuzz If you can test it too, it's welcome.
If the feedbacks are positive, this can be included in 3.0
function rocket_url_to_path( $url, $hosts = '' ) {
$url_components = get_rocket_parse_url( $url );
$site_url = trailingslashit( set_url_scheme( site_url() ) );
$home_path = ABSPATH;
if ( false !== strpos( rocket_extract_url_component( $url, PHP_URL_PATH ), rocket_extract_url_component( WP_CONTENT_URL, PHP_URL_PATH ) ) ) {
$site_url = trailingslashit( set_url_scheme( WP_CONTENT_URL ) );
$home_path = trailingslashit( WP_CONTENT_DIR );
}
$site_components = get_rocket_parse_url( $site_url );
if ( isset( $hosts[ $url_components['host'] ] ) && 'home' !== $hosts[ $url_components['host'] ] ) {
$site_url = trailingslashit( rocket_add_url_protocol( $url_components['host'] ) );
if ( $url_components['path'] !== $site_components['path'] ) {
$site_url .= ltrim( $site_components['path'], '/' );
}
}
$file = str_replace( $site_url, $home_path, rocket_set_internal_url_scheme( $url ) );
return rocket_realpath( $file );
}
@Tabrisrp confirmed!
Confirmed 👌 on my local site w/ subfolder.
On this site: https://secure.helpscout.net/conversation/542784975/62675?folderId=377611
It works in that files are now cache busted which they weren't before.
But now it has this issue: https://github.com/wp-media/wp-rocket/issues/757
i.e. fonts referred to with relative URLs in stylesheets are rewritten incorrectly with remove static resources option. (screenshot in above ticket)
This issue does not happen in 2.11.6
EDIT: I'm no longer sure if the relative URL issue existed with 2.11.6 or not, but certainly it's an issue on 2.11.7 with the new rocket_url_to_path
Will test further tmrw.
Confirmed 👌 by customer in this ticket: https://secure.helpscout.net/conversation/527926441/60727?folderId=377611
This is the original one that @glueckpress debugged for this issue.
Confirmed 👌 on this ticket:
https://secure.helpscout.net/conversation/537630766/61976?folderId=377611
Which is the setup referenced by Cedrox over here: https://github.com/wp-media/wp-rocket/issues/755
Azure / Docker with relative URLs.
@Tabrisrp I don’t have access to the customer site any longer, but I forwarded this issue to them.
Most helpful comment
Here is an updated version of the
rocket_url_to_pathversion that should solve the issue. I tested it with:@AliceOrru @glueckpress @arunbasillal @webtrainingwheels : if you have access to the customers websites with this issue, you can test the function below and see if it works.
@xbuzz If you can test it too, it's welcome.
If the feedbacks are positive, this can be included in 3.0