Bagaimana cara membuat abstraksi yang fleksibel untuk WP_Query?

8

Pertanyaan saya adalah tentang php tetapi ini melibatkan wordpress karena saya membuat plugin. Kasusnya adalah saya memiliki 5 pertanyaan, setiap pertanyaan memiliki 6 pilihan dan satu pilihan untuk dipilih. Sekarang orang tersebut akan memilih pilihan dari masing-masing atau hanya beberapa. Saya telah menciptakan kondisi if yang sekarang membuat saya marah, karena sudah terlalu lama dan akan melakukan lebih jauh, seperti hampir 100 kombinasi akan dibuat. Saya tidak ingin itu, saya tahu ada cara array multidimensi tetapi dalam bukan plugin atau ahli php untuk wordpress. jadi kalau ada yang bisa mengurutkannya untuk saya.

$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;      
}
Nofel
sumber
Apa perbedaan dengan pertanyaan Anda sebelumnya ?
fuxia
@ tooscho perbedaannya adalah bahwa di Q. ada pertanyaan tentang refactoring tapi sekarang saya bertanya tentang mengoptimalkan kode bersama dengan wp loop atau melakukannya dalam array.
Nofel

Jawaban:

18

Pertanyaan Anda sebenarnya bukan tentang WordPress, ini lebih tentang PHP dan refactoring. Tapi kami melihat begitu banyak kode buruk di sini, dan pola yang akan saya jelaskan di bawah (MVC) dapat membantu banyak pengembang lain, jadi saya memutuskan untuk menulis sedikit jawaban. Ingat, ada situs khusus untuk pertanyaan seperti itu di jaringan kami: Tinjauan Kode . Sayangnya, sangat sedikit pengembang WordPress yang aktif di sana.


Cara memperbaiki kode

  1. Hapus kode yang tidak berguna. Mempercantik sisanya.
  2. Temukan semua ekspresi berulang dan buat rutinitas (fungsi atau kelas) untuk abstrak dan merangkum mereka.
  3. Pisahkan penanganan data, model (simpan, ambil, konversi, interpretasi), dari output, tampilan (HTML, CSV, apa pun).

1. Hapus kode yang tidak berguna. Mempercantik sisanya.

Hasil

Anda memiliki cuplikan berulang ini:

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

the_post_thumbnail('thumbnail');

endwhile;
endif;

Anda menjalankan yang agak mahal the_post()setiap kali mendapatkan thumbnail posting. Tapi itu tidak diperlukan, Anda cukup menelepon:

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

Kueri

Jadi yang Anda butuhkan adalah ID pos, dan ini tersedia tanpa menelepon the_post(). Bahkan lebih baik: Anda dapat membatasi query untuk mengambil hanya ID.

Contoh sederhana:

$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

Sekarang Anda memiliki ID, dan Anda dapat menulis:

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

Tanpa overhead, kode Anda sudah lebih cepat dan lebih mudah dibaca.

Sintaksnya

Perhatikan bagaimana saya menyelaraskan =? Ini membantu memahami kode, karena pikiran manusia terspesialisasi dalam pengenalan pola. Mendukung itu dan kami dapat melakukan hal-hal yang luar biasa. Buat berantakan, dan kami terjebak sangat cepat.

Ini juga alasan mengapa saya dihapus endwhiledan endif. The sintaks alternatif berantakan dan sulit dibaca. Plus, itu membuat bekerja dalam IDE jauh lebih sulit: melipat dan melompat dari awal hingga akhir ekspresi lebih mudah dengan kawat gigi.

Nilai default

$argsArray Anda memiliki beberapa bidang yang Anda gunakan di mana-mana. Buat larik default, dan tulis bidang itu sekali saja :

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

Sekali lagi, perhatikan perataannya. Dan perhatikan juga bagaimana saya mengubah posts_per_pagenilainya. Jangan pernah meminta-1 . Apa yang terjadi ketika ada satu juta posting yang cocok? Anda tidak ingin membunuh koneksi database Anda setiap kali query ini berjalan, bukan? Dan siapa yang harus membaca semua posting ini? Selalu tetapkan batas yang masuk akal.

Sekarang yang harus Anda ubah adalah bidangnya $args[ 'tax_query' ][ 'terms' ]. Kami akan membahasnya sebentar lagi.

2. Temukan semua ekspresi berulang dan buat rutinitas

Kami sudah membersihkan beberapa kode berulang, sekarang bagian yang sulit: evaluasi parameter POST. Jelas, Anda telah membuat beberapa label sebagai hasil dari beberapa parameter. Saya sarankan untuk mengubah nama itu menjadi sesuatu yang lebih mudah dimengerti, tetapi untuk saat ini kami akan bekerja dengan skema penamaan Anda.

Pisahkan grup-grup ini dari yang lainnya, buat array yang dapat Anda kelola secara terpisah:

$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,
    )
);

Untuk mengisi termsbidang yang hilang dalam array default Anda, Anda menjalankan melalui $groupsarray sampai Anda menemukan kecocokan:

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;
}

Saya memisahkan run melalui daftar istilah dan perbandingan nilai-nilai, karena ini adalah operasi yang berbeda. Setiap bagian dari kode Anda harus melakukan hanya satu hal, dan Anda harus menjaga agar tingkat indentasi tetap datar agar mudah dibaca.

Sekarang kita memiliki semua bagian, mari kita rekatkan.

3. Organisasi: Pisahkan model dari tampilan

Ketika saya menulis model dan tampilan , saya memiliki sesuatu dalam pikiran: pendekatan MVC. Itu adalah singkatan dari Model View Controller , pola yang terkenal untuk mengatur komponen perangkat lunak. Bagian yang hilang sejauh ini adalah controller, kita akan lihat bagaimana kita menggunakannya nanti.

Anda berkata, Anda tidak tahu banyak tentang PHP, jadi saya harap Anda tahu lebih banyak tentang hasilnya. :) Mari kita mulai dengan itu:

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' );
    }
}

Bagus dan sederhana: kami memiliki dua metode: satu untuk mengatur sumber untuk ID posting kami, satu untuk membuat gambar mini.

Anda mungkin bertanya-tanya apa ini Post_Collector_Interface. Kita akan membahasnya sebentar lagi.

Sekarang sumber untuk pandangan kita, modelnya.

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;
    }
}

Ini tidak sepele lagi, tetapi kami sudah memiliki sebagian besar. The protected metode (fungsi) tidak dapat diakses dari luar, karena kita membutuhkan mereka untuk logika internal saja.

The publicmetode sederhana: pertama mendapat kami $grouparray yang dari atas, kembali kedua array ID pos. Dan lagi-lagi kita menemui keraguan ini Post_Collector_Interface.

Sebuah antarmuka adalah kontrak . Itu dapat ditandatangani (diimplementasikan) oleh kelas. Membutuhkan antarmuka, seperti kelas kami Thumbnail_List, berarti: kelas mengharapkan beberapa kelas lain dengan metode publik ini.

Mari kita bangun antarmuka itu. Ini sangat sederhana:

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

    public function get_post_ids();
}

Yup, itu saja. Kode mudah, bukan?

Apa yang kami lakukan di sini: kami membuat pandangan kami Thumbnail_Listindependen dari kelas konkret sementara kami masih bisa mengandalkan metode dari kelas yang kami dapatkan $source. Jika Anda berubah pikiran nanti, Anda bisa menulis kelas baru untuk mengambil ID posting atau menggunakannya dengan nilai-nilai tetap. Selama Anda mengimplementasikan antarmuka, tampilan akan puas. Anda bahkan dapat menguji tampilan sekarang dengan objek tiruan:

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

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

Ini sangat berguna ketika Anda ingin menguji tampilan. Anda tidak ingin menguji kedua kelas konkret bersama, karena Anda tidak akan melihat dari mana kesalahan berasal. Objek tiruan terlalu sederhana untuk kesalahan, ideal untuk pengujian unit.

Sekarang kita harus menggabungkan kelas kita entah bagaimana. Di sinilah controller memasuki panggung.

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();
    }
}

Pengontrol adalah satu bagian unik nyata dari suatu aplikasi; model dan tampilan dapat digunakan kembali di sana-sini, bahkan di bagian yang sama sekali berbeda. Tetapi controller ada hanya untuk satu tujuan ini, ini sebabnya kami taruh di $groupsini.

Dan sekarang Anda hanya perlu melakukan satu hal:

// Let the dogs out!
new Thumbnail_Controller;

Panggil baris ini di mana pun Anda membutuhkan output.

Anda dapat menemukan semua kode dari jawaban ini di intisari di GitHub .

fuxia
sumber
6
Berapa nomor ISBN jawaban itu?
kaiser
Jawaban buku teks memang: p
Manny Fleurmond
1
"Jangan pernah meminta -1." Saya akan mengatakan: pasang filter -1agar pengguna dengan situs besar dapat mengubahnya jika perlu.
chrisguitarguy
@ chrisguitarguy Saya lebih suka mengatur default yang aman dan membiarkan pengguna yang perlu -1menambahkan itu per filter. Yang sudah dimungkinkan dengan filter pada kueri.
fuxia