Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ethitter/fb901b9afe0b2cd64fa1ad607b5067ed to your computer and use it in GitHub Desktop.
Save ethitter/fb901b9afe0b2cd64fa1ad607b5067ed to your computer and use it in GitHub Desktop.
WordPress.com VIP site in a subdirectory
<?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