[wp-trac] [WordPress Trac] #39961: Make SHORTINIT accessible to plugins and themes.
WordPress Trac
noreply at wordpress.org
Fri Feb 24 09:27:20 UTC 2017
#39961: Make SHORTINIT accessible to plugins and themes.
----------------------------+-----------------------------
Reporter: majick | Owner:
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Bootstrap/Load | Version: trunk
Severity: normal | Keywords:
Focuses: performance |
----------------------------+-----------------------------
As it stands there's no safe way for a WordPress plugin or theme (to be
clear, specifically one permitted in the repository) to make use of the
SHORTINIT load constant for a performance increase. This performance
increase can be significant in terms of speed and memory for loading of
dynamic content delivery (eg. of scripts or styles etc.) as well as other
use cases (due to not having to load some core, but mostly not loading all
the plugins and the theme too.)
(Discovered in discourse with plugin review team for a plugin submission,
with one known exception here: backup plugins ''may'' be permitted in the
plugin repository where they can find `wp-load.php` (or `wp-settings.php`
or `wp-config.php`) so as to be able to access database credentials for
backup purposes.)
This is of course because `SHORTINIT` must be defined ''before'' requiring
`wp-load.php`, and so a plugin/theme needs to know ''where'' `wp-load.php`
is to be able to load it after defining `SHORTINIT` to make use of it -
BUT there is no current way for a standalone plugin/theme file to safely
determining that file path when it is loading first - meaning directly and
externally. (ie. `../../wp-load.php` is definitely not good enough, and a
recursive upwards directory searching function is not good enough either
because even though `WP_CONTENT_DIR` is defined from `ABSPATH`, it does
not account for a possible alternatives to `wp-content/plugins` or `wp-
content/themes`.)
My proposed solution is that the `ABSPATH` path can be defined in a file
that is written to the base plugins directory (that is, in
`WP_PLUGIN_DIR`) and the theme root directory (via `get_theme_root()`) so
that either a plugin or theme can simply include this load file from it's
parent directory in order to get the already defined and accurate
`ABSPATH` for the purpose of loading `wp-load.php` (ie. `ABSPATH.'/wp-
load.php`) - and then just proceed to do what it needs to do. **ATTACHED**
is the working code to do this with (place in an `mu-plugin` file for
testing):
It may seem a little strange at first to write this to a PHP file with a
just a single define in it, but on the other hand it really seems to me to
just be the ''simplest'' solution to this problem (which is more complex
than it first seems.) I chose a PHP file because if it were a text file it
would expose the absolute server path to external HTTP access
unecessarily. And anything other than a ''file'' available consistently
one directory up would not provide an accessible solution (eg. the path
cannot be retrieved from the database because of course, database access
is not available before load.)
As can be seen this initial proposal only checks for the direct file
method of writing (to keep things simple to start with), but this could be
expanded upon in future to better handle the other filesystem write
methods by checking credentials etc. (Obviously we don't want to request
credentials via a user form here, we just want to know if we have them so
we can write the new file or not. The need for this could be bypassed by
somewhat by including an empty file in the package, as updating a file can
use relaxed file permissions while writing a new one cannot. But I digress
on this point.)
For usage, a plugin or theme would then need to check that the `wp-
loadpath.php` file exists, and to be safer that it's contents contain the
`ABSPATH`. Doing it this way also prevents having to check the filesystem
write method (which can be handled in the previous step and is overkill
for plugin/theme authors to check on here.) Again, this being for a
performance improvement, plugins/themes should never rely on this method,
but rather, they would be able to access this more-performant method if it
available (again basically if the file path is writeable with correct
permissions) and fallback to a standard less-performant method if it is
not, which it would need to do for backwards compatbility anyway. For a
simple example, before enqueueing a dynamic stylesheet:
{{{#!php
<?php
add_action( 'wp_enqueue_scripts', 'wp_shortinit_load_example' );
function wp_shortinit_load_example() {
$loadpathfile = dirname(dirname(__FILE__)) . '/wp-loadpath.php';
if ( (file_exists( $loadpathfile )) && (strstr(file_get_contents(
$loadpathfile, ABSPATH ))) ) {
wp_enqueue_style( 'dynamic-style-example', plugins_url(
'example.css.php', __FILE__ ) );
} else {wp_enqueue_style( 'static-style-example', plugins_url(
'example.css', __FILE__ ) );}
}
}}}
Then the dynamic `example.css.php` could contain something as simple as:
{{{#!php
<?php
define( 'SHORTINIT', true );
require ( dirname( dirname( __FILE__ ) ) .'/wp-loadpath.php' );
require ( ABSPATH . '/wp-load.php' );
header( 'Content-type: text/css; charset: UTF-8' );
echo esc_attr( get_option( 'shortinit_example_css' ) );
exit;
}}}
I'm not looking to debate here whether using `SHORTINIT` for this example
is a good idea or not, that is up to each use case. It has definite and
well-tested advantages in terms of performance which is why it was created
and now just needs to be exposed in a reliable way to truly be useable for
that purpose. But if there are definite problems with this solution or a
more elegant one (I have really scratched my brain to come up with this
and don't see a more reliable and secure way, but who knows?) we can get
into those. To my mind there are really only a few easy questions I can
see that need to be answered before this could be implemented in core:
1. Is `wp-load.php` ''always'' found in the `ABSPATH` directory? It would
seem so, but just to check for certain, are there any known edge cases
where this is actually not so?
2. Does this create any possible security hole? It would seem not, as
simply defining `ABSPATH` in a PHP file does not actually do anything and
is no more accessible than any other file and so poses no real security
risk.
3. Since the solution proposed is to work with both plugins and themes,
are there any considerations missing here that would mean they would be
better treated as separately? It seems simple enough that they can be
handled together at this stage.
4. What is the best way of handling the other (non-direct) file write
methods? A check for credentials and using the filesystem to write if they
are already available seems to be all that is needed, beyond that seems
unnecessary.
5. Since the only change needed to implement this solution in core would
be to add the mu-plugins code above to somewhere in a core file, where
would the best place for that be? Perhaps just somewhere towards the end
of `wp-settings.php` but probably there is a more appropriate place.
6. After writing and testing this I realized even having a new file may
not even be necessary, since `index.php` already exists (a definite
advantage when handling the file writing) in both plugin and theme root
directories and contains no actual PHP code, it could be put to this
particular use instead of adding any new files (`wp-loadpath.php`). Unless
of course `index.php` is ever used for any other purpose than blocking
directory view access? It seems like it would be fine to use since it is a
core file it shouldn't be changed by anyone else anyway.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/39961>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list