[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