WordPress の標準「最近の投稿」は公開日の新しい順である。だが実運用では、過去記事をリライトして再公開せずに更新だけする場面がある。
そこで更新日時(最終更新日)で並べ直した「最近の更新」リストをサイドバーに出す小さなウィジェットを作った。
プラグインに頼らず、functions.php
に追加するスタイル。アイキャッチも表示し、狭いサイドバーでもタイトル直後に更新日を添えるレイアウトにしている。
このブログも「最近の投稿」から、このウィジェットに置き換えてみた。
目次
完成コード(functions.php)
- 更新日の新しい順に取得(
orderby => 'modified'
) - アイキャッチ(サムネイル)を表示
- タイトルのすぐ後ろに更新日を表示
- ウィジェットとショートコードの両対応
ショートコード例
[recently_updated_posts count="5" post_type="post" title="最近の更新"]
phpソースコード
/**
* 最近の「更新」投稿リスト(更新日時で並べ替え)
* - ウィジェット名: 「最近の更新投稿」
* - ショートコード: 最近の更新
選挙ボランティア体験記 (更新: )
知ったかぶり観測日記──太陽系外から見守る私 (更新: )
*/
if ( ! class_exists( 'WP_Widget_Recently_Updated_Posts' ) ) {
// テーマがアイキャッチに対応していない場合の保険
add_action( 'after_setup_theme', function () {
add_theme_support( 'post-thumbnails' );
} );
class WP_Widget_Recently_Updated_Posts extends WP_Widget {
public function __construct() {
parent::__construct(
'recently_updated_posts',
'最近の更新投稿',
array( 'description' => '更新日時(最終更新日)の新しい順に投稿を表示' )
);
}
public function widget( $args, $instance ) {
$widget_title = apply_filters( 'widget_title', $instance['title'] ?? '最近の更新' );
$count = ! empty( $instance['count'] ) ? (int) $instance['count'] : 5;
$post_type = ! empty( $instance['post_type'] ) ? sanitize_text_field( $instance['post_type'] ) : 'post';
echo $args['before_widget'];
if ( $widget_title ) {
echo $args['before_title'] . esc_html( $widget_title ) . $args['after_title'];
}
$q = new WP_Query( array(
'post_type' => $post_type,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'posts_per_page' => $count,
'orderby' => 'modified',
'order' => 'DESC',
'no_found_rows' => true,
) );
if ( $q->have_posts() ) {
echo '<ul class="recently-updated-posts">';
while ( $q->have_posts() ) {
$q->the_post();
$permalink = get_permalink();
$post_title = get_the_title();
$modified_at = get_the_modified_time( get_option( 'date_format' ) );
echo '<li class="recently-updated-item">';
// アイキャッチ(フィルタの影響を避け、素の <img> を出力)
$thumb_id = get_post_thumbnail_id();
if ( $thumb_id ) {
$img = wp_get_attachment_image_src( $thumb_id, 'thumbnail' );
if ( $img ) {
echo '<a href="' . esc_url( $permalink ) . '" class="rup-thumb">';
echo '<img class="rup-thumb-img" src="' . esc_url( $img[0] ) . '" width="' . (int) $img[1] . '" height="' . (int) $img[2] . '" alt="' . esc_attr( $post_title ) . '">';
echo '</a>';
}
}
// タイトル直後に更新日
echo '<div class="rup-text">';
echo '<a class="rup-title" href="' . esc_url( $permalink ) . '">' . esc_html( $post_title ) . '</a>';
echo ' <span class="updated-at">(更新: <time datetime="' . esc_attr( get_the_modified_time('c') ) . '">' . esc_html( $modified_at ) . '</time>)</span>';
echo '</div>';
echo '</li>';
}
echo '</ul>';
wp_reset_postdata();
} else {
echo '<p>更新された投稿はまだありません。</p>';
}
echo $args['after_widget'];
}
public function form( $instance ) {
$title = $instance['title'] ?? '最近の更新';
$count = isset( $instance['count'] ) ? (int) $instance['count'] : 5;
$post_type = $instance['post_type'] ?? 'post';
?>
<p>
<label>タイトル:
<input class="widefat" name="<?php echo esc_attr( $this->get_field_name('title') ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
</label>
</p>
<p>
<label>表示数:
<input name="<?php echo esc_attr( $this->get_field_name('count') ); ?>" type="number" min="1" step="1" value="<?php echo esc_attr( $count ); ?>">
</label>
</p>
<p>
<label>投稿タイプ(post / page / カスタム投稿など):
<input class="widefat" name="<?php echo esc_attr( $this->get_field_name('post_type') ); ?>" type="text" value="<?php echo esc_attr( $post_type ); ?>">
</label>
</p>
<?php
}
public function update( $new_instance, $old_instance ) {
$instance = array();
$instance['title'] = sanitize_text_field( $new_instance['title'] ?? '' );
$instance['count'] = max( 1, (int) ( $new_instance['count'] ?? 5 ) );
$instance['post_type'] = sanitize_text_field( $new_instance['post_type'] ?? 'post' );
return $instance;
}
}
// ウィジェット登録
add_action( 'widgets_init', function() {
register_widget( 'WP_Widget_Recently_Updated_Posts' );
} );
// 同等のショートコード
add_shortcode( 'recently_updated_posts', function( $atts ) {
$atts = shortcode_atts( array(
'count' => 5,
'post_type' => 'post',
'title' => '最近の更新',
), $atts, 'recently_updated_posts' );
ob_start();
the_widget( 'WP_Widget_Recently_Updated_Posts', array(
'title' => $atts['title'],
'count' => (int) $atts['count'],
'post_type' => $atts['post_type'],
), array( 'before_widget' => '', 'after_widget' => '', 'before_title' => '<h3>', 'after_title' => '</h3>' ) );
return ob_get_clean();
} );
}
スタイルシート(追加CSS)
サイドバー幅を想定したシンプルな見た目。サムネ左/テキスト右、タイトル直後に更新日。極端に幅が狭いときは更新日だけ次行に落とせるようにしてある。
/* 最近の更新ウィジェット */
.recently-updated-posts { list-style: none; margin: 0; padding: 0; }
.recently-updated-posts .recently-updated-item {
display: flex;
gap: .6rem;
align-items: flex-start;
margin: .4rem 0;
}
.recently-updated-posts .rup-thumb { flex: 0 0 auto; }
.recently-updated-posts .rup-thumb-img {
display: block;
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 6px;
}
.recently-updated-posts .rup-text { flex: 1 1 auto; min-width: 0; }
.recently-updated-posts .rup-title { font-weight: 600; text-decoration: none; }
.recently-updated-posts .rup-title:hover { text-decoration: underline; }
.recently-updated-posts .updated-at {
margin-left: .4em;
color: #666;
font-size: .9em;
}
/* 幅がかなり狭い場合は更新日を次行へ */
@media (max-width: 360px) {
.recently-updated-posts .updated-at { display: block; margin-left: 0; }
}
設置
- 子テーマの
functions.php
に上の PHP を追記(推奨は子テーマ)。 - 外観 → ウィジェット(ブロックテーマならサイトエディターのサイドバー)で「最近の更新投稿」を追加。
- 表示数や投稿タイプを設定。
- 外観 → カスタマイズ → 追加CSS(またはテーマのCSS)に上の CSS を貼る。
うまく表示されないときのメモ
アイキャッチが出ない テーマが
add_theme_support('post-thumbnails')
を持っているか確認。CPT ならadd_post_type_support( 'news', 'thumbnail' );
のようにサムネ対応を付ける。画像が「読み込めません」になる 画像直リンクでは見えるのにページ内でだけ失敗するなら、ホットリンク防止(Refererチェック)が原因のことが多い。
wp-content/uploads/
の.htaccess
の許可ドメインに自サイトのドメインや開発用の IP を追加する(例:RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
)。ローカルや UserDir(~user
)環境だと引っかかりやすい。右端が詰まって改行が変 本CSSではタイトルと更新日を同じ行に並べつつ自然に折り返す。常に別行にしたければ
.updated-at { display:block; margin-left:0; }
にする。