如何为WP_Query创建灵活的抽象?


8

我的问题是关于php的,但是在我创建插件时涉及到wordpress。情况是我有5个问题,每个问题有6个选择,每个选择一个。现在,此人可以从每个选择中选择一个,也可以选择几个。我已经创建了if条件,现在该条件使我发疯,因为它已经太久了,并且会进一步发展,就像将进行近100种组合一样。我不希望那样,我知道有一种多维数组的方法,但是不是wordpress的插件或PHP专家。因此,如果有人可以为我排序。

$qs = $_POST['q1'];
$q2 = $_POST['q2'];
$q3 = $_POST['q3'];
$q4 = $_POST['q4'];
$q5 = $_POST['q5'];
$q6 = $_POST['q6'];



 $args = array(
  'post_type' => 'product',
  'posts_per_page' => -1,
  'tax_query' => array(
    'relation' => 'AND',
    array(
     'taxonomy' => 'product_cat',
     'field' => 'slug',
     'terms' => 'fashion-follower'
    ),
//    array(
//     'taxonomy' => 'product_cat',
//     'field' => 'slug',
//     'terms' => 'cheap-and-cheerful'
//    )
  )
);
 //The Fashionsia
 if (($qs ==='party') && ($q2 === 'clothes') && ($q3 === 'shopping') && ($q5 === 'Sunbathing') && ($q6 === 'mini')){

$query = new WP_Query( $args );
if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();

     the_post_thumbnail('thumbnail');

endwhile;
    endif;      
}

//second question loop

$args2 = array(
  'post_type' => 'product',
  'posts_per_page' => -1,
  'tax_query' => array(
    'relation' => 'AND',
    array(
     'taxonomy' => 'product_cat',
     'field' => 'slug',
     'terms' => 'the-homemaker'
    ),
//    array(
//     'taxonomy' => 'product_cat',
//     'field' => 'slug',
//     'terms' => 'cheap-and-cheerful'
//    )
  )
);
 //The homemaker
 if (($qs ==='drink') && ($q2 === 'candles') && ($q3 === 'house') && ($q4 === 'diy')){

$query = new WP_Query( $args2 );
if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();

     the_post_thumbnail('thumbnail');

endwhile;
    endif;      
}
//third loop

$args3 = array(
  'post_type' => 'product',
  'posts_per_page' => -1,
  'tax_query' => array(
    'relation' => 'AND',
    array(
     'taxonomy' => 'product_cat',
     'field' => 'slug',
     'terms' => 'entertainment'
    ),
//    array(
//     'taxonomy' => 'product_cat',
//     'field' => 'slug',
//     'terms' => 'cheap-and-cheerful'
//    )
  )
);
 //The Entertainer
 if (($qs ==='party-babe') && ($q2 === 'winer')&& ($q4 === 'storm') && ($q6 === 'limo')){

$query = new WP_Query( $args3 );
if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();

     the_post_thumbnail('thumbnail');

endwhile;
    endif;      
}
//fourth loop
$args4 = array(
  'post_type' => 'product',
  'posts_per_page' => -1,
  'tax_query' => array(
    'relation' => 'AND',
    array(
     'taxonomy' => 'product_cat',
     'field' => 'slug',
     'terms' => 'family-fanatic'
    ),
//    array(
//     'taxonomy' => 'product_cat',
//     'field' => 'slug',
//     'terms' => 'cheap-and-cheerful'
//    )
  )
);
 //The family-fanatic
 if (($qs ==='movie') && ($q2 === 'kids')&& ($q6 === 'volvo')){

$query = new WP_Query( $args4 );
if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();

     the_post_thumbnail('thumbnail');

endwhile;
    endif;      
}
//fifth loop
//fourth loop
$args4 = array(
  'post_type' => 'product',
  'posts_per_page' => -1,
  'tax_query' => array(
    'relation' => 'AND',
    array(
     'taxonomy' => 'product_cat',
     'field' => 'slug',
     'terms' => 'family-fanatic'
    ),
//    array(
//     'taxonomy' => 'product_cat',
//     'field' => 'slug',
//     'terms' => 'cheap-and-cheerful'
//    )
  )
);
 //The romantic
 if (($qs ==='Dinner-show') && ($q5 === 'cruiser')){

$query = new WP_Query( $args4 );
if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();

     the_post_thumbnail('thumbnail');

endwhile;
    endif;      
}

您之前的问题有什么区别?
fuxia

@toscho的不同之处在于,问:关于重构的问题,但是现在我要优化代码以及wp循环或将其以数组形式进行。
2013年

Answers:


18

您的问题不是关于WordPress的,而是有关PHP和重构的。但是我们在这里看到了很多糟糕的代码,我将在下面解释的模式(MVC)可以帮助许多其他开发人员,因此我决定写一些答案。请记住,我们的网络中有一个专门的站点来解决此类问题:代码审查。不幸的是,很少有WordPress开发人员在那里活跃。


如何重构代码

  1. 删除无用的代码。美化其余的。
  2. 查找所有重复的表达式并创建例程(函数或类)以抽象并封装这些表达式。
  3. 将数据处理,模型(存储,提取,转换,解释)与输出,视图(HTML,CSV等)分开。

1.删​​除无用的代码。美化其余的。

输出

您有以下重复代码段:

if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();

the_post_thumbnail('thumbnail');

endwhile;
endif;

the_post()每次都要运行相当昂贵的操作才能获取帖子缩略图。但这不是必需的,您可以致电:

echo get_the_post_thumbnail( $post_id, 'post-thumbnail' );

查询

因此,您只需要职位ID,而无需致电即可使用the_post()。甚至更好:您可以将查询限制为获取ID。

一个简单的例子:

$post_ids = array();
$args     = array(
    'post_type'      => 'post',
    'posts_per_page' => 10,
    'fields'         => 'ids'
);
$query    = new WP_Query( $args );

if ( ! empty ( $query->posts ) )
    $post_ids = $query->posts; // just the post IDs

现在您有了ID,您可以编写:

foreach ( $post_ids as $post_id )
    echo get_the_post_thumbnail( $post_id, 'post-thumbnail' );

没有开销,您的代码已经更快,更易于阅读。

语法

注意我如何对齐=?这有助于理解代码,因为人类的思维专长于模式识别。支持这一点,我们可以做一些很棒的事情。造成混乱,我们很快就会陷入困境。

这也是我删除endwhile和的原因endif。该替代语法是混乱和难以阅读。另外,它使在IDE中的工作更加困难:使用花括号,可以轻松地从表达式的开始到结尾进行折叠和跳转。

默认值

你的$args阵列有你到处使用的一些领域。创建一个默认数组,然后只写一次这些字段:

$args = array(
    'post_type'      => 'product',
    'posts_per_page' => 100,
    'fields'         => 'ids',
    'tax_query'      => array(
        array(
            'taxonomy' => 'product_cat',
            'field'    => 'slug',
        )
    )
);

再次注意对齐。还要注意我如何更改posts_per_page值。 永远不要要求-1。如果有一百万个匹配的职位会怎样?您不想每次查询运行时都终止数据库连接吗?谁应该阅读所有这些帖子?始终设置合理的限制。

现在您所要做的就是更改字段$args[ 'tax_query' ][ 'terms' ]。我们将在稍后讨论。

2.查找所有重复的表达式并创建例程

我们已经清理了一些重复的代码,现在是最困难的部分:POST参数的评估。显然,由于某些参数,您已经制作了一些标签。我建议将其重命名为更易于理解的名称,但现在我们将使用您的命名方案。

将这些组与其余组分开,创建一个数组,以后可以分别管理:

$groups = array(
    'fashion-follower' => array(
        'q1' => 'party',
        'q2' => 'clothes',
        'q3' => 'shopping',
        'q4' => FALSE,
        'q5' => 'sunbathing',
        'q6' => 'mini',
    ),
    'the-homemaker' => array(
        'q1' => 'drink',
        'q2' => 'candles',
        'q3' => 'house',
        'q4' => 'diy',
        'q5' => FALSE,
        'q6' => FALSE,
    )
);

要填充terms默认数组中的缺失字段,请遍历 $groups数组直到找到匹配项:

function get_query_term( $groups )
{
    foreach ( $groups as $term => $values )
    {
        if ( compare_group_values( $values ) )
            return $term;
    }

    return FALSE;
}

function compare_group_values( $values )
{
    foreach ( $values as $key => $value )
    {
        // Key not sent, but required
        if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) )
            return FALSE;

        // Key sent, but wrong value
        if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value )
            return FALSE;
    }

    // all keys matched the required values
    return TRUE;
}

我将整个术语列表和值的比较都分开了,因为它们是不同的操作。代码的每一部分都应该做一件事,并且必须保持缩进级别平坦以提高可读性。

现在我们拥有了所有零件,让我们将它们粘在一起。

3.组织:从视图中分离模型

在编写模型视图时,我想到了一些东西:MVC方法。它代表Model View Controller模型视图控制器),这是一种用于组织软件组件的众所周知的模式。到目前为止,缺少的部分是控制器,稍后我们将了解如何使用它。

您说过,您对PHP不太了解,所以希望您对输出有所了解。:)让我们开始:

class Thumbnail_List
{
    protected $source;

    public function set_source( Post_Collector_Interface $source )
    {
        $this->source = $source;
    }

    public function render()
    {
        $post_ids = $this->source->get_post_ids();

        if ( empty ( $post_ids ) or ! is_array( $post_ids ) )
            return print 'Nothing found';

        foreach ( $post_ids as $post_id )
            echo get_the_post_thumbnail( $post_id, 'post-thumbnail' );
    }
}

简单又好用:我们有两种方法:一种是设置帖子ID的来源,另一种是呈现缩略图的方法。

您可能想知道这Post_Collector_Interface是什么。我们马上解决。

现在,我们的视图的来源是模型。

class Post_Collector implements Post_Collector_Interface
{
    protected $groups = array();

    public function set_groups( Array $groups )
    {
        $this->groups = $groups;
    }

    public function get_post_ids()
    {
        $term = $this->get_query_term();

        if ( ! $term )
            return array();

        return $this->query( $term );
    }

    protected function query( $term )
    {
        $args = array(
            'post_type'      => 'product',
            'posts_per_page' => 100,
            'fields'         => 'ids',
            'tax_query'      => array(
                array(
                    'taxonomy' => 'product_cat',
                    'field'    => 'slug',
                    'terms'    => $term
                )
            )
        );

        $query = new WP_Query( $args );

        if ( empty ( $query->posts ) )
            return array();

        return $query->posts;
    }

    protected function get_query_term()
    {
        foreach ( $this->groups as $term => $values )
        {
            if ( compare_group_values( $values ) )
                return $term;
        }

        return FALSE;
    }

    protected function compare_group_values( $values )
    {
        foreach ( $values as $key => $value )
        {
            // Key not sent, but required
            if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) )
                return FALSE;

            // Kent sent, but wrong value
            if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value )
                return FALSE;
        }

        // all keys matched the required values
        return TRUE;
    }
}

这不再是琐碎的事了,但是我们已经拥有了大部分内容。这些protected 方法(功能)无法从外部访问,因为我们仅将它们用于内部逻辑。

public方法是简单的:所述第一获取我们的$group阵列从上面,所述第二返回柱ID数组。我们再次遇到这个可疑的地方Post_Collector_Interface

一个接口是一个合同。可以按类签名(实现)。需要的接口,像我们班Thumbnail_List确实,指:类预期一些 与这些公共方法的其他类。

让我们构建该界面。真的很简单:

interface Post_Collector_Interface
{
    public function set_groups( Array $groups );

    public function get_post_ids();
}

是的,仅此而已。简单的代码,不是吗?

我们在这里所做的事情:我们使视图Thumbnail_List独立于具体的类,而我们仍然可以依赖作为的类的方法$source。如果以后改变主意,则可以编写一个新类来获取帖子ID或使用具有固定值的ID。只要实现该接口,该视图就会得到满足。您甚至可以立即使用模拟对象测试视图:

class Mock_Post_Collector implements Post_Collector_Interface
{
    public function set_groups( Array $groups ) {}

    public function get_post_ids()
    {
        return array ( 1 );
    }
}

当您要测试视图时,这非常有用。您不想一起测试两个具体的类,因为您不会看到错误的来源。模拟对象对于错误来说太简单了,非常适合单元测试。

现在我们必须以某种方式组合我们的课程。这是控制器进入阶段的地方。

class Thumbnail_Controller
{
    protected $groups = array(
        'fashion-follower' => array(
            'q1' => 'party',
            'q2' => 'clothes',
            'q3' => 'shopping',
            'q4' => FALSE,
            'q5' => 'sunbathing',
            'q6' => 'mini',
        ),
        'the-homemaker' => array(
            'q1' => 'drink',
            'q2' => 'candles',
            'q3' => 'house',
            'q4' => 'diy',
            'q5' => FALSE,
            'q6' => FALSE,
        )
    );
    public function __construct()
    {
        // not a post request
        if ( 'POST' !== $_SERVER[ 'REQUEST_METHOD' ] )
            return;

        // set up the model
        $model = new Post_Collector;
        $model->set_groups( $this->groups );

        // prepare the view
        $view = new Thumbnail_List;
        $view->set_source( $model );

        // finally render the tumbnails
        $view->render();
    }
}

控制器是应用程序中真正独特的一部分。即使在完全不同的部分,模型和视图也可能在这里和那里重复使用。但是控制器的存在只是为了这个目的,这就是为什么我们将其放在$group这里。

现在您只需要做一件事:

// Let the dogs out!
new Thumbnail_Controller;

在需要输出的任何地方调用此行。

您可以在GitHub的这个要点中找到此答案的所有代码。


6
该答案的ISBN号是多少?
kaiser

教科书的答案确实是:p
Manny Fleurmond

1
“不要要求-1。” 我会说:设置一个筛选器,-1以便拥有大量站点的用户可以根据需要进行更改。
chrisguitarguy

@chrisguitarguy我宁愿设置安全的默认值,并让需要-1过滤的用户添加该默认值。使用查询过滤器已经可以做到这一点。
fuxia
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.