Wordpress:在widget api中为已定义的帖子ID创建循环

Using WP_Widget class, I coded html layout to output single post meta(title, thumb, url, author avatar and name.

Now I need to output meta strings in PHP defined by post ID:

public function widget( $args, $instance ) {
  // outputs the content of the widget
  echo __( '
      <h4><a href="the_permalink">the_title</a></h4>
      <img src="the_thumbnail">
      <div>the_category</div>
      .....
      ', 'text_domain' );
}

and if possible to define the post id as outputs the options form on admin:

public function form( $instance ) {
    // outputs the options form on admin
}

Here're what I tried on my local site:

1. Create the widget class.

Save this widget somewhere and include it in your functions.php:

class PostInfoWidget extends WP_Widget
{
    /**
     * Constructor
     */
    function __construct() {
        parent::__construct('post-info-widget',
            __('Display Post Information', 'text-domain'), [
            'classname'   => 'post-info-widget',
            'description' => __('Use this widget to display a specific post information.')
        ]);
    }

    /**
     * Display front-end contents.
     */
    function widget($args, $instance)
    {
        $post = get_post($instance['post_id']);
        echo $args['before_widget'];
        if ( !empty($instance['widget_title']) ) {
            echo $args['before_title'] . $instance['widget_title'] . $args['after_title'];
        }
        ?>
        <article class="post post-sidebar" itemscope itemtype="https://schema.org/Article">
            <?= get_the_post_thumbnail($post, 'thumbnail', ['itemprop' => 'thumbnail']) ?>
            <h4 itemprop="name">
                <a itemprop="url" href="<?= esc_url( get_permalink($post) ) ?>">
                    <?= get_the_title($post) ?>
                </a>
            </h4>
            <div class="author-info">
                <span class="author-name">
                    <?php the_author_meta('display_name', $post->post_author) ?>
                </span>
                <span class="author-avatar">
                    <?= get_avatar($post->post_author) ?>
                </span>
            </div>
            <div class="category-info">
                <?php the_category(', ', '', $instance['post_id']) ?>
            </div>
        </article>
        <?php
        echo $args['after_widget'];
    }

    /**
     * Display back-end form.
     */
    function form($instance)
    {
        $widget_title = !empty($instance['widget_title']) ? $instance['widget_title'] : '';
        $post_id      = !empty($instance['post_id']) ? $instance['post_id'] : 1;
        ?>
        <p>
            <label for="<?= $this->get_field_id('widget_title') ?>">
                <?= __('Title of the widget:', 'text-domain') ?>
            </label>
            <input class="widefat" type="text" name="<?= $this->get_field_name('widget_title') ?>" value="<?= $widget_title ?>">
        </p>
        <p>
            <label for="<?= $this->get_field_id('post_id') ?>">
                <?= __('Displaying infomation of post ID:', 'text-domain') ?>
            </label>
            <input type="number" name="<?= $this->get_field_name('post_id') ?>" value="<?= $post_id ?>">
        </p>
        <?php
    }

    /**
     * Save back-end form.
     */
    function update($new_instance, $old_instance)
    {
        $instance = [];
        $instance['widget_title'] = sanitize_text_field($new_instance['widget_title']);
        $instance['post_id'] = absint($new_instance['post_id']);
        return $instance;
    }

}

2. Register the widget

Add this to your functions.php after you included the above code.

add_action('widgets_init', function() {
    register_widget('PostInfoWidget');
});

3. Register a sidebar to display the widget.

Add this code to your functions.php too:

register_sidebar([
    'name' => __('Post infomation sidebar', 'text-domain'),
    'id'   => 'post-info-sidebar',
    'description'   => __('Use this sidebar to display a specific post information.', 'text-domain'),
    'before_widget' => '<aside id="%1$s" class="widget %2$s" itemscope itemtype="https://schema.org/WPSideBar">',
    'after_widget'  => '</aside>',
    'before_title'  => '<h2 class="widget-title">',
    'after_title'   => '</h2>'
]);

4. Display the widget.

Add this code to your sidebar.php or any templates you want:

<?php if ( is_active_sidebar('post-info-sidebar') ) {
    dynamic_sidebar('post-info-sidebar');
} else {
    // Do something else.
} ?>

Now, try it out and customize it to your preference.

If I'm understanding correctly, you want to use the loop?

<?php
public function widget( $args, $instance ) {
    $r = new WP_Query([
        'posts_per_page'      => 10,
        'no_found_rows'       => true,
        'post_status'         => 'publish',
        'ignore_sticky_posts' => true
    ]);
    if ($r->have_posts()) {
        echo "<ul>";
        while ($r->have_posts()) {
            $r->the_post();
            $permalink = get_the_permalink();
            $title = get_the_title();
            $id = get_the_ID();
            $thumbnail = has_post_thumbnail() ? get_the_post_thumbnail() : "";
            $category = has_category() ? implode(",", get_the_category()) : "";
            echo "<h4><a href='$permalink'>$title</a></h4>";
            echo $thumbnail;
            echo "<div>$category</div>";
        }
    }
}