Created
July 23, 2016 01:19
-
-
Save ethitter/fb901b9afe0b2cd64fa1ad607b5067ed to your computer and use it in GitHub Desktop.
WordPress.com VIP site in a subdirectory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Move entire multisite into a subdirectory within its assigned domain | |
*/ | |
class WPCOM_VIP_Multisite_Subdirectory_Rewrites { | |
/** | |
* Singleton | |
*/ | |
private static $__instance = null; | |
public static function instance( $rewrite_root, $permalink_stub ) { | |
// Instantiate the singleton | |
if ( ! is_a( self::$__instance, __CLASS__ ) ) { | |
self::$__instance = new self( $rewrite_root, $permalink_stub ); | |
} | |
// Throw an error if subsequent instantiations use different arguments | |
if ( $rewrite_root !== self::$__instance->rewrite_root || $permalink_stub !== self::$__instance->permalink_stub ) { | |
_doing_it_wrong( 'WPCOM_VIP_Multisite_Subdirectory_Rewrites::instance', __CLASS__ . ' can only be instantiated with one set of arguments.', 1 ); | |
return false; | |
} | |
// Return this class's instance | |
return self::$__instance; | |
} | |
/** | |
* Class properties | |
*/ | |
private $rewrite_root = null; | |
private $permalink_stub = null; | |
private $permalink_structure = null; | |
/** | |
* Set up new permalink structure and the hooks that implement it | |
* | |
* @param string $rewrite_root String to prefix all URLs with | |
* @param string $permalink_stub WordPress permalink structure, with leading slash | |
*/ | |
private function __construct( $rewrite_root, $permalink_stub ) { | |
// Abort if requisite VIP functions are missing | |
if ( ! function_exists( 'wpcom_vip_load_permastruct' ) ) { | |
_doing_it_wrong( 'WPCOM_VIP_Multisite_Subdirectory_Rewrites::instance', __CLASS__ . ' only works with the WordPress.com VIP environment. Be sure to include its init call before this function is used.', 1 ); | |
return; | |
} | |
// Set properties from the instantiation | |
$this->rewrite_root = $rewrite_root; | |
if ( 0 !== strpos( $permalink_stub, '/' ) ) { | |
$permalink_stub = '/' . $permalink_stub; | |
} | |
$this->permalink_stub = $permalink_stub; | |
$this->permalink_structure = $this->rewrite_root . $this->permalink_stub; | |
// Bail if we don't have what's required | |
if ( in_array( null, array( $this->rewrite_root, $this->permalink_stub, $this->permalink_structure ) ) ) { | |
$this->rewrite_root = $this->permalink_stub = $this->permalink_structure = null; | |
_doing_it_wrong( 'WPCOM_VIP_Multisite_Subdirectory_Rewrites::instance', __CLASS__ . ' requires two valid arguments.', 1 ); | |
return; | |
} | |
// Setting a static slug in the permalink structure takes care of most of this for us | |
wpcom_vip_load_permastruct( '/' . $this->permalink_structure ); | |
// Force certain rules to automatically respect the prefix | |
// Called several times because `WP_Rewrite` can overwrite this when other rules are added | |
add_filter( 'after_setup_theme', array( $this, 'set_rewrite_root' ) ); | |
add_filter( 'wp_loaded', array( $this, 'set_rewrite_root' ) ); | |
// Filter rules | |
add_filter( 'rewrite_rules_array', array( $this, 'filter_rewrite_rules' ) ); | |
// Intercept some requests and update them to reflect the new structure | |
add_action( 'parse_request', array( $this, 'parse_request' ) ); | |
// Override URL of static front-page, when applicable | |
add_filter( 'page_link', array( $this, 'filter_page_link' ), 10, 2 ); | |
add_filter( 'redirect_canonical', array( $this, 'filter_canonical_redirect' ), 10, 2 ); | |
} | |
/** | |
* Enforces custom URL prefix | |
* | |
* Uses Core functionality normally applied to sites whose permalink structures include `index.php` | |
*/ | |
public function set_rewrite_root() { | |
global $wp_rewrite; | |
$wp_rewrite->root = $this->rewrite_root . '/'; | |
} | |
/** | |
* Prepend all rules with the specified root | |
*/ | |
public function filter_rewrite_rules( $rules ) { | |
if ( ! is_array( $rules ) ) { | |
return $rules; | |
} | |
$prefixed_rules = array(); | |
foreach( $rules as $key => $value ) { | |
if ( 0 === strpos( $key, $this->rewrite_root ) ) { | |
$prefixed_rules[ $key ] = $value; | |
} else { | |
$new_key = $this->rewrite_root . '/' . $key; | |
$prefixed_rules[ $new_key ] = $value; | |
} | |
} | |
return $prefixed_rules; | |
} | |
/** | |
* Special handling for the homepage, which is normally detected by a lack of request params | |
*/ | |
public function parse_request( $request ) { | |
// Display main archive at new location | |
if ( $request->request === $this->rewrite_root ) { | |
// Lack of query args is how WP detects the homepage | |
$request->query_vars = array(); | |
} | |
// Redirect requests to root | |
if ( '' === $request->request ) { | |
wp_safe_redirect( user_trailingslashit( home_url( $this->rewrite_root ) ), 301 ); | |
exit; | |
} | |
} | |
/** | |
* Force static homepage to use new structure | |
* | |
* Core disobeys all other filtering and forces this to `home_url('/')` otherwise | |
*/ | |
public function filter_page_link( $link, $_page_id ) { | |
if ( 'page' === get_option( 'show_on_front' ) && (int) $_page_id === (int) get_option( 'page_on_front' ) ) { | |
$link = user_trailingslashit( home_url( $this->rewrite_root ) ); | |
} | |
return $link; | |
} | |
/** | |
* Correct canonical redirect for frontpage requests | |
*/ | |
public function filter_canonical_redirect( $redirect_url, $requested_url ) { | |
// Stop WP from sending front-page requests back to the root | |
if ( is_front_page() && false !== stripos( $requested_url, $this->rewrite_root ) && false === stripos( $redirect_url, $this->rewrite_root ) ) { | |
$parsed_redirect = parse_url( $redirect_url ); | |
$parsed_request = parse_url( $requested_url ); | |
// Only deal with requests for the frontpage and any pagination thereunder | |
if ( preg_match( "#^/{$this->rewrite_root}/?(page/([\d]+)/?)?#i", $parsed_request['path'] ) ) { | |
$match = '#^' . preg_quote( $parsed_redirect['scheme'] . '://' . $parsed_redirect[ 'host' ] . $parsed_redirect['path'] ) . '#i'; | |
$replace = user_trailingslashit( $parsed_redirect['scheme'] . '://' . $parsed_redirect['host'] . "/{$this->rewrite_root}" . $parsed_redirect['path'] ); | |
$redirect_url = preg_replace( $match, $replace, $redirect_url ); | |
} | |
} | |
return $redirect_url; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment