オリジナルプラグイン作成
ソースファイル
wp-content/
┣ plugins/
┣ simple-image-search/
┣ simple-image-search.php
┣ js/search.js
┗ css/style.css
simple-image-search.php
下記のようにすればひとまずプラグインとして登録できており、有効化すると編集画面でショートコード[simple-image-search]でフォームが表示されます。
<?php
/**
* Plugin Name: Simple Image Search
* Description: シンプルな画像検索プラグイン
* Version: 0.1
* Author: Your Name
*/
// 直接アクセス禁止
if (!defined('ABSPATH')) exit;
class SimpleImageSearch {
public function __construct() {
// 初期化フック
add_action('init', array($this, 'init'));
// Ajax処理の登録(ログイン・非ログインユーザー両方用)
add_action('wp_ajax_simple_image_search', array($this, 'handle_search'));
add_action('wp_ajax_nopriv_simple_image_search', array($this, 'handle_search'));
// スクリプトとスタイルの読み込み
add_action('wp_enqueue_scripts', array($this, 'enqueue_assets'));
}
/**
* 初期化処理
*/
public function init() {
// ショートコードの登録
add_shortcode('simple_image_search', array($this, 'render_search_form'));
}
/**
* スクリプトとスタイルの読み込み
*/
public function enqueue_assets() {
// CSSの登録と読み込み
wp_enqueue_style(
'simple-image-search',
plugins_url('css/style.css', __FILE__),
array(),
'0.1'
);
// JavaScriptの登録と読み込み
wp_enqueue_script(
'simple-image-search',
plugins_url('js/search.js', __FILE__),
array(), // 依存関係なし
'0.1',
true // フッターで読み込み
);
// Ajax URLとnonceをJavaScriptに渡す
wp_localize_script(
'simple-image-search',
'simpleImageSearch',
array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('simple_image_search_nonce')
)
);
}
/**
* 検索フォームの表示
*/
public function render_search_form() {
ob_start();
?>
<div class="simple-image-search">
<div class="search-header">
<input type="text"
id="image-search-input"
placeholder="画像を検索..."
autocomplete="off">
</div>
<div id="image-search-results" class="search-results"></div>
</div>
<?php
return ob_get_clean();
}
/**
* 検索処理のハンドラー(Ajax)
*/
public function handle_search() {
// nonceチェック
check_ajax_referer('simple_image_search_nonce', 'nonce');
// 検索キーワードを取得して整形
$search_term = sanitize_text_field($_POST['search_term'] ?? '');
// 検索クエリの設定
$args = array(
'post_type' => 'attachment',
'post_mime_type' => array(
'image/jpeg',
'image/png',
'image/gif'
),
'post_status' => 'inherit',
'posts_per_page' => 20,
's' => $search_term,
'orderby' => 'date',
'order' => 'DESC'
);
// 検索実行
$query = new WP_Query($args);
$results = array();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$attachment_id = get_the_ID();
// 画像情報の取得
$thumbnail_url = wp_get_attachment_image_url($attachment_id, 'thumbnail');
$full_url = wp_get_attachment_image_url($attachment_id, 'full');
$metadata = wp_get_attachment_metadata($attachment_id);
// ファイルサイズの取得
$file_path = get_attached_file($attachment_id);
$file_size = file_exists($file_path) ? filesize($file_path) : 0;
$results[] = array(
'id' => $attachment_id,
'title' => get_the_title(),
'thumbnail_url' => $thumbnail_url,
'full_url' => $full_url,
'width' => $metadata['width'] ?? '',
'height' => $metadata['height'] ?? '',
'filesize' => size_format($file_size),
'date' => get_the_date()
);
}
}
wp_reset_postdata();
wp_send_json_success($results);
}
}
// プラグインのインスタンス化
new SimpleImageSearch();
search.js
/**
* 画像検索用のJavaScript
*/
document.addEventListener("DOMContentLoaded", function () {
const searchInput = document.getElementById("image-search-input");
const resultsContainer = document.getElementById("image-search-results");
let searchTimer = null;
let isSearching = false;
// 検索入力イベントの設定
searchInput.addEventListener("input", function () {
clearTimeout(searchTimer);
const searchTerm = this.value.trim();
if (searchTerm === "") {
resultsContainer.innerHTML = "";
return;
}
// 入力から300ms後に検索実行
searchTimer = setTimeout(() => {
performSearch(searchTerm);
}, 300);
});
/**
* 検索実行関数
*/
async function performSearch(searchTerm) {
if (isSearching) return;
isSearching = true;
resultsContainer.innerHTML = '<div class="searching">検索中...</div>';
try {
const formData = new FormData();
formData.append("action", "simple_image_search");
formData.append("nonce", simpleImageSearch.nonce);
formData.append("search_term", searchTerm);
const response = await fetch(simpleImageSearch.ajax_url, {
method: "POST",
body: formData,
});
const data = await response.json();
if (data.success) {
displayResults(data.data);
} else {
resultsContainer.innerHTML =
'<div class="error">検索中にエラーが発生しました</div>';
}
} catch (error) {
console.error("Search error:", error);
resultsContainer.innerHTML =
'<div class="error">検索中にエラーが発生しました</div>';
} finally {
isSearching = false;
}
}
/**
* 結果表示関数
*/
function displayResults(results) {
resultsContainer.innerHTML = "";
if (results.length === 0) {
resultsContainer.innerHTML =
'<div class="no-results">画像が見つかりませんでした</div>';
return;
}
const gridContainer = document.createElement("div");
gridContainer.className = "image-grid";
results.forEach((image) => {
const imageItem = createImageItem(image);
gridContainer.appendChild(imageItem);
});
resultsContainer.appendChild(gridContainer);
}
/**
* 画像アイテム要素作成関数
*/
function createImageItem(image) {
const imageItem = document.createElement("div");
imageItem.className = "image-item";
// クリックでオリジナル画像を新しいタブで開く
imageItem.addEventListener("click", () => {
window.open(image.full_url, "_blank");
});
imageItem.innerHTML = `
<div class="image-preview">
<img src="${image.thumbnail_url}"
alt="${image.title}"
loading="lazy">
</div>
<div class="image-info">
<div class="title">${image.title}</div>
<div class="meta">
${image.width}x${image.height}px
<span class="separator">|</span>
${image.filesize}
</div>
</div>
`;
return imageItem;
}
});
style.css
.simple-image-search {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
/* 検索入力エリア */
.search-header {
margin-bottom: 20px;
}
#image-search-input {
width: 100%;
padding: 10px;
font-size: 16px;
border: 2px solid #ddd;
border-radius: 4px;
transition: border-color 0.3s ease;
}
#image-search-input:focus {
border-color: #0073aa;
outline: none;
}
/* 検索結果グリッド */
.image-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
}
/* 画像アイテム */
.image-item {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
background: #fff;
}
.image-item:hover {
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
/* 画像プレビュー */
.image-preview {
position: relative;
padding-top: 75%; /* 4:3のアスペクト比 */
background: #f0f0f0;
}
.image-preview img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
/* 画像情報 */
.image-info {
padding: 10px;
}
.image-info .title {
font-size: 14px;
font-weight: 500;
margin-bottom: 4px;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.image-info .meta {
font-size: 12px;
color: #666;
}
.image-info .separator {
margin: 0 5px;
color: #ddd;
}
/* ステータスメッセージ */
.searching,
.error,
.no-results {
text-align: center;
padding: 20px;
color: #666;
}
.error {
color: #d63638;
}
/* レスポンシブ対応 */
@media (max-width: 600px) {
.image-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 10px;
}
.image-info .title {
font-size: 12px;
}
.image-info .meta {
font-size: 11px;
}
}
検索のロジック
メディアライブラリに画像をアップロードしたときの流れ
1. 画像アップロード
↓
2. wp_postsテーブルにレコード作成
- post_type = 'attachment'
- post_mime_type = 'image/jpeg'(など)
- post_title = ファイル名(自動設定)
↓
3. wp_postmetaテーブルにメタ情報を保存
- _wp_attachment_metadata(サイズ情報など)
- _wp_attachment_image_alt(Alt テキスト)
WordPressの基本的なデータベース構造
/**
* wp_posts テーブル(メインテーブル)
* すべての投稿、ページ、メディアファイルの基本情報を格納
*/
CREATE TABLE wp_posts (
ID bigint(20) NOT NULL AUTO_INCREMENT, -- 投稿/メディアのユニークID
post_title text NOT NULL, -- タイトル
post_name varchar(200) NOT NULL, -- スラッグ(URL用)
post_content longtext NOT NULL, -- 本文/説明
post_excerpt text NOT NULL, -- 抜粋/キャプション
post_type varchar(20) NOT NULL, -- 投稿タイプ(attachment=メディア)
post_mime_type varchar(100) NOT NULL, -- メディアタイプ(image/jpeg等)
post_status varchar(20) NOT NULL, -- 状態
/* その他のフィールド */
);
/**
* wp_postmeta テーブル(メタ情報テーブル)
* 追加の情報を格納(Alt テキスト、画像サイズなど)
*/
CREATE TABLE wp_postmeta (
meta_id bigint(20) NOT NULL AUTO_INCREMENT, -- メタ情報のID
post_id bigint(20) NOT NULL, -- 関連する投稿/メディアのID
meta_key varchar(255), -- メタデータの種類
meta_value longtext, -- メタデータの値
);