0

I've googled a lot, and I do have found answers at WordPress SE and at stackoverflow.com. However, the answers are somewhat incomplete or doesn't work at all. Here I'll explain my problem in detail, give my progress on the problem and the obstacles I'm facing in solving the problem.

Assumptions:-

  1. Plugins and themes at both the websites are pre-installed, and they are exactly same.
  2. Uploads folder is also same.

Assumptions indicate the current status of the folders. It doesn't assumes that they are being synchronized as the following process starts.

Problem:-

  1. There is a site A and site B.
  2. If any posts, pages, products, images, slider images, menus, menu items, categories, SEO settings etc of site A or site B is changed then it should be changed for the other website too.
  3. If a post or product is published with a category containing a prefix ABC- (e.g. ABC-Windows Tips) then that post or product should only appear on site B.

Current Progress:-

I didn't come up with a reasonable solution, but I connected site B to site A's database by editing wp-config.php.

I also copy pasted the following code for both of the sites respectively:-

Site A:-

define('WP_HOME','http://siteA.com');
define('WP_SITEURL','http://siteA.com');

Site B:-

define('WP_HOME','http://siteB.com');
define('WP_SITEURL','http://siteB.com');

Obstacles:-

  1. My admin password for site B has been changed to the site A's password. (I'm not sure if this is going ALRIGHT or MESSED UP. If you can help me in this then that would be great.)
  2. The uploads folder is not being synchronized. Media items uploaded via Site A are only visible at Site A. Featured images of posts are going 404 on site B. We can either make the uploads folder to synchronize between two different web hostings. Or make it such that site B starts picking images from site 'A' uploads folder. Something like defining constants like we did for home and siteurl i.e. WP_HOME and WP_SITEURL.
  • To understand and take the problem in a reverse way, what's the difference between site A and B ? Only the theme ? – Simon Nov 16 '13 at 13:21
  • theme is same. Differences:- 1 domain name 2 woocommerce currency 3 site B will display some additional products and posts besides what's already at site A. – Omar Tariq Nov 16 '13 at 13:29
2

Once you have same db, you will have same users, so offcouse the password for the user 'admin' (please do not use 'admin' as username) will be the one setted in database, and of course is the same for the 2 sites, once they shared the db.

However you can create users that can login only in one site and users that can login in the other.

To do that, add a field to the users profile called 'User Site' that will save the value entered on the user meta 'user_site'.

function site_profile_field( $user ) {
    if ( ! current_user_can('promote_users') ) return; // only for admins
    echo '<h3>' . __('User Site') . '</h3>';
    echo '<table class="form-table">';
    $now = get_user_meta( $user->ID, 'user_site', true ) ? : "";
    echo '<tr><th><label for="user_site">' .  __('Enter the domain') . '</label></th>';
    printf(
      '<td><input type="text" name="user_site" id="user_site" value="%s" /></td></tr>',
      esc_attr($now)
    );
    echo '</table>';
}
add_action( 'show_user_profile', 'site_profile_field' );
add_action( 'edit_user_profile', 'site_profile_field' );


function site_profile_field_save( $user_id ) {
   if ( ! current_user_can( 'edit_user', $user_id ) ) return;
   $site = filter_input(INPUT_POST, 'user_site', FILTER_SANITIZE_URL);
   if ( $site ) {
     update_user_meta( $user_id, 'user_site', $site );
   }
}
add_action( 'personal_options_update', 'site_profile_field_save' );
add_action( 'edit_user_profile_update', 'site_profile_field_fields_save' );

Then everytime a user log to site you can check that meta and compare to the WP_SITEURL constant, if no match you can block the user

add_action( 'wp_authenticate', 'check_user_site', 1, 2 );

function check_user_site( $username, $password ) {
  if ( ! defined('WP_SITEURL') ) return;
  $user = get_user_by( 'login', $username );
  if ( $user->exists ) {
     $allowed = get_user_meta($user->ID, 'user_site', true);
     if ( $allowed ) {
       $domain = parse_url(WP_SITEURL, PHP_URL_HOST);
       $allowed_domain = parse_url($allowed, PHP_URL_HOST);
       if ( ! substr_count( $domain, $allowed_domain ) ) {
         $password = NULL; // set password to null in this way login will fail
       }
     }
  }
}

If the 'User Site' field is left blank or WP_SITEURL is not defined the user will be able to login in both sites.

This for the first problem.

For the second (upload sync) you can set the site B to use the site A uploads folder, but doing so, every upload should be done in site A, so if users of site B want to upload a file they can't.

This can be done using adding a setting WP_CONTENT_URL in config.php, so you'll have (just after the definition of ABSPATH)

define('WP_HOME', 'http://siteB.com');
define('WP_SITEURL', 'http://siteB.com');
define('WP_CONTENT_DIR', ABSPATH . 'wp-content');
define('WP_CONTENT_URL', 'http://www.siteA.com/wp-content');

So you have to upload all files in site A, and then using this config on site B, when you use a proper function to get an attachment url (wp_get_attachment_url and similar) WordPress will return the url of site A. For post that contain media url in the body, once are all uploaded on site a, the already containt the url of site A.

A more flexible solution, that allow you to upload files from both sites, can be use for uploads an external file base, e.g Amazon S3 and serve urls via Amazon Cloudfront. This plugin will make your life easy in doing this. Other plugin like this provide functionalities to use other services for same pourpose, however googling it will be easy find a plugin that works with your favourite service.

  • You have also commented on my other question so I guess you might be getting what I'm trying to do. Can you please update your answer to further explain how can I do the workaround you said For the second (upload sync) you can set the site B to use the site A uploads folder, but doing so, every upload should be done in site A, so if users of site B want to upload a file they can't. – Omar Tariq Nov 16 '13 at 7:56
  • @OmarTariq answer updated – gmazzap Nov 16 '13 at 11:45
  • I believe that I've to write the most latest code in Site B's config.php. If this is so then the first two lines should be define('WP_HOME', 'http://siteB.com');define('WP_SITEURL', 'http://siteB.com');. Am I right? – Omar Tariq Nov 16 '13 at 12:30
  • @OmarTariq yes, my bad... copy & paste hurts sometimes – gmazzap Nov 16 '13 at 12:46
1

I have some modifications that I make in wp-config.php that allow for WordPress to work with my version control process. I think with some adjustments the modifications could work for your purpose as well.

1) Make URLs relative instead of absolute.

This is useful because WordPress likes to write absolute URLS to the database, but since you're serving the same content from different URLS this would get messy.

Add the following to wp-config.php on both servers

define('WP_SITEURL', 'http://' . $_SERVER['SERVER_NAME'] );
define('WP_HOME', 'http://' . $_SERVER['SERVER_NAME']);
define('WP_CONTENT_DIR', $_SERVER['DOCUMENT_ROOT'] . '/wp-content');
define('WP_CONTENT_URL', '/wp-content');
define('FS_CHMOD_DIR', (0755 & ~ umask()));
define('FS_CHMOD_FILE', (0644 & ~ umask()));
define('UPLOADS', WP_CONTENT_URL . '/uploads');

2) Define database credentials for both (or more) environments

In your case the database credentials would be the same for both servers.

Your username and password will be the same on both sites.

Replace the portion of wp-config.php where you define database credentials with the following:

// define environments
$environments = array(
    'server1' => array(
        'address' => array( 'domain1.com', 'www.domain1.com' ),
        'db' => array(
            'name' => '',
            'user' => '',
            'password' => '',
            'host' => 'localhost',
            'charset' => 'utf8',
            'collate' => ''
        ),
        'ssl' => false,
        'dev' => false
    ),
    'server2' => array(
        'address' => array( 'domain1.com', 'www.domain2.com' ),
        'db' => array(
            'name' => '',
            'user' => '',
            'password' => '',
            'host' => '',
            'charset' => 'utf8',
            'collate' => ''
        ),
        'ssl' => false,
        'dev' => false
    )
);

// allows wildcards in the array to be searched
function better_in_array( $needle, $haystack ) {
    foreach ($haystack as $value) {
        if ( fnmatch( $value, $needle ) === true ) {
            return true;
        }
    }
    return false;
}

// loop through environments to get proper db credentials
foreach( $environments as $key => $env ) {

    if ( better_in_array( $_SERVER['SERVER_NAME'] , $env['address'] ) ) {

        // if we find a matching environment, apply db credentials
        define( 'DB_NAME',  $env['db']['name']  );
        define( 'DB_USER',  $env['db']['user']  );
        define( 'DB_PASSWORD',  $env['db']['password']  );
        define( 'DB_HOST',  $env['db']['host']  );
        define( 'DB_CHARSET',   $env['db']['charset']   );
        define( 'DB_COLLATE',   $env['db']['collate']   );

        if ( $env['ssl'] == true ) {
            define( 'FORCE_SSL_ADMIN', true );
        }

        if ( $env['dev'] == true ) {
            define( 'WP_DEBUG', true );  // Turn debugging ON
            define( 'WP_DEBUG_DISPLAY', false ); // Turn forced display OFF
            define( 'WP_DEBUG_LOG', true );  // Turn logging to wp-content/debug.log ON
        }

        $environment = $key;

        break; // break foreach if we find a match
    }
}

// make sure all db constants are set.
if ( !defined( 'DB_NAME' ) || !defined( 'DB_USER' ) || !defined( 'DB_PASSWORD' ) || !defined( 'DB_HOST' ) || !defined( 'DB_CHARSET' ) || !defined( 'DB_COLLATE' ) ) {
    echo 'Environment not configured.';
    exit;
}

3) Sync the uploads between servers.

There are several ways to do this and how you do it may actually depend on your server setups. rsync? Store uploads in an Amazon S3 bucket? BitTorent Sync could be useful (and free). A quick google search turned up this tutorial: http://blog.bittorrent.com/2013/09/17/sync-hacks-how-to-set-up-bittorrent-sync-on-ubuntu-server-13-04/

Things like core, plugin and template updates need to be synced too. Ordinarily I would hold all this in version control and deploy to both servers to handle this. Potentially you could accomplish this by setting the entire site to sync instead of just the uploads directory but I have no experience with this and am unaware of this would cause any issues.

  • It's not. Everything is being served from a single database. – Joey Yax Nov 15 '13 at 2:33
  • So your environments stuff - here - is pretty useless... And 1st OP problem is not solved. In addition when I use version control for 2 or more sites I prefer to ignore wp-confing.php and manually change it in every environment: all my passwords in same file (and in general version controlling files with password) doesn't seem a good choice for me, but this is an option. – gmazzap Nov 15 '13 at 8:27
  • I believe I covered all of the problems and obstacles mentioned by the OP. The environment portion of this certainly isn't required. My reasoning for providing it you have only a single code-set so no changes to the code are being made on individual servers. If you don't like the passwords in a single file you could just as easily only deploy the relevant credentials to the appropriate server. – Joey Yax Nov 15 '13 at 17:04
  • @JoeyYax I tried to use rsync, but I don't have SSH access to the site. I believe that I've pretty much constraints by the web hosting company as it is a shared web hosting. I'm thinking of either synchronizing the uploads folder or pointing site B to use site A's uploads folder. However, I would like to know that what good your first point did 1) Make URLs relative instead of absolute.? I didn't see any changes to the site and the 404 images problem is not fixed either? – Omar Tariq Nov 16 '13 at 8:57
  • 1
    Lack of SSH makes this pretty difficult but not impossible. Your best bet would probably be to use an external service like Amazon S3 to store uploads. The change to the URLS made in the first step will not work retroactively for images and links that are already embedded - you'll have to run a find/replace on the database. This is a good tool for running the find/replace. If you check the page source you'll notice many URLS no longer contain the domain and new links/embeds won't either. – Joey Yax Nov 16 '13 at 22:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.