WordPress
世界最大シェアのCMS。豊富なテーマ・プラグインエコシステムと初心者にも優しいインターフェース。
CMS
WordPress
概要
WordPressは、世界で最も人気のあるオープンソースのコンテンツ管理システム(CMS)です。2003年にブログプラットフォームとして誕生し、現在では全ウェブサイトの43.4%以上で使用されています。PHPとMySQLで構築され、その柔軟性と拡張性により、ブログから企業サイト、ECサイトまで幅広い用途に対応できます。
詳細
WordPressは、その使いやすさと豊富な機能で知られています。5分間の簡単なインストールプロセス、直感的な管理画面、強力なプラグインシステム、そして数千種類のテーマにより、技術的な知識が限られているユーザーでも本格的なウェブサイトを構築できます。
主な特徴:
- プラグインエコシステム: 59,000以上の無料プラグインが利用可能
- テーマシステム: 数千種類のテーマから選択可能
- Gutenbergエディタ: ブロックベースの直感的なコンテンツ編集
- マルチサイト機能: 一つのインストールで複数のサイトを管理
- RESTful API: ヘッドレスCMSとしても利用可能
- 多言語対応: 200以上の言語に翻訳
- SEO最適化: URLの自動生成、メタデータ管理など
メリット・デメリット
メリット
- 使いやすく、非技術者でも管理可能
- 巨大なコミュニティとサポート体制
- 豊富なプラグインとテーマ
- 定期的なセキュリティアップデート
- 無料で利用可能(オープンソース)
- SEOに強い構造
- モバイルレスポンシブ対応
- カスタマイズの自由度が高い
デメリット
- プラグインの多用によるパフォーマンス低下
- セキュリティの脆弱性(人気ゆえの標的)
- アップデート時の互換性問題
- 大規模サイトでのパフォーマンス課題
- データベース構造の制限
- カスタマイズには PHP の知識が必要
参考ページ
- WordPress公式サイト
- WordPress日本語サイト
- WordPress Codex(開発者向けドキュメント)
- WordPress Developer Resources
- WordPress Plugin Directory
- WordPress Theme Directory
書き方の例
1. Hello World(基本的なセットアップ)
functions.php(テーマ機能の追加)
<?php
// テーマのセットアップ
function my_theme_setup() {
// タイトルタグのサポート
add_theme_support('title-tag');
// アイキャッチ画像のサポート
add_theme_support('post-thumbnails');
// カスタムメニューの登録
register_nav_menus(array(
'primary' => __('Primary Menu', 'my-theme'),
'footer' => __('Footer Menu', 'my-theme')
));
}
add_action('after_setup_theme', 'my_theme_setup');
// スタイルシートとスクリプトの読み込み
function my_theme_scripts() {
wp_enqueue_style('my-theme-style', get_stylesheet_uri());
wp_enqueue_script('my-theme-script',
get_template_directory_uri() . '/js/script.js',
array('jquery'), '1.0.0', true
);
}
add_action('wp_enqueue_scripts', 'my_theme_scripts');
2. テーマ開発
index.php(メインテンプレート)
<?php get_header(); ?>
<main id="main" class="site-main">
<?php if (have_posts()) : ?>
<div class="posts-container">
<?php while (have_posts()) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<header class="entry-header">
<h2 class="entry-title">
<a href="<?php the_permalink(); ?>">
<?php the_title(); ?>
</a>
</h2>
<div class="entry-meta">
<?php echo get_the_date(); ?> |
<?php the_author(); ?> |
<?php the_category(', '); ?>
</div>
</header>
<?php if (has_post_thumbnail()) : ?>
<div class="entry-thumbnail">
<?php the_post_thumbnail('medium'); ?>
</div>
<?php endif; ?>
<div class="entry-content">
<?php the_excerpt(); ?>
</div>
<footer class="entry-footer">
<a href="<?php the_permalink(); ?>" class="read-more">
<?php _e('Read More', 'my-theme'); ?> →
</a>
</footer>
</article>
<?php endwhile; ?>
<div class="pagination">
<?php the_posts_pagination(array(
'mid_size' => 2,
'prev_text' => __('← Previous', 'my-theme'),
'next_text' => __('Next →', 'my-theme'),
)); ?>
</div>
</div>
<?php else : ?>
<p><?php _e('No posts found.', 'my-theme'); ?></p>
<?php endif; ?>
</main>
<?php get_sidebar(); ?>
<?php get_footer(); ?>
3. プラグイン開発
my-plugin.php(基本的なプラグイン構造)
<?php
/**
* Plugin Name: My Custom Plugin
* Plugin URI: https://example.com/my-plugin
* Description: カスタム機能を追加するプラグイン
* Version: 1.0.0
* Author: Your Name
* Author URI: https://example.com
* License: GPL v2 or later
* Text Domain: my-plugin
*/
// 直接アクセスを防ぐ
if (!defined('ABSPATH')) {
exit;
}
// プラグインのアクティベーション
register_activation_hook(__FILE__, 'my_plugin_activate');
function my_plugin_activate() {
// データベーステーブルの作成
global $wpdb;
$table_name = $wpdb->prefix . 'my_plugin_data';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
value text NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
// ショートコードの登録
add_shortcode('my_custom_shortcode', 'my_custom_shortcode_handler');
function my_custom_shortcode_handler($atts) {
$atts = shortcode_atts(array(
'title' => 'Default Title',
'color' => 'blue'
), $atts);
ob_start();
?>
<div class="my-custom-box" style="border-color: <?php echo esc_attr($atts['color']); ?>">
<h3><?php echo esc_html($atts['title']); ?></h3>
<p>This is custom content from my plugin!</p>
</div>
<?php
return ob_get_clean();
}
// 管理画面メニューの追加
add_action('admin_menu', 'my_plugin_admin_menu');
function my_plugin_admin_menu() {
add_menu_page(
'My Plugin Settings',
'My Plugin',
'manage_options',
'my-plugin',
'my_plugin_admin_page',
'dashicons-admin-generic',
20
);
}
function my_plugin_admin_page() {
?>
<div class="wrap">
<h1>My Plugin Settings</h1>
<form method="post" action="options.php">
<?php settings_fields('my_plugin_settings'); ?>
<?php do_settings_sections('my_plugin_settings'); ?>
<?php submit_button(); ?>
</form>
</div>
<?php
}
4. カスタム投稿タイプ
custom-post-type.php(カスタム投稿タイプの登録)
<?php
// カスタム投稿タイプ「製品」の登録
add_action('init', 'register_product_post_type');
function register_product_post_type() {
$labels = array(
'name' => '製品',
'singular_name' => '製品',
'add_new' => '新規追加',
'add_new_item' => '新しい製品を追加',
'edit_item' => '製品を編集',
'new_item' => '新しい製品',
'view_item' => '製品を表示',
'search_items' => '製品を検索',
'not_found' => '製品が見つかりません',
'not_found_in_trash' => 'ゴミ箱に製品はありません',
'menu_name' => '製品'
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-cart',
'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
'rewrite' => array('slug' => 'products'),
'show_in_rest' => true // Gutenbergエディタのサポート
);
register_post_type('product', $args);
}
// カスタムタクソノミー「製品カテゴリー」の登録
add_action('init', 'register_product_taxonomy');
function register_product_taxonomy() {
$labels = array(
'name' => '製品カテゴリー',
'singular_name' => '製品カテゴリー',
'search_items' => 'カテゴリーを検索',
'all_items' => 'すべてのカテゴリー',
'parent_item' => '親カテゴリー',
'parent_item_colon' => '親カテゴリー:',
'edit_item' => 'カテゴリーを編集',
'update_item' => 'カテゴリーを更新',
'add_new_item' => '新しいカテゴリーを追加',
'new_item_name' => '新しいカテゴリー名',
'menu_name' => '製品カテゴリー'
);
$args = array(
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'show_in_rest' => true,
'rewrite' => array('slug' => 'product-category')
);
register_taxonomy('product_category', 'product', $args);
}
// カスタムフィールドの追加(ACF不使用)
add_action('add_meta_boxes', 'add_product_meta_boxes');
function add_product_meta_boxes() {
add_meta_box(
'product_details',
'製品詳細',
'product_details_callback',
'product',
'normal',
'high'
);
}
function product_details_callback($post) {
wp_nonce_field('product_details_nonce', 'product_details_nonce');
$price = get_post_meta($post->ID, '_product_price', true);
$sku = get_post_meta($post->ID, '_product_sku', true);
?>
<table class="form-table">
<tr>
<th><label for="product_price">価格</label></th>
<td>
<input type="text" id="product_price" name="product_price"
value="<?php echo esc_attr($price); ?>" class="regular-text" />
</td>
</tr>
<tr>
<th><label for="product_sku">SKU</label></th>
<td>
<input type="text" id="product_sku" name="product_sku"
value="<?php echo esc_attr($sku); ?>" class="regular-text" />
</td>
</tr>
</table>
<?php
}
// カスタムフィールドの保存
add_action('save_post_product', 'save_product_details');
function save_product_details($post_id) {
if (!isset($_POST['product_details_nonce']) ||
!wp_verify_nonce($_POST['product_details_nonce'], 'product_details_nonce')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (isset($_POST['product_price'])) {
update_post_meta($post_id, '_product_price',
sanitize_text_field($_POST['product_price']));
}
if (isset($_POST['product_sku'])) {
update_post_meta($post_id, '_product_sku',
sanitize_text_field($_POST['product_sku']));
}
}
5. データベース操作
database-operations.php(WPDBを使用したデータベース操作)
<?php
// グローバルな$wpdbオブジェクトを使用
global $wpdb;
// 1. データの挿入
function insert_custom_data($name, $value) {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
$result = $wpdb->insert(
$table_name,
array(
'name' => $name,
'value' => $value,
'created_at' => current_time('mysql')
),
array('%s', '%s', '%s') // データ型の指定
);
if ($result === false) {
error_log('Database insert failed: ' . $wpdb->last_error);
return false;
}
return $wpdb->insert_id;
}
// 2. データの取得
function get_custom_data($limit = 10) {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
// 準備されたステートメントを使用(SQLインジェクション対策)
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM $table_name ORDER BY created_at DESC LIMIT %d",
$limit
)
);
return $results;
}
// 3. 特定のデータを取得
function get_custom_data_by_name($name) {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
$result = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $table_name WHERE name = %s",
$name
)
);
return $result;
}
// 4. データの更新
function update_custom_data($id, $name, $value) {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
$result = $wpdb->update(
$table_name,
array(
'name' => $name,
'value' => $value,
'updated_at' => current_time('mysql')
),
array('id' => $id),
array('%s', '%s', '%s'),
array('%d')
);
return $result !== false;
}
// 5. データの削除
function delete_custom_data($id) {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
$result = $wpdb->delete(
$table_name,
array('id' => $id),
array('%d')
);
return $result !== false;
}
// 6. カスタムクエリの実行
function get_statistics() {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
// 統計情報の取得
$stats = $wpdb->get_results("
SELECT
COUNT(*) as total_records,
COUNT(DISTINCT name) as unique_names,
MAX(created_at) as last_created
FROM $table_name
");
return $stats[0];
}
// 7. トランザクション処理(WordPress 5.5以降)
function complex_database_operation($data_array) {
global $wpdb;
// トランザクション開始
$wpdb->query('START TRANSACTION');
try {
foreach ($data_array as $data) {
$result = insert_custom_data($data['name'], $data['value']);
if (!$result) {
throw new Exception('Insert failed');
}
}
// コミット
$wpdb->query('COMMIT');
return true;
} catch (Exception $e) {
// ロールバック
$wpdb->query('ROLLBACK');
error_log('Transaction failed: ' . $e->getMessage());
return false;
}
}
6. API連携
rest-api.php(REST APIの実装)
<?php
// カスタムREST APIエンドポイントの登録
add_action('rest_api_init', function () {
// 製品一覧の取得
register_rest_route('myapi/v1', '/products', array(
'methods' => 'GET',
'callback' => 'get_products_api',
'permission_callback' => '__return_true', // 公開API
'args' => array(
'per_page' => array(
'default' => 10,
'sanitize_callback' => 'absint',
),
'page' => array(
'default' => 1,
'sanitize_callback' => 'absint',
),
),
));
// 単一製品の取得
register_rest_route('myapi/v1', '/products/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'get_single_product_api',
'permission_callback' => '__return_true',
'args' => array(
'id' => array(
'validate_callback' => function($param, $request, $key) {
return is_numeric($param);
}
),
),
));
// 製品の作成(認証必須)
register_rest_route('myapi/v1', '/products', array(
'methods' => 'POST',
'callback' => 'create_product_api',
'permission_callback' => function() {
return current_user_can('edit_posts');
},
'args' => array(
'title' => array(
'required' => true,
'sanitize_callback' => 'sanitize_text_field',
),
'content' => array(
'required' => true,
'sanitize_callback' => 'wp_kses_post',
),
'price' => array(
'required' => false,
'sanitize_callback' => 'sanitize_text_field',
),
),
));
});
// 製品一覧を取得するAPIコールバック
function get_products_api($request) {
$per_page = $request->get_param('per_page');
$page = $request->get_param('page');
$args = array(
'post_type' => 'product',
'posts_per_page' => $per_page,
'paged' => $page,
'post_status' => 'publish',
);
$query = new WP_Query($args);
$products = array();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$products[] = array(
'id' => get_the_ID(),
'title' => get_the_title(),
'content' => get_the_content(),
'excerpt' => get_the_excerpt(),
'price' => get_post_meta(get_the_ID(), '_product_price', true),
'sku' => get_post_meta(get_the_ID(), '_product_sku', true),
'featured_image' => get_the_post_thumbnail_url(get_the_ID(), 'full'),
'date' => get_the_date('c'),
'link' => get_permalink(),
);
}
}
wp_reset_postdata();
return new WP_REST_Response(array(
'products' => $products,
'total' => $query->found_posts,
'pages' => $query->max_num_pages,
'current_page' => $page,
), 200);
}
// 単一製品を取得するAPIコールバック
function get_single_product_api($request) {
$id = $request->get_param('id');
$post = get_post($id);
if (!$post || $post->post_type !== 'product') {
return new WP_Error(
'product_not_found',
'Product not found',
array('status' => 404)
);
}
$product = array(
'id' => $post->ID,
'title' => $post->post_title,
'content' => apply_filters('the_content', $post->post_content),
'excerpt' => $post->post_excerpt,
'price' => get_post_meta($post->ID, '_product_price', true),
'sku' => get_post_meta($post->ID, '_product_sku', true),
'featured_image' => get_the_post_thumbnail_url($post->ID, 'full'),
'gallery' => get_post_meta($post->ID, '_product_gallery', true),
'categories' => wp_get_post_terms($post->ID, 'product_category',
array('fields' => 'names')),
'date' => get_the_date('c', $post),
'modified' => get_the_modified_date('c', $post),
'author' => get_the_author_meta('display_name', $post->post_author),
'link' => get_permalink($post->ID),
);
return new WP_REST_Response($product, 200);
}
// 製品を作成するAPIコールバック
function create_product_api($request) {
$title = $request->get_param('title');
$content = $request->get_param('content');
$price = $request->get_param('price');
$post_data = array(
'post_title' => $title,
'post_content' => $content,
'post_type' => 'product',
'post_status' => 'draft', // 下書きとして作成
'post_author' => get_current_user_id(),
);
$post_id = wp_insert_post($post_data);
if (is_wp_error($post_id)) {
return new WP_Error(
'product_creation_failed',
'Failed to create product',
array('status' => 500)
);
}
// カスタムフィールドを保存
if ($price) {
update_post_meta($post_id, '_product_price', $price);
}
return new WP_REST_Response(array(
'id' => $post_id,
'message' => 'Product created successfully',
'link' => get_permalink($post_id),
), 201);
}
// JWT認証の実装例(別途JWT認証プラグインが必要)
add_filter('rest_authentication_errors', function($result) {
// すでにユーザーがログインしている場合はスキップ
if (!empty($result)) {
return $result;
}
// Authorizationヘッダーを確認
$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (strpos($auth_header, 'Bearer ') === 0) {
$token = substr($auth_header, 7);
// JWTトークンの検証(実装は省略)
$user_id = verify_jwt_token($token);
if ($user_id) {
wp_set_current_user($user_id);
return true;
}
}
return $result;
});