将小部件变量传递给外部函数

时间:2014-04-07 作者:Shane

我正在开发一个自定义小部件,它显示来自所选分类法(类别或标记)的帖子。此小部件包含一个文本框,用户输入分类法(类别或标记)的ID以从帖子中排除。此ID可能因小部件而异,因为此小部件的多个实例将出现在同一页面上,不包括不同的类别或标记。I am looking for a way to pass the $exclude variable from widget() to the excludeTheID() function which is located in functions.php

What I have tried: 将筛选器设置为调用excludeTheID()函数并传入$exclude的包装函数,但返回NULL。

在这个例子中,下面是我试图完成的一个模拟:

class testWidget extends WP_Widget {

    public function __construct() {
        // .......
    }

    public function form( $instance ) {
        // This widget contains a text field ($exclude)  that the user is to enter a taxonomy ID into.
    }

    public function update( $new_instance, $old_instance ) {
        // .......
    }

    public function widget( $args, $instance ) {
        // this value represents what the user would enter in the textbox of the widget
        $exclude = 15;
        // .......

        // This function does the work
        add_filter( "posts_where", "excludeTheID" );    

        // Create a new query
        $loop = new WP_Query();

        // Remove the filter
        remove_filter( "posts_where", "excludeTheID" );
    }
}

// FROM Functions.php: 
// External function responsible for generating the new WHERE clause using the  value in $exclude.

function excludeTheID( $where, $exclude )
{   

    $clauses = array(
        array(
            \'taxonomy\'  => \'category\',
            \'field\'     => \'id\',
            \'terms\'     => $exclude,
            \'operator\' => \'NOT IN\',
        ),
    );

    // Access the global WordPress DB variable
    global $wpdb;

    // Create the new WHERE Query string using the above arrays
    $tax_sql = get_tax_sql( $clauses, $wpdb->posts, \'ID\' );
    $where .= $tax_sql[\'where\'];

    return $where;
}
我不想使用globals来实现这一点,因为每个小部件将在页面上该小部件的每个实例中传递一个唯一的$exclude值。

任何指导都将不胜感激:)

谢谢

3 个回复
最合适的回答,由SO网友:Tom J Nowell 整理而成

首先,您需要您的代码将排除值存储在某处。

由于您不想使用全局(这样做是正确的),因此剩下的选项很少:

一个类,您已经拥有的类,一个闭包,一个标准API,选项1,一个新的对象/类,这里我们创建一个对象,它包含您要排除的类别,以及一些排除它的逻辑。

class wpse140557_exclude {
    $exclude = 0;
    public __construct( $exclude ) {
        $this->exclude = $exclude;
        add_filter( \'posts_where\', array( $this, \'exclude_filter\' ) );
    }
    public function exclude_filter( ... ) {
        // etc... using $this->exclude
    }
     public function remove_filter() {
        remove_filter( \'posts_where\', array( $this, \'exclude_filter\' ) );
     }
}

$exclude = new wpse140557_exclude( 12 ); // excluding category 12

// do some stuff/loops

$exclude->remove_filter(); // remove our filter
选项2闭包这里我们使用闭包,这些闭包需要使用PHP 5.3+

$exclude_closure = function (.. args...) use ( $exclude ) {
    // exclusion code $exclude
}

add_filter( \'posts_where\', $exclude_closure );

// do stuff

remove_filter(\'posts_where\', $exclude_closure );
选项3,您已经拥有的类将函数移到您的小部件类中,然后使用:

add_filter( "posts_where", array( $this, "excludeTheID" ) );

// do stuff

remove_filter( "posts_where", array( $this, "excludeTheID" ) );
然后使用$this->exclude访问/设置要排除的类别。这是选项1的一个不太通用的版本。

选项4,WP\\U查询

如果您查看了官方文档,您会发现有一个标题为“排除属于类别的帖子”的部分

这显示了两种无需额外功能即可完成所需操作的方法:

$query = new WP_Query( \'cat=-12,-34,-56\' );
以及

$query = new WP_Query( array( \'category__not_in\' => array( 2, 6 ) ) );
标签和其他分类法也有类似的参数

家庭作业我建议你仔细阅读以下内容:

函数和函数对象闭包和匿名函数什么是PHP可调用的,什么不是The WP_Query official codex page

SO网友:Rarst

我认为有两种方法可以实现这一点,具体取决于体系结构的其余部分。

将filter part方法设置为widget类的方法,而不是函数。

在内部将数据分配给其对象属性,该方法将对其具有干净的访问权限,而不会污染全局命名空间。

设置自定义查询变量。

将数据传递给WP_Query 构造函数,并对其进行筛选函数检查。你需要确保它是合理独特的,也许可以调整一些东西,以便WP_Query 没有放弃它(我上次这么做已经有一段时间了,不记得具体的实现细节)。

SO网友:gmazzap

首先\'posts_where\' filter(就像所有其他“posts\\u*”过滤器一样)不是很可靠,因为您假设where子句是标准的,但如果其他插件在your之前或之后使用相同的过滤器,那么在最好的情况下,结果不是预期的,在最坏的情况下,您只会得到错误的sql查询。

之后,当您可以直接构建查询参数时,为什么要使用过滤器?

如果目的是保存一个可以在小部件外部使用的外部函数,那么让该函数返回查询数组,而不是应用过滤器。

粗略代码作为概念证明:

// in widget class

public function widget( $args, $instance ) {

    $exclude = $instance[\'exclude\']; // this is what user have write in the widget form

    $query = new WP_Query( get_excluded_term_args( $exclude ) );

    if ( $query->have_posts() ) { while ( $query->have_posts() ) {
       $query->the_post();
       // echo stuff
    } wp_reset_postdata(); }

}


// in functions.php

function get_excluded_term_args( $exclude ) {
  return array(
    array(
        \'taxonomy\'  => \'category\',
        \'field\'     => \'id\',
        \'terms\'     => $exclude,
        \'operator\' => \'NOT IN\',
    ),
  );
}
以这种方式:

您不依赖不太可靠的“posts\\u where”过滤器,您可以重复使用get_excluded_term_args 要获取查询参数并与其他参数合并以构建复杂查询,它可以正常工作

结束

相关推荐

Widgets in the loop if active

我正在尝试将一个小部件作为“第一个帖子”,如果它处于活动状态。。然后让帖子继续。。它可以工作,但第一篇帖子消失了,第二篇帖子成为小部件后的第一行。。看不出我做错了什么。。正如你所看到的,我已经有一个小部件显示在帖子之间。<?php if (have_posts()) : ?> <?php $paged = (get_query_var(\'paged\')) ? get_query_var(\'paged\') : 1; ?> <?php $i=1;?>