用于本地和远程开发的 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_path;
$blog_id = get_current_blog_id();如果(!$切换){
$url = is_ssl() ? 'https://' : 'http://';
$url .= WP_DEVELOPMENT_DOMAIN;
如果(!is_main_site()){
$url .= rtrim( $path, '/' );
}返回 $url;
} 别的 {
$switched_path = $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_path, '/' );返回 $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 安装,该安装使用远程数据库。
您还应该能够将更改推送到远程服务器,并在远程站点上查看准确的副本。
故障排除、警告和问题!
不幸的是,许多(许多)事情可能会出错。 以下是一些症状和尝试的方法:
- 管理页面很好,但我无法访问任何内部前端页面!
- .htaccess 丢失或尚未初始化。 添加文件并重新保存您的永久链接。
- 更多即将推出!
在本地站点上工作时,如果您访问:
我的站点 > 网络管理员 > 仪表板
它将带您到远程站点,即:
example.com/wp-admin/network
这可能不是你想要的,但你可以直接在地址栏中输入并保留在本地环境中,即:
mysite-local/wp-admin/network
结论
如果一切顺利,您现在应该有一个工作设置,可以让您编写本地托管的 WordPress 安装,该安装使用远程数据库。
您还应该能够将更改推送到远程服务器,并在远程站点上查看准确的副本。
在下面的评论中,让我们知道您如何遵循 WordPress 多站点本地和远程开发的分步指南!
如果您在 Web 开发方面需要帮助,请随时与我们联系。
