画像登録時にスラッグもファイル名(タイムスタンプ)に自動変更する方法

Cocoonカスタマイズ集
この記事は約8分で読めます。
記事内に広告が含まれています。

はじめに

以前の記事では、画像アップロード時にファイル名をタイムスタンプに変更して重複や上書きを防ぐ方法を紹介しました。

しかし、WordPressの標準仕様では元のファイル名がそのまま「スラッグ」として残ってしまいます。

そこで、ファイル名だけでなくスラッグも自動でタイムスタンプに揃えて変更するカスタマイズを行います。

この記事では、この方法について説明します。

目的

メディアを編集

普段は意識しにくい「スラッグ」ですが、今回変更を行う理由は主に2つあります。

  1. WordPress 7.0の仕様変更
    「画像」ブロックのメディアパネルにスラッグが表示されるようになり、エンコードされた長い文字列などが目につくようになったため(図2参照)。
Gutenbergエディター
  1. 管理上の不一致を解消するため
    サーバー上のファイル名(タイムスタンプ)とデータベース上のスラッグ(元ファイル名)が異なっている不揃いを無くすため。

このように、見た目の違和感をなくしメディアライブラリの整合性を保つために、スラッグの自動変換を行います。

実装手順

以下のコードをfunctions.phpに追加します。

add_action('add_attachment', function ($post_id) {
  global $wpdb;

  // 保存されたメディアのファイルパスを取得
  $file = get_attached_file($post_id);
  if (!$file) {
    return;
  }

  // ファイル名から拡張子を除いた文字列を取得
  $slug = pathinfo(wp_basename($file), PATHINFO_FILENAME);
  if ($slug === '') {
    return;
  }

  // ファイル名をスラッグ用に変換して登録
  $wpdb->update(
    $wpdb->posts,
    ['post_name' => sanitize_title($slug)],
    ['ID' => $post_id]
  );

  // 更新したメディアのキャッシュを削除
  clean_post_cache($post_id);
});

参考:メディア一覧に「スラッグ」列を追加する方法

現在のメディアのスラッグがどう設定されているかを確認できるよう、メディア一覧に「スラッグ」項目を追加します。

完成イメージ

実装手順

以下のコードをfunctions.phpに追加します。

// 管理画面一覧にカラムを追加
add_filter('manage_media_columns', function ($columns) {
  $columns['media_slug'] = 'スラッグ';

  return $columns;
});


// 管理画面一覧のカラムを並び替え可能に設定
add_filter('manage_upload_sortable_columns', function ($columns) {
  $columns['media_slug'] = 'name';

  return $columns;
});


// 管理画面一覧のカラムにデータを表示
add_action('manage_media_custom_column', function ($column, $post_id) {
  if ($column === 'media_slug') {
    echo esc_html(get_post_field('post_name', $post_id));
  }
}, 10, 2);

参考:過去のメディアを一括変換する方法

これからアップロードする画像だけでなく、過去にアップロード済みの既存メディアのスラッグもファイル名に合わせて一括変換するダッシュボードウィジェットを追加します。

完成イメージ

実装手順

以下のコードをfunctions.phpに追加します。

// ダッシュボードウィジェットを追加
add_action('wp_dashboard_setup', function () {
  wp_add_dashboard_widget(
    'media-slug-sync',
    'メディアスラッグ一括変換',
    'render_media_slug_sync'
  );
});


/**
 * ダッシュボードにウィジェットを出力
 *
 * @return void
 */
if (!function_exists('render_media_slug_sync')):
function render_media_slug_sync()d {
  // 権限チェック
  if (!current_user_can('manage_options')) {
    return;
  }

  // 変換が必要な対象件数を取得
  $count = count(media_slug_sync_get_targets());

  // 処理完了通知メッセージを表示
  if (isset($_GET['media_slug_synced'])) {
    printf('<p style="color:green;">%d 件変換しました。</p>', (int) $_GET['media_slug_synced']);
  }

  // 件数の表示
  echo "<p>対象メディア: <strong>{$count} 件</strong></p>";
  // 対象が0件の場合はフォームを表示せずに終了
  if ($count === 0) {
    return;
  }

  ?>
  <form method="post" action="<?php echo admin_url('admin-post.php'); ?>" onsubmit="return confirm('変換しますか?');">
    <input type="hidden" name="action" value="media_slug_sync">
    <?php wp_nonce_field('media_slug_sync'); ?>
    <button type="submit" class="button button-primary">一括変換</button>
  </form>
  <?php
}
endif;


/**
 * 変換対象のメディア一覧を取得
 *
 * @return array<int, string> [メディアID => 新スラッグ]
 */
if (!function_exists('media_slug_sync_get_targets')):
function media_slug_sync_get_targets(): array {
  global $wpdb;

  // データベースからすべてのメディアとファイルパス情報を取得
  $rows = $wpdb->get_results(
    "SELECT p.ID, p.post_name, m.meta_value AS file
       FROM {$wpdb->posts} p
       INNER JOIN {$wpdb->postmeta} m ON m.post_id = p.ID AND m.meta_key = '_wp_attached_file'
      WHERE p.post_type = 'attachment'"
  );

  $targets = [];
  foreach ($rows as $row) {
    // ファイル名から安全なスラッグを生成
    $slug = sanitize_title(pathinfo(wp_basename($row->file), PATHINFO_FILENAME));
    // スラッグが存在し、現在のスラッグと異なる場合のみ対象に追加
    if ($slug !== '' && $slug !== $row->post_name) {
      $targets[(int) $row->ID] = $slug;
    }
  }
  return $targets;
}
endif;


// 管理者からのPOSTリクエストを実行
add_action('admin_post_media_slug_sync', function () {
  // 権限チェック
  if (!current_user_can('manage_options')) {
    wp_die();
  }

  // nonceチェック
  check_admin_referer('media_slug_sync');

  global $wpdb;
  $done = 0;

  // 対象メディアを順次データベース更新
  foreach (media_slug_sync_get_targets() as $id => $slug) {
    // 重複を回避した一意のスラッグを生成
    $unique = wp_unique_post_slug($slug, $id, 'inherit', 'attachment', 0);
    // スラッグ(post_name)を直接更新
    if ($wpdb->update($wpdb->posts, ['post_name' => $unique], ['ID' => $id]) !== false) {
      // 投稿キャッシュのクリア
      clean_post_cache($id);
      $done++;
    }
  }

  wp_safe_redirect(add_query_arg('media_slug_synced', $done, admin_url('index.php')));
  exit;
});

さいごに

今回紹介した方法を使えば、ファイル名だけでなくスラッグまで自動的に一括整理されるようになります。
これにより、メディアライブラリの整合性が保たれ、エディター上での視認性向上や運用管理の効率化につながります。

タイトルとURLをコピーしました