restore_current_blog()与switch_to_blog()


23

在您的每个实例之后,switch_to_blog()应致电restore_current_blog()以恢复当前(实际上是上一个)博客。

但是,如果您要遍历两个或两个以上博客并分别调用switch_to_blog(),那么是否有理由不在switch_to_blog()循环结束时使用其他博客来切换到原始博客,而不是restore_current_blog()在每次通过时都进行调用。

例如

为什么不:

 $original_blog_id = get_current_blog_id();
 foreach( $blog_ids as $blog_id ){
    switch_to_blog( $blog_id );
    //Do stuff
 }
 switch_to_blog( $original_blog_id );

代替:

 foreach( $blog_ids as $blog_id ){
    switch_to_blog( $blog_id );
    //Do stuff
    restore_current_blog_id();
 }

现在我明白了,感谢您纠正了我的回答;)我正在修改所有内容。
brasofilo

Answers:


19

switch_to_blog()需要调用的每个实例之后,restore_current_blog()否则WP会认为它处于“交换”模式,并且可能会返回不正确的数据。

如果您查看这两个函数的源代码,则将看到这些函数将数据推送/弹出到名为的全局变量中$GLOBALS['_wp_switched_stack']。如果您不restore_current_blog()每次都打电话switch_to_blog()$GLOBALS['_wp_switched_stack']将为非空。如果$GLOBALS['_wp_switched_stack']为非空,即使您使用切换回原始博客,WP仍认为它处于切换模式switch_to_blog()。开关模式功能为ms_is_switched(),并且会影响wp_upload_dir()。如果wp_upload_dir()认为它处于切换模式,则可能返回不正确的数据。wp_upload_dir()为网站构建URL,因此这是非常关键的功能。

这是正确的用法:

 foreach( $blog_ids as $blog_id ){
    switch_to_blog( $blog_id );
    //Do stuff
    restore_current_blog();
 }

谢谢,我还没有机会研究wp_upload_dir()用于生成url 的常量和逻辑的全部内容,但是我想请您相信这确实会导致错误的行为。在任何情况下,ms_is_switched()手段的存在都会导致我的替代方法无法正常运行,并且可能会破坏插件以及核心。感谢
Stephen Harris

1
如果是这样,则Codex页面restore_current_blog()需要更新,因为它说对于多个开关,只需要保存当前开关,$blog_id然后使用多个switch_to_blog()调用即可。
Pat J

16

如果要运行多个博客,则无需每次都还原以前的博客。唯一增长的是$GLOBALS['_wp_switched_stack']–具有博客ID的数组,无需担心。

但是请记住,在第二次切换restore_current_blog() 后将不再起作用(!!!),因为它使用的是先前的博客-当时不是第一个博客。因此,存储第一个博客ID,然后致电…

switch_to_blog( $first_blog_id ); 
unset ( $GLOBALS['_wp_switched_stack'] );
$GLOBALS['switched'] = false; 

…而不是restore_current_blog()完成时。必须重置全局变量,否则您将遇到@ user42826提到的问题。

性能影响巨大。我在具有12个站点的本地安装上运行了一些测试:

$sites = wp_get_sites();

print '<pre>' . count( $sites ) . " sites\n";

timer_start();

print 'With restore_current_blog():    ';

foreach ( $sites as $site ) {
    switch_to_blog( $site[ 'blog_id' ] );
    restore_current_blog();
}

timer_stop( 1, 9 );

print "\nWithout restore_current_blog(): ";

timer_start();

$current_site = get_current_blog_id();

foreach ( $sites as $site ) {
    switch_to_blog( $site[ 'blog_id' ] );
}

switch_to_blog( $current_site );
$GLOBALS['_wp_switched_stack'] = array();
$GLOBALS['switched']           = FALSE;

timer_stop( 1, 9 );

print '</pre>';

结果:

12 sites
With restore_current_blog():    0.010648012
Without restore_current_blog(): 0.005203962

restore_current_blog()在每个开关之后使用,会使切换所需的时间加倍。


认为没有任何理由不这样做。感到困惑的是为什么restore_current_blog()不只检索先前的博客ID并致电switch_to_blog()-简要查看代码源,似乎有一些代码重复...
Stephen Harris

3
我不认为直接修改全局变量不是一个好主意,因为您会将代码耦合到Core的内部,这不是面向未来的。最好正确使用API​​。
伊恩·邓恩2014年

2
@IanDunn仅作记录:switch_to_blog()反正这是一个非常有限(已损坏)的API。如果WordPress可以解决此问题,则无论如何我们都必须重构代码。WordPress永远不会放弃其心爱的全球客户。
fuxia

2
@IanDunn I don't think modifying the globals directly is a good idea,不要告诉wp核心开发人员;)
Ejaz

1
@JD当然,您需要了解上下文。在已经切换状态的情况下,您甚至可能必须维护正确的堆栈索引。我可能会寻找避免这种情况的方法。另一方面,这是WordPress,所以可能没有其他方法……
fuxia

1

感谢@toscho回答。WP队列中的此请求-请参阅此处的更新。直到WP中已修复,如果有人迫切希望使用standard restore_current_blog(),那么这里是另一种方法(如果我错了,请更正):

发挥作用,即

function restore_original_blog_X(){

    if(!empty(($GLOBALS['_wp_switched_stack'][0])){
        $GLOBALS['blog_id']= $GLOBALS['_wp_switched_stack'][0];
        $GLOBALS['_wp_switched_stack'] = array($GLOBALS['_wp_switched_stack'][0]);
        restore_current_blog();
    }

}

并且完成多个开关后仅执行一次。(更多:wp-includes / ms-blogs.php

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.