Afișarea articolelor după lună

27 ian. 2015, 11:52:21
Vizualizări: 27K
Voturi: 3

Vreau să obțin ceva de genul acesta, nu știu dacă este posibil și care ar fi cea mai bună modalitate de a o face:

exemplu de afișare articole grupate după lună

Modul în care interoghez articolele este următorul:

<div class="post">
    <?php global $wp_query;
    query_posts( array('post_type' => array( 'lecturas-post' ),'showposts' => 15, 'paged'=>$paged, 'order' => 'DESC' ));?>
    <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
        <div><?php the_title() ?></a>
    <?php endwhile; // sfârșitul buclei. ?>
</div>

Poate cineva să-mi dea un sfat despre cum sau care ar fi cea mai bună modalitate de a face acest lucru?

2
Comentarii

Pentru a obține această structură, ai nevoie de mai multe interogări. Mai întâi trebuie să identifici lunile de afișat, apoi să parcurgi rezultatele și să extragi articolele relevante. Voi încerca să ofer un răspuns în curând...

David Gard David Gard
27 ian. 2015 13:47:13

Poți realiza acest lucru într-o singură interogare fără a folosi query_posts

Pieter Goosen Pieter Goosen
27 ian. 2015 15:18:55
Toate răspunsurile la întrebare 3
5
11

După cum s-a menționat într-un comentariu, puteți face acest lucru într-o singură interogare. Principiul aici este de a afișa antetul cu data doar dacă luna postării curente nu se potrivește cu cea a postării anterioare.

CÂTEVA OBSERVAȚII

Înainte de a începe, câteva observații:

  • Niciodată nu folosiți query_posts, decât dacă chiar trebuie să distrugeți totul pe o pagină. Această funcție nu doar rerulează interogarea principală și o strică, dar afectează paginarea și variabilele globale, și interferează cu funcțiile obiectului interogat. Dacă chiar trebuie să rulați o interogare personalizată, folosiți WP_Query sau get_posts.

  • showposts a fost înlocuit de ani de zile cu posts_per_page.

  • Nu este necesar să utilizați variabila globală $wp_query. query_posts o strică oricum.

PLANUL

Postările sunt afișate în ordine cronologică, cu cele mai noi primele și cele mai vechi ultimele, deci sunt deja în ordinea corectă. Tot ce trebuie făcut este să afișați data în locul potrivit.

Pentru a face acest lucru, trebuie doar să obțineți luna și anul curente din data postării curente și să le comparați cu luna postării anterioare, afișând data dacă lunile nu se potrivesc sau să o omiteți dacă se potrivesc.

Pentru explicație, voi folosi bucla principală cu interogarea principală.

Pentru a realiza acest lucru, trebuie să:

  • Obțineți luna din data postării curente. Pentru aceasta, folosiți get_the_date( 'F' ).

  • Obțineți postarea anterioară din buclă cu $wp_query->posts['acesta va fi postarea curentă -1 ']->post.

  • Obțineți și comparați lunile dintre cele două postări.

  • Afișați sau nu data în funcție de comparație.

CODUL

Acest cod se plasează în interiorul buclei dumneavoastră, imediat după instrucțiunea while().

$current_month = get_the_date('F');

if( $wp_query->current_post === 0 ) { 

   the_date( 'F Y' );

}else{ 

    $f = $wp_query->current_post - 1;       
    $old_date =   mysql2date( 'F', $wp_query->posts[$f]->post_date ); 

    if($current_month != $old_date) {

        the_date( 'F Y' );;

    }

}

INTEROGARE PERSONALIZATĂ

Dacă aveți nevoie să rulați o interogare personalizată, încercați acest cod:

$q = new WP_Query( array('post_type' => array( 'lecturas-post' ),'posts_per_page' => 15, 'paged'=>$paged, 'order' => 'DESC' ));

if( $q->have_posts() ) {
    while( $q->have_posts() ) {

        $q->the_post();

        $current_month = get_the_date('F');

        if( $q->current_post === 0 ) { 

           the_date( 'F Y' );

        }else{ 

            $f = $q->current_post - 1;       
            $old_date =   mysql2date( 'F', $q->posts[$f]->post_date ); 

            if($current_month != $old_date) {

                the_date( 'F Y' );;

            }

        }

        the_title();

    }

}
27 ian. 2015 16:44:06
Comentarii

Răspuns bun, și un concept similar pentru secțiunea ta de interogare personalizată ca în răspunsul meu actualizat, doar un mod diferit de a verifica dacă titlul a fost afișat. Presupun că depinde de OP dacă doresc să includă date_query sau nu :)

David Gard David Gard
27 ian. 2015 17:37:37

Un lucru pe care îl voi menționa totuși este că o lună poate fi împărțită pe mai multe pagini. Dacă OP nu este deranjat de asta, atunci perfect, am considerat că merită menționat.

David Gard David Gard
27 ian. 2015 17:39:25

@DavidGard mulțumesc. Data va fi afișată pe fiecare pagină la primul post, indiferent. Dacă nu ai nevoie de asta, adaugă condiția is_paged().

Pieter Goosen Pieter Goosen
27 ian. 2015 17:50:13

@wpuser Cu plăcere. Bucură-te :-)

Pieter Goosen Pieter Goosen
27 ian. 2015 17:50:51

@PieterGoosen - Îmi dau seama, am considerat că merită menționat pentru oricine altcineva care ar putea da peste acest răspuns în viitor. Știu că mă confund ușor, așa că presupun că la fel sunt și ceilalți!

David Gard David Gard
27 ian. 2015 17:56:38
7

Răspuns Actualizat

După ce am reflectat asupra comentariului lui @PieterGoosen de mai jos, am adăugat o metodă de a atinge obiectivul folosind o singură interogare.

Am comparat metodele și interogarea unică este mai rapidă, cu metoda cu interogări multiple fiind cu aproximativ 15% mai lentă. Nu o diferență enormă, dar fiecare detaliu contează, iar sincer, metoda poate fi probabil rafinată și mai mult.

Am lăsat metoda cu interogări multiple în răspuns pentru posteritate, dar recomand să folosiți metoda cu interogare unică.

Metoda cu Interogare Unică

$time_start = microtime(true);

/** Configurăm un obiect DateInterval pentru acum 6 luni (puteți modifica după necesități) */
$interval = new DateInterval('P6M');
$interval->invert = 1;

/** Obținem data așa cum era acum 6 luni */
$date = new DateTime(date('Y-m-d'));
$date->add($interval);

/** Interogăm baza de date pentru toate articolele mai noi decât intervalul de dată specificat */
$args = array(
    'nopaging'          => true,
    'posts_per_page'    => -1,
    'post_type'         => 'post',
    'post_status'       => 'publish',
    'order_by'          => 'date',
    'date_query'        => array(
        'after' => $date->format('Y-m-d')
    )
);
$month_query = new WP_Query($args);

/** Verificăm să existe articole pentru această lună... */
if($month_query->have_posts()) :

    $month_titles = array();
    $close_ul = false;
    
    
    //echo '<ul style="padding-left: 250px;" id="monthly-posts">';
    
    /** Setăm atributele pentru afișarea titlului ca atribut */
    $title_attribute_args = array(
        'before'    => 'Vizitați articolul \'',
        'after'     => '\' ',
        'echo'      => false
    );      
    
    /** Parcurgem fiecare articol pentru această lună... */
    while($month_query->have_posts()) : $month_query->the_post();
    
        /** Verificăm luna/anul articolului curent */
        $month_title = date('F Y', strtotime(get_the_date('Y-m-d H:i:s')));
        
        /** Afișăm o dată ușor de înțeles, dacă nu a fost deja afișată */
        if(!in_array($month_title, $month_titles)) :
        
            if($close_ul) echo '</ul>';                                                             // Verificăm dacă lista neordonată de articole trebuie închisă (nu pentru prima '$month_title')
            echo '<h1 style="padding-left: 250px;" id="monthly-title">' . $month_title . '</h1>';   // Afișăm '$month_title'
            echo '<ul style="padding-left: 250px;" id="monthly-posts">';                            // Deschidem o listă neordonată pentru articolele care urmează
            $month_titles[] = $month_title;                                                         // Adăugăm acest `$month_title' în array-ul de `$month_titles` ca să nu se repete
            $close_ul = true;                                                                       // Indicăm că lista neordonată trebuie închisă la următoarea oportunitate
            
        endif;
        
        /** Afișăm fiecare articol pentru această lună */
        printf(
            '<li id="monthly-post-%1$s">%2$s <a href="%3$s" title="%4$s">%3$s</a></li>',
            get_the_ID(),                               /** %1$s - ID-ul articolului */
            get_the_title(),                            /** %2$s - Titlul articolului */
            get_permalink(get_the_ID()),                /** %3$s - Link-ul articolului */
            the_title_attribute($title_attribute_args)  /** %4$s - Titlul pentru utilizare ca atribut */
        );
        
    endwhile;
    
    if($close_ul) echo '</ul>'; // Închidem ultima listă neordonată de articole (dacă au fost afișate)
    
endif;

/** Resetăm interogarea ca WordPress să nu facă lucruri ciudate */
wp_reset_query();

Răspuns Original

Încercați această soluție. Am configurat-o astfel încât să afișeze doar ultimele 6 luni și doar ultimele 5 articole din fiecare lună, dar puteți modifica după necesități.

În esență, codul va verifica mai întâi care luni au articole și apoi va afișa ultimele cinci articole din acea lună, împreună cu un link.

Metoda cu Interogări Multiple

global $wpdb, $wp_locale;
    
/** Interogăm lunile individuale de afișat (am ales ultimele 6 luni) */
$query = $wpdb->prepare('
    SELECT DISTINCT YEAR(`%1$s`.`post_date`) AS year, MONTH(`%1$s`.`post_date`) AS month
    FROM `%1$s`
    WHERE `%1$s`.`post_type` = "post"
    ORDER BY `%1$s`.`post_date` DESC
    LIMIT 6',
    $wpdb->posts
);
$months = $wpdb->get_results($query);

/** Numărăm lunile */
$month_count = count($months);

/** Ne asigurăm că există luni de afișat... */
if($month_count || ($month_count === 1 && $months[0]->month > 0)) :

    /** Parcurgem fiecare lună... */
    foreach($months as $month) :

        if($month->year === 0) :
            continue;
        endif;
        
        /** Obținem luna și anul individual și construim o dată ușor de înțeles (pentru titlu) */
        $m = zeroise($month->month, 2);
        $y = $month->year;
        $human_date = sprintf(__('%1$s %2$d'), $wp_locale->get_month($m), $y);
        
        /** Obținem articolele pentru această lună (am ales doar ultimele 5 articole) */
        $args = array(
            'nopaging'          => true,
            'posts_per_page'    => 5,
            'post_type'         => 'post',
            'post_status'       => 'publish',
            'order_by'          => 'date',
            'year'              => $y,
            'monthnum'          => $m
        );
        $month_query = new WP_Query($args);
        
        /** Verificăm să existe articole pentru această lună... */
        if($month_query->have_posts()) :

            /** Afișăm o dată ușor de înțeles */
            echo '<h1 id="monthly-title">' . $human_date . '</h1>';
            echo '<ul id="monthly-posts">';
            
            /** Setăm atributele pentru afișarea titlului ca atribut */
            $title_attribute_args = array(
                'before'    => 'Vizitați articolul \'',
                'after'     => '\' ',
                'echo'      => false
            );      
            
            /** Parcurgem fiecare articol pentru această lună... */
            while($month_query->have_posts()) : $month_query->the_post();
            
                /** Afișăm fiecare articol pentru această lună */
                printf(
                    '<li id="monthly-post-%1$s">%2$s <a href="%3$s" title="%4$s">%3$s</a></li>',
                    get_the_ID(),                               /** %1$s - ID-ul articolului */
                    get_the_title(),                            /** %2$s - Titlul articolului */
                    get_permalink(get_the_ID()),                /** %3$s - Link-ul articolului */
                    the_title_attribute($title_attribute_args)  /** %4$s - Titlul pentru utilizare ca atribut */
                );
                
            endwhile;
            
            echo '</ul>';
            
        endif;
        
        /** Resetăm interogarea ca WordPress să nu facă lucruri ciudate */
        wp_reset_query();
        
    endforeach;

endif;
27 ian. 2015 14:29:12
Comentarii

Poți face asta într-o singură interogare :-)

Pieter Goosen Pieter Goosen
27 ian. 2015 14:33:14

Serios? La ce te gândești? M-am gândit și la GROUP BY, dar OP vrea titluri pentru lună/an, așa că micuțul meu creier nu vede dincolo de interogări multiple :-/

David Gard David Gard
27 ian. 2015 14:36:49

Voi încerca să postez o soluție mai târziu. Sunt puțin ocupat :-)

Pieter Goosen Pieter Goosen
27 ian. 2015 15:18:14

Hmm, sunt intrigat... Presupun că ai putea să obții toate articolele mai noi decât X folosind date_query, și apoi să le separi într-un array multidimensional. S-ar putea să încerc asta, dar aștept cu nerăbdare un răspuns super-simplu de la tine mai târziu ;-)

David Gard David Gard
27 ian. 2015 15:29:51

@PieterGoosen Am încercat o metodă cu o singură interogare, dar aș fi recunoscător pentru orice critică (constructivă) pe care ai putea să o ai!

David Gard David Gard
27 ian. 2015 16:39:16

Versiunea ta actualizată arată bine. Cu siguranță o altă metodă validă, deși poate puțin prea mult. Vei primi votul meu pentru versiunea actualizată :-)

Pieter Goosen Pieter Goosen
27 ian. 2015 18:15:08

Mulțumesc :) Am tendința să fiu foarte detaliat în răspunsurile mele, întotdeauna presupun că utilizatorul începe de la zero (decât dacă este furnizat un cod).

David Gard David Gard
27 ian. 2015 18:36:53
Arată celelalte 2 comentarii
4

Aceasta este o funcție pe care am creat-o pentru a fi utilizată în diverse scopuri, pentru a prelua date despre postări sau tipuri personalizate de postări înainte sau după un anumit an/lună, sau anul curent, în orice ordine ai nevoie:

// poți schimba numele în cazul în care intră în conflict cu alt plugin
function get_posts_by_date($user_options = array()){

  $options = array(
    'year_limit' => '1980'
    ,'month_limit' => '01'
    ,'operator' => '>=' // operator de comparare a datei
    ,'current_year' => true // limitează datele la anul curent
    ,'post_type' => 'post'
    ,'year_order' => 'DESC'
    ,'month_order' => 'DESC'
    ,'post_ids_order' => 'DESC'
    ,'raw_output' => false
  );

  extract(array_merge($options, $user_options));

  global $wpdb;

  if($operator == '>=' || $operator == '=='){
    $day = "01";
  } elseif($mode == '<='){
    $day = "31";
  }

  if($current_year){ // va fi după [anul anterior]/12/31
    $year_limit = date('Y', strtotime('-1 year'));
    $month_limit = '12';
    $day = "31";
    $operator == '>=';
  }

  // atenție: dacă parametrii tăi provin din input/utilizator/formulare, 
  // folosește $wpdb::prepare()
  // https://developer.wordpress.org/reference/classes/wpdb/prepare/
  $results = $wpdb->get_results("
    SELECT tbl.y year, group_concat(month_posts ORDER BY tbl.m " . $month_order . " SEPARATOR '-') months
      FROM (
        SELECT YEAR(p.post_date) y, MONTH(p.post_date) m, concat(MONTH(p.post_date), ':', group_concat(p.id ORDER BY p.post_date " . $post_ids_order . " )) month_posts
        FROM $wpdb->posts p
        WHERE (p.post_status = 'publish' OR p.post_status = 'future')
          AND p.post_type = '" . $post_type . "'
          AND p.post_date " . $operator . " DATE('" . $year_limit . "-" . $month_limit . "-" . $day . " 00:00:00')
        GROUP BY y, m
      ) tbl
    GROUP BY tbl.y
    ORDER BY tbl.y " . $year_order
  );

  if($raw_output) return $results;

  global $wp_locale;

  foreach ($results as $data){
    $months_data = explode('-',$data->months);
    $months = array();
    $data->count = 0; // numărătoare pe an

    foreach ($months_data as $month_data){
      $month_obj = new stdClass;

      $splitted = explode(':',$month_data);
      $raw_month = $splitted[0];
      $month_obj->number = $raw_month;
      $month_obj->name = $wp_locale->get_month($raw_month);
      $month_obj->posts = array();
      $post_ids = explode(',',$splitted[1]);
      $data->count += count($post_ids);

      foreach($post_ids as $post_id){
        $month_obj->posts[] = get_post($post_id);
        $months[$raw_month] = $month_obj;
      }// foreach
    }// foreach

    $data->months = $months;
  }// foreach

  return $results;
}// get_posts_by_date

Exemplu de utilizare:

$posts_by_date = get_posts_by_date(array(
  'year_limit' => '2016'
  ,'operator' => '<='
  ,'current_year' => false
  ,'post_type' => 'product'
  ,'month_order' => 'ASC'
  ,'raw_output' => true
));

Dacă opțiunea raw_output este adevărată, rezultatul implicit va arăta cam așa:

array(2) {
  [0]=>
  object(stdClass)#6645 (2) {
    ["year"]=>
    string(4) "2017"
    ["months"]=>
    string(65) "8:386,401-7:406,373,380,377,408,399,362-6:1,391,404-5:367,397,394"
  }
  [1]=>
  object(stdClass)#6644 (2) {
    ["year"]=>
    string(4) "2016"
    ["months"]=>
    string(5) "6:429"
  }
}

Șirul "months" conține valori formatate astfel:

lună:[id-uri postări]-lună:[id-uri postări]-etc

Dacă opțiunea raw_output este falsă, vei obține o listă de postări în formatul:

array (array de obiecte)
  obiect
    -> year (ex. '2017')
    -> count (total postări pe an)
    -> months (array de obiecte)
        lună
          -> number (al lunii)
          -> name (localizat)
          -> posts (array de obiecte postare)

Cod fericit... :)

15 aug. 2017 11:59:30
Comentarii

Atenție la posibilele injecții SQL și evitați folosirea funcției extract (este mai greu de depanat) și nu folosiți nume generice de funcții pentru a evita posibilele conflicte de nume (sau folosiți namespace-uri).

birgire birgire
15 aug. 2017 16:45:52

@birgire: bah... știu toate aceste lucruri, dar este responsabilitatea dezvoltatorului să evalueze numele funcției în raport cu mediul său și, eventual, să santineze datele introduse de utilizator/de la formular. Acesta este doar un cod util pe care îl împărtășesc, sincer cred că această funcție va ajuta pe mulți. Apoi, sper cu adevărat că orice dezvoltator -- (doar) dacă este necesar -- va fi perfect capabil să schimbe numele funcției și/sau să santineze datele introduse de utilizator sau să adauge o instrucțiune prepare în loc să scrie direct...

Luca Reghellin Luca Reghellin
16 aug. 2017 16:05:42

Sper că vor face asta, dar mi-e teamă că mulți doar copiază/lipească codul de pe acest site și îl uită, dacă a funcționat prima dată ;-)

birgire birgire
16 aug. 2017 17:52:27

Bine, mulțumesc! Am adăugat sugestii de securitate, cred că e suficient, întrebarea originală nu era despre probleme de securitate :)

Luca Reghellin Luca Reghellin
16 aug. 2017 19:09:10