Sag niemals nie: Widget für die X neuesten Beiträge eigener Post Types

Ich hab ja gesagt, mir ist das zu kompliziert, aber jetzt hab ich mir doch ein Widget geschrieben, das die X neuesten Beiträge eines wählbaren Post Types anzeigt. Man kann dem Widget einen Titel geben, man kann eingeben wieviele Beiträge angezeigt werden sollen, man kann auch noch anwählen ob das Datum mit angezeigt werden soll oder nicht. Aussehen tut das Ganze so:

post_type_widget

post_type_widget

Und die Ausgabe in der Sidebar sieht zum Beispiel so aus:

widget_posts

widget_posts

Hier hab ich als Post Type „post“ angegeben (das sind meine Rezepte), das Limit auf 5 gesetzt und Datum ausgeben angekreuzt.

Das Widget wird ganz normal im Plugins-Verzeichnis angelegt, der Header mit der Klassendeklaration sieht so aus:

/*
Plugin Name: Post Type Widget
Plugin URI: http://evileu.de/wordpress
Description: Zeigt die neuesten X Beiträge des gewählten Post Types an
Author: Evi Leu
Version: 1.0
Author URI: http://evileu.de
*/


class PostTypeWidget extends WP_Widget
{
  function PostTypeWidget()
  {
    $widget_ops = array('classname' => 'PostTypeWidget', 'description' => 'Zeigt die neuesten X Beiträge des gewählten Post Types an' );
    $this->WP_Widget('PostTypeWidget', 'Post Type', $widget_ops);
  }

Interessant wird es in der Formulardefinition, da habe ich mir ein Dropdownfeld mit meinen vorhandenen Post Types gebastelt, ich picke das mal heraus und markiere die anzupassenden Stellen rot:

<p>
    <label for="<?php echo $this->get_field_id( 'posttype' ); ?>"><?php _e( 'Select Post Type', 'textdomain' ); ?>:</label>
    <p>Post Type auswählen
   <select id="<?php echo $this->get_field_id('posttype'); ?>" name="<?php echo $this->get_field_name('posttype'); ?>" class="widefat" style="width:100%;">
    <option <?php selected( $instance['posttype'], 'post'); ?> value="post">Post</option>
    <option <?php selected( $instance['posttype'], 'kochbuch'); ?> value="kochbuch">Kochbuch</option>   
    <option <?php selected( $instance['posttype'], 'projects'); ?> value="projects">Projects</option> 
    </select>
   </p>

Man hätte auch die vorhandenen Post Types aus der Datenbank fischen können, aber das war mit zu viel Heckmeck, da müsste man ja noch die WordPress-eigenen Types und evtl. auch die von irgendwelchen Plugins angelegten herausfiltern, ich fand es so herum entschieden einfacher. Wer mehr Post Types hat, ergänzt einfach den Select entsprechend.

Nachtrag: alle Post Types aus der wp_posts anzeigen

Jetzt hab ichs doch noch ausprobiert, wer sich alle vorhandenen Post Types aus der wp_posts im Dropdownfeld anzeigen lassen will, kann für den Select folgende Konstruktion verwenden:

 <p>Post Type auswählen
   <select id="<?php echo $this->get_field_id('posttype'); ?>" name="<?php echo $this->get_field_name('posttype'); ?>" class="widefat" style="width:100%;">
    <?php
    global $wpdb;
    $alleposts = $wpdb->get_results( "SELECT DISTINCT post_type 
                                      from ".$wpdb->prefix."posts");
    
    foreach($alleposts as $einpost){      
      echo "<option ".selected( $instance['posttype'], $einpost->post_type)." value=".$einpost->post_type.">".$einpost->post_type."</option>";
    }
    ?>
    
    </select>
   </p>

Da kriegt man halt auch jeden Schrott angezeigt, aber es funktioniert:

alle_post_types

alle_post_types

Bleibt jedem selber überlassen, ob er diese Option verwenden will oder den statischen Select von oben. Mir ist die statische Dropdownliste lieber, weil sie den Benutzer nicht in Versuchung bringt hier eine sinnfreie Option wie z.B revisions anzuwählen. Natürlich könnte man den SQL entsprechend aufblasen und noch einige „WHERE post_type NOT LIKE ‚xyz'“ dranflicken, aber das ist mir entschieden zu umständlich.

Die Checkbox für das Datum

Für die Checkbox zum Datum anzeigen habe ich folgende Konstruktion verwendet:

<p>
    <input class="checkbox" type="checkbox" <?php checked( $instance[ 'your_checkbox_var' ], 'on' ); ?> id="<?php echo $this->get_field_id( 'your_checkbox_var' ); ?>" name="<?php echo $this->get_field_name( 'your_checkbox_var' ); ?>" /> 
    <label for="<?php echo $this->get_field_id( 'your_checkbox_var' ); ?>">Datum anzeigen</label>
</p>

Die ganze Funktion form($instance) sieht so aus:

function form($instance)
  {
    $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
    $title = $instance['title'];
    
    $instance = wp_parse_args( (array) $instance, array( 'posttype' => '' ) );
    $posttype = $instance['posttype'];
    
    $instance = wp_parse_args( (array) $instance, array( 'anzahl' => '' ) );
    $anzahl = $instance['anzahl'];
    
    $instance = wp_parse_args( (array) $instance, array( 'your_checkbox_var' => '' ) );
    $your_checkbox_var = $instance['your_checkbox_var'];
    
    
    
?>
  <p><label for="<?php echo $this->get_field_id('title'); ?>">Titel: <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /></label></p>
  
   <p>
    <label for="<?php echo $this->get_field_id( 'posttype' ); ?>"><?php _e( 'Select Post Type', 'textdomain' ); ?>:</label>
    <p>Post Type auswählen
   <select id="<?php echo $this->get_field_id('posttype'); ?>" name="<?php echo $this->get_field_name('posttype'); ?>" class="widefat" style="width:100%;">
    <option <?php selected( $instance['posttype'], 'post'); ?> value="post">Post</option>
    <option <?php selected( $instance['posttype'], 'kochbuch'); ?> value="kochbuch">Kochbuch</option>   
    <option <?php selected( $instance['posttype'], 'projects'); ?> value="projects">Projects</option> 
    </select>
   </p>
  <p><label for="<?php echo $this->get_field_id('anzahl'); ?>">Anzahl: <input id="<?php echo $this->get_field_id('anzahl'); ?>" 
name="<?php echo $this->get_field_name('anzahl'); ?>" type="number" value="<?php echo attribute_escape($anzahl); ?>" /></label></p>
<p>
    <input class="checkbox" type="checkbox" <?php checked( $instance[ 'your_checkbox_var' ], 'on' ); ?> id="<?php echo $this->get_field_id( 'your_checkbox_var' ); ?>" name="<?php echo $this->get_field_name( 'your_checkbox_var' ); ?>" /> 
    <label for="<?php echo $this->get_field_id( 'your_checkbox_var' ); ?>">Datum anzeigen</label>
</p>
  
  
  
<?php
  }

Dann noch die Funktion update() anpassen:

function update($new_instance, $old_instance)
  {
    $instance = $old_instance;
    $instance['title'] = $new_instance['title'];
    $instance['posttype'] = $new_instance['posttype'];
    $instance['anzahl'] = $new_instance['anzahl'];
    $instance[ 'your_checkbox_var' ] = $new_instance[ 'your_checkbox_var' ];
    return $instance;
  }

Und schliesslich in der Funktion widget() die Variablen abholen:

function widget($args, $instance)
  {
    extract($args, EXTR_SKIP);
 
    echo $before_widget;
    $your_checkbox_var = $instance[ 'your_checkbox_var' ] ? 'true' : 'false';
    $title = empty($instance['title']) ? ' ' : apply_filters('widget_title', $instance['title']);
    $posttype    = empty( $instance['posttype'] ) ? '' : esc_attr( $instance['posttype'] );
    $anzahl    = empty( $instance['anzahl'] ) ? '' : esc_attr( $instance['anzahl'] );

Der eigentliche OpCode des Widgets ist nicht weiter kompliziert, die Hauptsache ist die SQL-Query, in die ich die Variablen für den Post Type und für die Anzahl einsetze:

global $wpdb;
    $alleposts = $wpdb->get_results( "SELECT * from ".$wpdb->prefix."posts 
where post_type like '".$posttype."' 
and post_status like 'publish' 
ORDER BY post_date DESC
 LIMIT ".$anzahl."");
    

Das ganze wird noch nach dem post_status=publish gefiltert und absteigend nach Datum sortiert und kann jetzt in einem foreach ausgegeben werden. Dabei baue ich noch die Abfrage ein, ob das Datum mit ausgegeben werden soll:

foreach($alleposts as $einpost){
        
        $dt = new DateTime($einpost->post_date);
        echo $einpost->post_title." ";
        if ($your_checkbox_var == 'true'){ echo $dt->format('d.m.Y');}
        echo "<br>";
    }

Hier könnte man wie schon öfter gehabt mit dem get_permalink() über die ID gleich noch den Link zum entsprechenden Beitrag mit einbauen, das spare ich mir jetzt. Wem das jetzt zu schnell ging, den ganzen Code des Widgets gibt es hier gezippt: post-type-widget

Viel Spaß beim Nachbauen!