用于本地和远程开发的 WordPress 多站点

已发表: 2021-07-19

在为 Web 开发时使用本地和远程环境是常见的做法。 在单个 WordPress 站点的情况下,这很好用。 但是,多站点 WordPress 安装使问题变得非常复杂。

在寻找 WordPress 多站点安装问题的解决方案时,我们在 Laubster Boy 上看到了 John Russel 撰写的一系列文章。 在这些文章中,他为远程开发和生产环境标出了解决此问题的方法,这与我们想要的非常接近。 通过一些修改,我们设法或多或少地对事情进行了排序。 但是,从那以后,WordPress 的某些更新破坏了该解决方案,我们不得不重新审视这个问题。

在本文中,我将向您展示我们如何使用各种资源和一些修补来解决这个问题。

意图

我们希望能够托管站点的本地安装和站点的远程安装,它们都运行在同一个(远程)数据库上。

问题

WordPress 多站点设置总是重定向到基本安装,在这种情况下:远程。 这使得很难在完全反映远程站点的开发代码库上工作。

为了解决这个问题,有必要运行两个使用不同数据库的安装。 这可能会导致混乱的冲突和同步问题,因为每次编辑时,都必须合并代码和数据库。

解决方案

我们将使用 WPMU 域映射插件。

请注意,此插件中的几个文件将被直接编辑,因此如果您出于任何原因更新插件,请务必记住这一点!

此过程假设您在远程和本地环境中安装了 WordPress 多站点。

每个步骤的以下步骤将被本地和远程分开,因为在每个位置拥有相同文件的不同版本很重要。

因此,完成后台设置后,让我们继续执行步骤!

本地和远程 WordPress 多站点的目录结构

作为参考,此设置在本地和远程环境中的文件结构如下:

 +-- wp-config.php
|
+-- .htaccess
|
+-- wp-内容
| |
| +--sunrise.php
| |
| +-- 插件
| |
| +-- wordpress-mu-domain-mapping
| |
| ++-- 更新日志.txt
| |
| +-- domain_mapping.php
| |
| +-- readme.txt
| |
| +--sunrise.php
| |
| +-- wordpress-mu-domain-mapping.php

1. 远程

本节提供远程文件和设置的详细信息。

1.1 wp-config.php

这不应在远程服务器上更改。

1.2 WordPress MU 域映射(远程!)

从这里下载WordPress MU 域映射插件:

https://en-gb.wordpress.org/plugins/wordpress-mu-domain-mapping/

在远程站点上安装并“网络激活”,以便它在所有站点上都处于活动状态。

1.3 日出.php

wordpress-mu-domain-mapping插件中的sunrise.php文件直接复制到wp-content目录中,使其位于此处:

/wp-content/sunrise.php

1.4 结束远程编辑

您现在已完成编辑远程站点。 访问几页以确保您没有破坏任何东西,我们就到此为止了。

2. 本地

本节显示应该在 localhost 上执行的操作。 一些代码是重复的,但为了完整性而显示所有代码。

2.1 wp-config.php

从下面复制代码并粘贴到您的 wp-config.php 文件中。 然后,您可以使用远程 wp-config.php(数据库等)中的详细信息更新它

您需要使用您的数据库详细信息等来更新它,但我们最终会得到一个类似于下面“代码清单 1:wp-config.php ”中所示的文档。

代码清单 1:wp-config.php


<?php

定义('环境','发展');
定义('WP_DEBUG_LOG',真);
定义('WP_DEBUG_DISPLAY',真);
定义('WP_DEBUG',真);

/* MySQL 设置 */

/** WordPress 的数据库名称 */
定义('DB_NAME','mysite_db');

/** MySQL 数据库用户名 */
定义('DB_USER','mysite_user');

/** MySQL 数据库密码 */
定义('DB_PASSWORD','***********');

/** MySQL 主机名 */
定义('DB_HOST','example.com');

/** 用于创建数据库表的数据库字符集。 */
定义('DB_CHARSET','utf8');

/** 数据库整理类型。 如果有疑问,请不要更改此设置。 */
定义('DB_COLLATE',”);

定义('AUTH_KEY','***********');
定义('SECURE_AUTH_KEY','***********');
定义('LOGGED_IN_KEY', '************');
定义('NONCE_KEY', '***********');
定义('AUTH_SALT','************');
定义('SECURE_AUTH_SALT','***********');
定义('LOGGED_IN_SALT','***********');
定义('NONCE_SALT', '************');

$table_prefix = 'wp_';

/* 多站点 */
定义('WP_ALLOW_MULTISITE',真);
定义('多站点',真);
定义('SUBDOMAIN_INSTALL',假);
定义('DOMAIN_CURRENT_SITE','example.com');
定义( 'PATH_CURRENT_SITE', '/' );
定义('SITE_ID_CURRENT_SITE',1);
定义('BLOG_ID_CURRENT_SITE',1);

定义('ADMIN_COOKIE_PATH','/');
定义('COOKIEPATH',”);
定义('SITECOOKIEPATH',”);

// WPMU 共享数据库的东西
定义('日出','开');
定义('WP_PRODUCTION_DOMAIN','example.com');
定义('WP_DEVELOPMENT_DOMAIN','mysite-local-domain');

/* 就是这样,停止编辑! 快乐的博客。 */

/** WordPress 目录的绝对路径。 */
如果(!定义('ABSPATH')){
定义('ABSPATH',目录名(__FILE__)。'/');
}

/** 设置 WordPress 变量和包含的文件。 */
require_once( ABSPATH . 'wp-settings.php' );

2.2 WordPress MU 域映射(本地!)

将相同的插件添加到本地站点。 根据远程站点,您可能认为就是这样,但您错了!

在您最喜欢的编辑器中打开文件domain_mapping.php并编辑第 708 和 709 行,因此整个 if 语句如下所示:

代码清单 2:domain_mapping.php


if ( $url && $url != untrailingslashit( $protocol . $current_blog->domain . $current_blog->path ) ) {
$redirect = get_site_option('dm_301_redirect') ? “301”:“302”;
if ( ( (defined( 'VHOST' ) && 常量( “VHOST” ) != 'yes' ) || (defined( 'SUBDOMAIN_INSTALL' ) && 常量( 'SUBDOMAIN_INSTALL' ) == false ) ) {
$_SERVER[ 'REQUEST_URI' ] = str_replace( $current_blog->path, '/', $_SERVER[ 'REQUEST_URI' ] );
}
// header(“位置:{$url}{$_SERVER['REQUEST_URI']}”, true, $redirect );
// 出口;
}

2.3 日出.php

首先,将sunrise.php 文件从wordpress-mu-domain-mapping 插件复制到wp-content 目录。 这里可能已经有一个sunrise.php 文件。 别担心 - 只需覆盖它。

从这里复制:

/wp-content/plugins/wordpress-mu-domain-mapping/sunrise.php

到这里:

/wp-content/sunrise.php

接下来,编辑这个新的sunrise.php 文件,在第 40 行附近添加几行,使其看起来像下面的代码:

代码清单 3:sunrise.php


<?php if (!defined('SUNRISE_LOADED')){define('SUNRISE_LOADED', 1); } if ( defined( 'COOKIE_DOMAIN' ) ) { die( '常量“COOKIE_DOMAIN”已定义(可能在 wp-config.php 中)。请删除或注释掉该define() 行。'); $wpdb->dmtable = $wpdb->base_prefix 。 '域_映射';
$dm_domain = $_SERVER['HTTP_HOST'];

if ( ( $nowww = preg_replace( '|^www.|', ”, $dm_domain ) ) != $dm_domain ) {
$where = $wpdb->prepare('domain IN (%s,%s)', $dm_domain, $nowww );
} 别的 {
$where = $wpdb->prepare('domain = %s', $dm_domain);
}

$wpdb->suppress_errors();
$domain_mapping_id = $wpdb->get_var(“SELECT blog_id FROM {$wpdb->dmtable} WHERE {$where} ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1”);
$wpdb->suppress_errors(false);
如果( $domain_mapping_id ){
$current_blog = $wpdb->get_row(“SELECT * FROM {$wpdb->blogs} WHERE blog_id = '$domain_mapping_id' LIMIT 1”);
$current_blog->domain = $dm_domain;
$current_blog->path = '/';
$blog_id = $domain_mapping_id;
$site_id = $current_blog->site_id;

定义('COOKIE_DOMAIN',$dm_domain);

$current_site = $wpdb->get_row(“SELECT * from {$wpdb->site} WHERE id = '{$current_blog->site_id}' LIMIT 0,1”);
$current_site->blog_id = $wpdb->get_var( “SELECT blog_id FROM {$wpdb->blogs} WHERE domain='{$current_site->domain}' AND path='{$current_site->path}'” );
如果(函数存在('get_site_option')){
$current_site->site_name = get_site_option('site_name');
} elseif (function_exists('get_current_site_name')){
$current_site = get_current_site_name( $current_site );
}

定义('DOMAIN_MAPPING',1);
}

/*
* 1) 添加了多站点代码
*/

// 过滤显示/输出为HTML的域
add_filter( 'pre_option_home', 'dev_pre_url_filter', 1 );
add_filter( 'pre_option_siteurl', 'dev_pre_url_filter', 1 );
add_filter('the_content', 'dev_content_filter', 100);
add_filter( 'content_url', 'dev_content_url_filter', 100, 2);
add_filter( 'post_thumbnail_html', 'dev_content_filter', 100);
add_filter('wp_get_attachment_link', 'dev_content_filter', 100);
add_filter('wp_get_attachment_url', 'dev_content_filter', 100);
add_filter( 'upload_dir', 'dev_upload_dir_filter', 10 );

函数 dev_pre_url_filter() {
全局 $wpdb, $path, $switched;
$网址;
$switched_pa​​th;
$blog_id = get_current_blog_id();

如果(!$切换){
$url = is_ssl() ? 'https://' : 'http://';
$url .= WP_DEVELOPMENT_DOMAIN;
如果(!is_main_site()){
$url .= rtrim( $path, '/' );
}

返回 $url;
} 别的 {
$switched_pa​​th = $wpdb->get_var(“SELECT path FROM {$wpdb->blogs} WHERE blog_id = {$blog_id} ORDER BY CHAR_LENGTH(path) DESC LIMIT 1”);
$url = is_ssl() ? 'https://' : 'http://';
$url .= WP_DEVELOPMENT_DOMAIN;
$url .= rtrim( $switched_pa​​th, '/' );

返回 $url;
}
}

函数 dev_content_filter( $post_content ) {
全球 $wpdb;

$blog_details = get_blog_details();
$original_url = $wpdb->get_var(“SELECT domain FROM {$wpdb->dmtable} WHERE blog_id = {$blog_details->blog_id} ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1”);
$dev_url = WP_DEVELOPMENT_DOMAIN 。 $blog_details->path;

if ( $original_url !== null ) {
$post_content = str_replace( $original_url .'/', $original_url, $post_content );
$post_content = str_replace( $original_url, $dev_url, $post_content );
}
// 将所有 url 更改为指向 staging(图像、锚点、帖子内容中的任何内容)
$post_content = str_replace( WP_PRODUCTION_DOMAIN, WP_DEVELOPMENT_DOMAIN, $post_content );
// 将“上传”的 url 更改为指向生产,以便图像可见
$post_content = str_replace( WP_DEVELOPMENT_DOMAIN . $blog_details->path . 'wp-content/uploads', WP_PRODUCTION_DOMAIN . $blog_details->path . 'wp-content/uploads', $post_content );

返回 $post_content;
}

/*
* 过滤 content_url 函数——专门寻找 content_url('upload') 调用,其中路径在字符串中有上传
*
* 添加以便 MU-Plugins 可以在 DEV 和 PROD 上使用 content_url
*/
函数 dev_content_url_filter( $url, $path ) {
if ( !empty( $path ) && strpos( $path, 'uploads' ) !== false ) {
返回 str_replace( WP_DEVELOPMENT_DOMAIN, WP_PRODUCTION_DOMAIN, $url );
}

返回 $url;
}

函数 dev_upload_dir_filter( $param ) {
$param['url'] = str_replace( WP_DEVELOPMENT_DOMAIN, WP_PRODUCTION_DOMAIN, $param['url'] );
$param['baseurl'] = str_replace( WP_DEVELOPMENT_DOMAIN, WP_PRODUCTION_DOMAIN, $param['baseurl'] );

返回 $param;
}

/*
* 替换 /wp-includes/ms-load.php get_site_by_path
*/
function dev_get_site_by_path( $_site, $_domain, $_path, $_segments, $_paths ) {
全局 $wpdb, $path;

// 为了在数据库中有一个可能的匹配,将 $_domain 设置为 WP_PRODUCTION_DOMAIN
$_domain = WP_PRODUCTION_DOMAIN;

// 搜索匹配域和第一个路径段的站点
$site = $wpdb->get_row( $wpdb->prepare( “SELECT * FROM $wpdb->blogs WHERE domain = %s and path = %s”, $_domain, $_paths[0] ) );
$current_path = $_paths[0];

如果( $site === null ){
// 专用于主博客 – 如果未找到站点,则加载主博客
$site = $wpdb->get_row( $wpdb->prepare( “SELECT * FROM $wpdb->blogs WHERE domain = %s and path = %s”, $_domain, '/' ) );
$current_path = '/';
}

// 设置路径以匹配第一段
$path = $current_path;

返回 $site;
}

add_filter( 'pre_get_site_by_path', 'dev_get_site_by_path', 1, 5);

3..htaccess(本地)

将以下内容插入到您的.htaccess文件中(请注意,本地目录已从最后的 index.php RewriteRule 行中删除):

代码清单 4:.htaccess


# 开始 WordPress
<IfModule mod_rewrite.c>;
重写引擎开启
重写基数 /
重写规则 ^index.php$ – [L]

# 在 /wp-admin 中添加一个斜杠
重写规则 ^wp-admin$ wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
重写规则 ^ – [L]
重写规则 ^(wp-(content|admin|includes).*) $1 [L]
重写规则 ^(.*.php)$ $1 [L]
重写规则。 /index.php [L]
</IfModule>;

# 结束 WordPress

4. 虚拟主机

设置虚拟主机,以便您可以在浏览器地址栏中输入 wp-config.php(以上)中为WP_DEVELOPMENT_DOMAIN提供的值并访问该站点。 通常你会输入 localhost,但这会覆盖它。

在示例代码(上面)中,虚拟主机被设置为在地址栏中使用“price-buckland”并指向包含 WordPress 的目录。

MAMP环境下添加虚拟主机的流程如下:

1)在终端:

 $ sudo vi /etc/hosts

2) 添加以下行,根据您要在浏览器中输入的地址进行替换:

 127.0.0.1 mysite-本地域

3)接下来,我们要为您的本地环境激活虚拟主机,因此打开以下文件进行编辑:

 $ sudo vi /Applications/MAMP/conf/apache/httpd.conf

找到这些行:

 # 虚拟主机
# 包含 /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf

并取消注释“包含”行,如下所示:

 # 虚拟主机
包括/Applications/MAMP/conf/apache/extra/httpd-vhosts.conf

4)现在编辑以下文件:

 $ sudo vi /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf

并添加两个条目——首先在浏览器中允许“localhost”,其次,添加新的虚拟主机,使您能够在浏览器中键入自定义域并访问本地服务器:

 DocumentRoot "/Users/用户名/htdocs/"
    服务器名称本地主机


    DocumentRoot "/Users/username/htdocs/mysite-local-directory"
    服务器名称 mysite-local-domain

5)重启apache服务器。 在我的情况下,MAMP,但从命令行运行:

 apachectl重启

如果一切顺利,您现在应该有一个工作设置,可以让您编写本地托管的 WordPress 安装,该安装使用远程数据库。

您还应该能够将更改推送到远程服务器,并在远程站点上查看准确的副本。

故障排除、警告和问题!

不幸的是,许多(许多)事情可能会出错。 以下是一些症状和尝试的方法:

    1. 管理页面很好,但我无法访问任何内部前端页面!
    2. .htaccess 丢失或尚未初始化。 添加文件并重新保存您的永久链接。
    3. 更多即将推出!

在本地站点上工作时,如果您访问:

 我的站点 > 网络管理员 > 仪表板

它将带您到远程站点,即:

 example.com/wp-admin/network

这可能不是你想要的,但你可以直接在地址栏中输入并保留在本地环境中,即:

mysite-local/wp-admin/network

结论

如果一切顺利,您现在应该有一个工作设置,可以让您编写本地托管的 WordPress 安装,该安装使用远程数据库。

您还应该能够将更改推送到远程服务器,并在远程站点上查看准确的副本。

在下面的评论中,让我们知道您如何遵循 WordPress 多站点本地和远程开发的分步指南!


如果您在 Web 开发方面需要帮助,请随时与我们联系。