Skip to content

Instantly share code, notes, and snippets.

@mjangda
Created January 18, 2012 22:46
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mjangda/1636304 to your computer and use it in GitHub Desktop.
Save mjangda/1636304 to your computer and use it in GitHub Desktop.
How to use WordPress across environments without needing to mess with URLs in the database.
<?php
// This is the meat of the plugin and should go in mu-plugins/0-env-url-override.php
// Only load these filters if we're not in the production environment
if ( defined( 'ENV_NOT_PRODUCTION' ) && ENV_NOT_PRODUCTION ) {
// This always needs to be filtered
add_filter( 'site_url', 'env_filter_site_url', 0 );
// We don't filter home_url in the admin so that we get production URLs for posts.
// This does break certain links like "Preview/View Post", however.
// If local post permalinks in content isn't an issue, then the is_admin check should be removed
if ( ! is_admin() )
add_filter( 'home_url', 'env_filter_home_url', 0 );
// Output buffering will sweep up any remaining URLs and point them to local versions.
// This is only run in the front-end to allow media uploads to work correctly.
// However, the side effect is that images appear broken in the admin.
// This can be probably resolved by using a central CDN for all environments.
if ( ! is_admin() )
ob_start( 'env_str_replace_links' );
// This is our hack-around to fix links in the admin that point to our production URL because we don't run home_url in the admin
// This is less than ideal and still doesn't catch everything
add_action( 'admin_footer', 'env_str_replace_links_js', 99 ); // load late so we know jQuery is available
// Filter these URLs since they use constants that are defined very early.
add_filter( 'plugins_url', 'env_filter_site_url', 0 ); // This is needed mainly for the admin, otherwise output buffering handles the URLs
//add_filter( 'content_url', 'env_filter_site_url', 0 ); // This one shouldn't be needed since we have output buffering
// Filtering the permalink probably isn't necessary.
//add_filter( 'post_link', 'env_filter_home_url', 0 );
}
function env_filter_home_url( $url ) {
if ( strpos( $url, WP_HOME ) === 0 )
return str_replace( WP_HOME, ENV_LOCAL_HOME, $url );
return $url;
}
function env_filter_site_url( $url ) {
if ( strpos( $url, WP_SITEURL ) === 0 )
return str_replace( WP_SITEURL, ENV_LOCAL_SITEURL, $url );
return $url;
}
// Filter all content and replace any production URLs with appropriate dev URLs
// http://groups.google.com/group/wp-hackers/browse_thread/thread/55e8bf607c456b17/ab20214865c36726
function env_str_replace_links( $content ) {
$content = str_replace( WP_HOME, ENV_LOCAL_HOME, $content );
return $content;
}
function env_str_replace_links_js() {
// I'm sure this can be done in a cleaner way, but for now, speed wins over grace :)
?>
<script>
var env_home = '<?php echo esc_js( WP_HOME ); ?>';
var env_home_replace = '<?php echo esc_js( ENV_LOCAL_HOME ); ?>'; // using the constants directly, because home_url() isn't filtered
var env_siteurl = '<?php echo esc_js( WP_SITEURL ); ?>';
var env_home_replace = '<?php echo esc_js( ENV_LOCAL_SITEURL ); ?>';
jQuery( 'a[href]' ).each( function() {
var href_replace = '',
href = this.getAttribute( 'href' );
if ( -1 < href.indexOf( env_home ) )
href_replace = href.replace( env_home, env_home_replace );
else if ( -1 < href.indexOf( env_siteurl ) )
href_replace = href.replace( env_siteurl, env_siteurl_replace );
if ( href_replace )
this.setAttribute( 'href', href_replace );
} );
</script>
<?php
}
// Debug
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( var_export( array(
'home_url: ' . home_url(),
'WP_HOME: ' . WP_HOME,
'site_url: ' . site_url(),
'WP_SITEURL: ' . WP_SITEURL,
'LOCAL_HOME: ' . ENV_LOCAL_HOME,
'LOCAL_SITEURL: ' . ENV_LOCAL_SITEURL,
'WP_CONTENT_DIR: ' . WP_CONTENT_DIR
), true ) );
} );
// Remote: mysite.com
// Stating: preprod.mysite.com
// QA: qa.mysitetesting.com
// Local: localhost/mysite
// Production URLs are hardcoded in wp-config.php using the WP_HOME and WP_SITEURL constants.
// When $_SERVER['HTTP_HOST'] doesn't match our production URL, we assume that we're in a non-production environment.
// In this context, we filter production URLs and replace with local URL.
// We use output buffering to sweep up any URLs missed by the filters.
<?php
// This code should be added to wp-config.php
// Hard-code the values of our production environment
define( 'WP_HOME', 'http://notlocal.digitalize.ca' );
define( 'WP_SITEURL','http://notlocal.digitalize.ca' );
switch ( $_SERVER['HTTP_HOST'] ) {
case 'localhost': // Our localhost install is in a subfolder, so we're overriding the URLs here
define( 'ENV_LOCAL_HOME', 'http://localhost/wp31' );
define( 'ENV_LOCAL_SITEURL', 'http://localhost/wp31' );
break;
// Other environments that use subfolders should go here as well
// Use this to customize other constants across environments
default: // default to HTTP_HOST
define( 'ENV_LOCAL_HOME', 'http://' . $_SERVER['HTTP_HOST'] ); // this needs be changed if https should be supported
define( 'ENV_LOCAL_SITEURL', 'http://' . $_SERVER['HTTP_HOST'] ); // this needs be changed if https should be supported
break;
}
define( 'ENV_NOT_PRODUCTION', WP_HOME !== ENV_LOCAL_HOME );
if ( ENV_NOT_PRODUCTION ) {
// Override the COOKIEHASH in non-production environments
// We need to do this since COOKIEHASH is based off the siteurl and auth will fail
define( 'COOKIEHASH', md5( ENV_LOCAL_HOME ) );
}
@wpmnger
Copy link

wpmnger commented Sep 12, 2013

Using a variant of your code here and added the following for WPML to work:
add_filter ( 'option_home' , 'env_filter_home_url'); // This is needed to enable WPML

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment