MENU
  • WEB制作・開発
    • 学習・挑戦記Web制作に関連する情報
    • 技術MEMO
    • セキュリティ
  • IT TOOL一覧
    • ECサイトIT TOOL ECサイト
    • アピス在庫管理
    • クラウドファンディング
    • セルフオーダーシステム
    • レッスン施術サービスレッスン施術サービス予約サイト
    • シンプルクラウドソーシング
    • 会議室予約
    • ShopifyShopifyに関連する設定などさまざまな投稿をしていきます。
  • 在庫管理
  • ビジネス支援ツール
    • Canva
    • WordPressWordpressのサイト構築あれこれ!
    • ZOOM
    • エクセル・ワード
    • バーコード
  • このブランドはどこの国?|
  • テクノロジー・トレンド
  • お知らせ
  • IT導入補助金
  • イヤホン
  • スマホ・PC・タブレット
  • SEO・ブログ運営
  • アクセス解析
  • ブログ運営
  • ブログ収益化
  • プロンプト
  • PC関連ネットで販売するPC関連商品の説明
技術が生活を楽にする
tecn
    • WEB制作・開発
      • 学習・挑戦記Web制作に関連する情報
      • 技術MEMO
      • セキュリティ
    • IT TOOL一覧
      • ECサイトIT TOOL ECサイト
      • アピス在庫管理
      • クラウドファンディング
      • セルフオーダーシステム
      • レッスン施術サービスレッスン施術サービス予約サイト
      • シンプルクラウドソーシング
      • 会議室予約
      • ShopifyShopifyに関連する設定などさまざまな投稿をしていきます。
    • 在庫管理
    • ビジネス支援ツール
      • Canva
      • WordPressWordpressのサイト構築あれこれ!
      • ZOOM
      • エクセル・ワード
      • バーコード
    • このブランドはどこの国?|
    • テクノロジー・トレンド
    • お知らせ
    • IT導入補助金
    • イヤホン
    • スマホ・PC・タブレット
    • SEO・ブログ運営
    • アクセス解析
    • ブログ運営
    • ブログ収益化
    • プロンプト
    • PC関連ネットで販売するPC関連商品の説明
tecn
    • WEB制作・開発
      • 学習・挑戦記Web制作に関連する情報
      • 技術MEMO
      • セキュリティ
    • IT TOOL一覧
      • ECサイトIT TOOL ECサイト
      • アピス在庫管理
      • クラウドファンディング
      • セルフオーダーシステム
      • レッスン施術サービスレッスン施術サービス予約サイト
      • シンプルクラウドソーシング
      • 会議室予約
      • ShopifyShopifyに関連する設定などさまざまな投稿をしていきます。
    • 在庫管理
    • ビジネス支援ツール
      • Canva
      • WordPressWordpressのサイト構築あれこれ!
      • ZOOM
      • エクセル・ワード
      • バーコード
    • このブランドはどこの国?|
    • テクノロジー・トレンド
    • お知らせ
    • IT導入補助金
    • イヤホン
    • スマホ・PC・タブレット
    • SEO・ブログ運営
    • アクセス解析
    • ブログ運営
    • ブログ収益化
    • プロンプト
    • PC関連ネットで販売するPC関連商品の説明
  1. ホーム
  2. WordPress
  3. WordPressでNEWS配信システムを作る実践講座|第6回:固定ページ内でNEWS候補を編集・承認できる担当者UIを作る

WordPressでNEWS配信システムを作る実践講座|第6回:固定ページ内でNEWS候補を編集・承認できる担当者UIを作る

2026 7/05
AI活用 生産性アップ・便利 WordPress 未分類
2026年7月5日

第5回では、固定ページにショートコードを貼り、NEWS候補一覧を表示する管理画面を作りました。

固定ページに、

このページを見るにはログインが必要です。

というショートコードを貼ることで、登録済みのNEWS候補を一覧で確認できるようになりました。

一覧画面では、表示先NEWS、承認ステータス、表示フラグ、X投稿ステータス、カテゴリ、NEWS表示文、元記事リンク、編集リンクを確認できるようにしました。

ただし、第5回の段階では、固定ページ側はあくまで一覧確認用でした。

NEWS表示文を修正したり、表示先NEWSを変更したり、承認ステータスを変更したりする場合は、一覧の「編集」リンクからWordPressダッシュボード側のNEWS候補編集画面へ移動する必要がありました。

この方法でも、初期運用としては問題ありません。

WordPressの管理画面に慣れている人であれば、ダッシュボード側のNEWS候補編集画面で修正できます。

しかし、NEWS管理を行う担当者が増えてきたり、WordPressの細かい操作に慣れていない人がNEWS候補だけを確認・承認するようになったりすると、ダッシュボード全体を見せずに、専用の固定ページだけで作業できる方が分かりやすくなります。

そこで第6回では、固定ページ側のNEWS候補管理画面を発展させます。

固定ページ上で、NEWS候補の内容を確認するだけでなく、NEWS表示文、表示先NEWS、表示フラグ、承認ステータス、X投稿ステータス、メモを編集・保存できるようにします。

これにより、担当者はWordPressダッシュボードの細かい操作を知らなくても、TECN NEWS候補管理ページだけで日々のNEWS確認作業を進められるようになります。

目次

H2-1 第6回で行うこと

第6回では、固定ページ側のNEWS候補管理画面を、一覧確認画面から編集・承認できる担当者UIへ発展させます。

第5回の固定ページでは、NEWS候補一覧を表示することができました。

しかし、編集そのものはダッシュボード側のNEWS候補編集画面で行う形でした。

第6回では、固定ページ上で次の操作ができるようにします。

NEWS表示文を編集する。

表示先NEWSを選択する。

表示対象にするかどうかを切り替える。

承認ステータスを変更する。

X投稿ステータスを変更する。

メモを編集する。

保存ボタンで更新する。

必要な場合は、ダッシュボード側の詳細編集画面へ移動する。

つまり、第6回では、固定ページ側を単なる確認画面ではなく、担当者が日常的に使えるNEWS管理画面にします。

ただし、今回の初版では、NEWS候補が複数ある場合に、すべてのNEWS候補をカード形式で表示し、それぞれのカード上で編集できる形にします。

たとえばNEWS候補が10件あれば、10件分の編集カードが表示されます。

件数が多くなってきた場合は、将来的に「一覧画面から1件を選んで詳細編集する方式」や、「未確認だけ表示する方式」へ改善できます。

しかし、まずは初版として、固定ページ側で編集・承認・保存までできることを優先します。

H2-2 第5回まででできていること

第5回までで、TECN NEWS候補管理 V1はかなり形になってきました。

第3回では、NEWS候補を保存するためのカスタム投稿タイプを作りました。

WordPress管理画面に「NEWS候補」という専用メニューを追加し、通常の記事とは別にNEWS候補を管理できるようにしました。

第4回では、NEWS候補の編集画面に入力項目を追加しました。

元記事URL、カテゴリ、NEWS表示文、表示先NEWS、表示フラグ、承認ステータス、X投稿文案、X投稿ステータス、メモを入力・保存できるようにしました。

第5回では、固定ページにNEWS候補一覧を表示するショートコードを作りました。

固定ページ「TECN NEWS候補管理」に、

このページを見るにはログインが必要です。

を貼ることで、担当者がNEWS候補を一覧で確認できるようになりました。

ここまでで、次のことができる状態になっています。

NEWS候補を登録できる。

NEWS候補に必要な情報を保存できる。

ダッシュボード側でNEWS候補を編集できる。

固定ページ側でNEWS候補一覧を確認できる。

元記事を開ける。

編集リンクからダッシュボード側のNEWS候補編集画面へ移動できる。

第6回では、ここに固定ページ側での編集・承認機能を追加します。

H2-3 なぜ固定ページ側にも編集UIを作るのか

WordPressには、もともと管理画面があります。

NEWS候補も、ダッシュボード側の「NEWS候補」メニューから編集できます。

そのため、技術的には固定ページ側に編集UIを作らなくても運用はできます。

しかし、実務では、担当者全員がWordPressのダッシュボード操作に慣れているとは限りません。

WordPressの管理画面には、投稿、固定ページ、外観、プラグイン、ユーザー、設定など、さまざまなメニューがあります。

NEWS候補だけを確認したい担当者にとっては、ダッシュボード全体が見えるとかえって分かりにくい場合があります。

そこで、固定ページ側に専用のNEWS管理UIを作ります。

担当者は、固定ページ「TECN NEWS候補管理」を開くだけで、NEWS候補を確認できます。

さらに、第6回では、そのページ上でNEWS表示文や承認ステータスを変更できるようにします。

これにより、担当者はWordPressの細かい操作を覚えなくても、NEWS管理に必要な作業だけを行えるようになります。

一方で、ダッシュボード側の管理機能も残します。

つまり、第6回以降は、次の2つの管理方法が使えるようになります。

1つ目は、ダッシュボード側の管理です。

WordPress操作に慣れている人は、NEWS候補一覧やNEWS候補編集画面から詳細に管理できます。

2つ目は、固定ページ側の管理です。

NEWS担当者は、固定ページの専用UIから、NEWS表示文、表示先NEWS、表示フラグ、承認ステータスなどを編集できます。

このように、ダッシュボード側と固定ページ側の両方から管理できる形にしておくと、運用の幅が広がります。

H2-4 第6回の完成イメージ

第6回の完成イメージは、固定ページ上にNEWS候補ごとのカードが表示される形です。

各カードには、NEWS候補のタイトル、登録日、元記事URL、カテゴリ、NEWS表示文、表示先NEWS、承認ステータス、表示フラグ、X投稿ステータス、メモ、保存ボタンが表示されます。

担当者は、カードごとに内容を確認します。

NEWS表示文に修正が必要であれば、テキストエリアで修正します。

表示先NEWSが違っていれば、プルダウンから正しい表示先を選びます。

表示対象にする場合は、チェックボックスをONにします。

確認が終わったら、承認ステータスを「承認済み」に変更します。

X投稿を行った場合は、X投稿ステータスを「投稿済み」に変更します。

補足事項があれば、メモ欄に入力します。

最後に「このNEWS候補を保存」ボタンを押します。

保存後、画面上に「NEWS候補を更新しました。」というメッセージが表示されます。

ページを再読み込みしても変更内容が残っていれば、固定ページ側からの更新処理が成功しています。

また、ダッシュボード側のNEWS候補編集画面を開いても、同じ値が反映されています。

つまり、第6回では、固定ページ側とダッシュボード側の両方から同じNEWS候補データを管理できるようになります。

H2-5 第6回で更新できる項目

第6回の固定ページ側UIでは、すべての項目を編集対象にするわけではありません。

編集できる項目と、表示確認だけにする項目を分けます。

固定ページ側で編集できる項目は、次の通りです。

NEWS表示文。

表示先NEWS。

表示フラグ。

承認ステータス。

X投稿ステータス。

メモ。

これらは、担当者が日常的に変更する可能性が高い項目です。

たとえば、NEWS表示文は読者に見せる文面なので、担当者が修正することがあります。

表示先NEWSは、TECN NEWS、どこの国NEWS、在庫管理 / DX NEWSなど、どのNEWS枠に表示するかを決める項目です。

表示フラグは、実際に表示対象にするかどうかを決める項目です。

承認ステータスは、未確認、修正中、承認済み、非表示のように、NEWS候補の状態を管理する項目です。

X投稿ステータスは、X投稿を行うか、投稿済みか、投稿しないかを管理する項目です。

メモは、判断理由や注意点を残すために使います。

一方で、固定ページ側では表示確認だけにする項目もあります。

元記事URL。

カテゴリ。

NEWS候補のタイトル。

登録日。

これらは、基本的には元記事情報として扱います。

大きく修正する必要がある場合は、ダッシュボード側のNEWS候補編集画面で変更します。

このように、固定ページ側では日常運用に必要な項目だけを編集できるようにし、詳細編集はダッシュボード側に残します。

H2-6 第6回の実装方針

第6回では、第5回で作ったショートコード

このページを見るにはログインが必要です。
の中身を差し替えます。

第5回では、NEWS候補を一覧テーブルで表示していました。

第6回では、一覧テーブルではなく、NEWS候補ごとのカード形式に変更します。

カードの中に編集フォームを入れ、それぞれのNEWS候補を固定ページ上で更新できるようにします。

ここで注意が必要なのは、同じショートコード名を使うことです。

第5回と同じ、

このページを見るにはログインが必要です。

を使います。

そのため、新しいスニペットを追加するのではなく、第5回で作成したスニペットの中身を第6回版に丸ごと差し替えます。

同じ関数名や同じショートコードを別スニペットで重複登録すると、エラーになる可能性があります。

安全な手順は次の通りです。

Code Snippetsで「TECN NEWS候補管理 V1:NEWS候補一覧ショートコード」を開く。

既存コードをすべて削除する。

第6回版のコードを貼り付ける。

保存して有効化する。

固定ページ「TECN NEWS候補管理」を再表示する。

これで、同じ固定ページ、同じショートコードのまま、固定ページ側のUIを第6回版に更新できます。

H2-7 第6回版ショートコードのコード

それでは、第6回版のコードを用意します。

Code Snippetsに貼り付ける場合は、先頭の <?php は入れません。

第5回で作ったスニペット、

TECN NEWS候補管理 V1:NEWS候補一覧ショートコード

を開き、中身を以下のコードに差し替えます。

/**
 * TECN NEWS候補管理 V1
 * 固定ページ側 NEWS候補編集・承認UI
 *
 * 固定ページに [apice_news_admin] を貼ると、
 * ログイン済みで投稿編集権限のある担当者が
 * NEWS候補を一覧確認し、その場で編集・承認できます。
 */

function apice_news_admin_shortcode() {

    // ログイン確認
    if ( ! is_user_logged_in() ) {
        return '<div style="padding:16px; border:1px solid #ddd; background:#fafafa;">このページを見るにはログインが必要です。</div>';
    }

    // 権限確認
    if ( ! current_user_can( 'edit_posts' ) ) {
        return '<div style="padding:16px; border:1px solid #ddd; background:#fafafa;">このページを表示する権限がありません。</div>';
    }

    $message = '';

    /**
     * 固定ページ側からの更新処理
     */
    if (
        isset( $_POST['apice_news_admin_action'] ) &&
        $_POST['apice_news_admin_action'] === 'update_news_candidate'
    ) {

        $post_id = isset( $_POST['apice_news_post_id'] ) ? intval( $_POST['apice_news_post_id'] ) : 0;

        if (
            $post_id > 0 &&
            get_post_type( $post_id ) === 'apice_news_candidate' &&
            current_user_can( 'edit_post', $post_id ) &&
            isset( $_POST['apice_news_admin_nonce'] ) &&
            wp_verify_nonce( $_POST['apice_news_admin_nonce'], 'apice_news_admin_update_' . $post_id )
        ) {

            $allowed_news_targets = array(
                '',
                'TECN NEWS',
                'ダイソーNEWS',
                'どこの国NEWS',
                'LDAC / Bluetooth NEWS',
                '在庫管理 / DX NEWS',
                'TECNおすすめ',
                '非表示',
            );

            $allowed_approval_statuses = array(
                '未確認',
                '修正中',
                '承認済み',
                '非表示',
            );

            $allowed_x_post_statuses = array(
                '未投稿',
                '投稿済み',
                '投稿しない',
            );

            if ( isset( $_POST['news_text'] ) ) {
                update_post_meta(
                    $post_id,
                    'news_text',
                    sanitize_textarea_field( $_POST['news_text'] )
                );
            }

            if (
                isset( $_POST['news_target'] ) &&
                in_array( $_POST['news_target'], $allowed_news_targets, true )
            ) {
                update_post_meta(
                    $post_id,
                    'news_target',
                    sanitize_text_field( $_POST['news_target'] )
                );
            }

            $display_flag = isset( $_POST['display_flag'] ) ? '1' : '0';
            update_post_meta( $post_id, 'display_flag', $display_flag );

            if (
                isset( $_POST['approval_status'] ) &&
                in_array( $_POST['approval_status'], $allowed_approval_statuses, true )
            ) {
                update_post_meta(
                    $post_id,
                    'approval_status',
                    sanitize_text_field( $_POST['approval_status'] )
                );
            }

            if (
                isset( $_POST['x_post_status'] ) &&
                in_array( $_POST['x_post_status'], $allowed_x_post_statuses, true )
            ) {
                update_post_meta(
                    $post_id,
                    'x_post_status',
                    sanitize_text_field( $_POST['x_post_status'] )
                );
            }

            if ( isset( $_POST['memo'] ) ) {
                update_post_meta(
                    $post_id,
                    'memo',
                    sanitize_textarea_field( $_POST['memo'] )
                );
            }

            $message = 'NEWS候補を更新しました。';

        } else {
            $message = '更新できませんでした。権限または確認キーを確認してください。';
        }
    }

    $args = array(
        'post_type'      => 'apice_news_candidate',
        'post_status'    => array( 'publish', 'draft', 'pending', 'private' ),
        'posts_per_page' => 50,
        'orderby'        => 'date',
        'order'          => 'DESC',
    );

    $news_query = new WP_Query( $args );

    ob_start();
    ?>

    <div class="apice-news-admin-wrap">

        <style>
            .apice-news-admin-wrap {
                margin: 24px 0;
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans JP", sans-serif;
            }

            .apice-news-admin-title {
                font-size: 24px;
                font-weight: 800;
                margin: 0 0 8px 0;
                color: #111827;
            }

            .apice-news-admin-lead {
                margin: 0 0 20px 0;
                color: #4b5563;
                line-height: 1.8;
            }

            .apice-news-admin-message {
                padding: 12px 14px;
                margin: 0 0 18px 0;
                border-radius: 10px;
                background: #ecfdf5;
                border: 1px solid #bbf7d0;
                color: #166534;
                font-weight: 700;
            }

            .apice-news-admin-summary {
                display: flex;
                flex-wrap: wrap;
                gap: 10px;
                margin: 0 0 18px 0;
            }

            .apice-news-admin-badge {
                display: inline-flex;
                align-items: center;
                gap: 6px;
                padding: 7px 12px;
                border-radius: 999px;
                background: #f3f4f6;
                color: #374151;
                font-size: 13px;
                font-weight: 700;
            }

            .apice-news-card {
                border: 1px solid #e5e7eb;
                border-radius: 16px;
                background: #ffffff;
                box-shadow: 0 5px 16px rgba(0,0,0,0.05);
                margin: 0 0 18px 0;
                overflow: hidden;
            }

            .apice-news-card-header {
                padding: 16px 18px;
                background: #f9fafb;
                border-bottom: 1px solid #e5e7eb;
            }

            .apice-news-card-title {
                font-size: 17px;
                font-weight: 800;
                color: #111827;
                line-height: 1.6;
                margin: 0 0 4px 0;
            }

            .apice-news-card-meta {
                font-size: 12px;
                color: #6b7280;
            }

            .apice-news-card-body {
                padding: 18px;
            }

            .apice-news-form-grid {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 16px;
            }

            .apice-news-form-field {
                margin: 0 0 14px 0;
            }

            .apice-news-form-field-full {
                grid-column: 1 / -1;
            }

            .apice-news-form-field label {
                display: block;
                font-size: 13px;
                font-weight: 800;
                color: #374151;
                margin: 0 0 6px 0;
            }

            .apice-news-form-field input[type="text"],
            .apice-news-form-field select,
            .apice-news-form-field textarea {
                width: 100%;
                max-width: 100%;
                padding: 8px 10px;
                border: 1px solid #d1d5db;
                border-radius: 8px;
                background: #ffffff;
                font-size: 14px;
                box-sizing: border-box;
            }

            .apice-news-form-field textarea {
                min-height: 90px;
                line-height: 1.6;
            }

            .apice-news-readonly {
                padding: 8px 10px;
                background: #f9fafb;
                border: 1px solid #e5e7eb;
                border-radius: 8px;
                color: #374151;
                font-size: 14px;
                line-height: 1.6;
            }

            .apice-news-actions {
                display: flex;
                flex-wrap: wrap;
                align-items: center;
                gap: 12px;
                margin-top: 10px;
                padding-top: 14px;
                border-top: 1px solid #e5e7eb;
            }

            .apice-news-save-button {
                appearance: none;
                border: none;
                border-radius: 999px;
                padding: 10px 18px;
                background: #2563eb;
                color: #ffffff;
                font-weight: 800;
                cursor: pointer;
            }

            .apice-news-save-button:hover {
                background: #1d4ed8;
            }

            .apice-news-admin-link {
                display: inline-block;
                color: #2563eb;
                font-weight: 700;
                text-decoration: none;
            }

            .apice-news-admin-link:hover {
                text-decoration: underline;
            }

            .apice-news-checkbox-label {
                display: inline-flex !important;
                align-items: center;
                gap: 8px;
                font-weight: 700 !important;
            }

            .apice-news-empty {
                padding: 18px;
                border: 1px solid #e5e7eb;
                border-radius: 10px;
                background: #fafafa;
                color: #4b5563;
            }

            @media (max-width: 768px) {
                .apice-news-form-grid {
                    grid-template-columns: 1fr;
                }
            }
        </style>

        <h2 class="apice-news-admin-title">NEWS候補管理</h2>

        <p class="apice-news-admin-lead">
            登録済みのNEWS候補を確認し、この画面からNEWS表示文、表示先NEWS、表示フラグ、承認ステータス、X投稿ステータス、メモを更新できます。
            元記事URLやカテゴリなどを含めて大きく修正する場合は、ダッシュボード側のNEWS候補編集画面も利用できます。
        </p>

        <?php if ( ! empty( $message ) ) : ?>
            <div class="apice-news-admin-message">
                <?php echo esc_html( $message ); ?>
            </div>
        <?php endif; ?>

        <div class="apice-news-admin-summary">
            <span class="apice-news-admin-badge">表示件数:<?php echo esc_html( $news_query->post_count ); ?>件</span>
            <span class="apice-news-admin-badge">固定ページ側編集UI:有効</span>
        </div>

        <?php if ( $news_query->have_posts() ) : ?>

            <?php while ( $news_query->have_posts() ) : ?>
                <?php
                $news_query->the_post();

                $post_id = get_the_ID();

                $source_url       = get_post_meta( $post_id, 'source_url', true );
                $source_category  = get_post_meta( $post_id, 'source_category', true );
                $news_text        = get_post_meta( $post_id, 'news_text', true );
                $news_target      = get_post_meta( $post_id, 'news_target', true );
                $display_flag     = get_post_meta( $post_id, 'display_flag', true );
                $approval_status  = get_post_meta( $post_id, 'approval_status', true );
                $x_post_status    = get_post_meta( $post_id, 'x_post_status', true );
                $memo             = get_post_meta( $post_id, 'memo', true );

                if ( $approval_status === '' ) {
                    $approval_status = '未確認';
                }

                if ( $x_post_status === '' ) {
                    $x_post_status = '未投稿';
                }

                $edit_link = get_edit_post_link( $post_id );
                ?>

                <div class="apice-news-card">

                    <div class="apice-news-card-header">
                        <div class="apice-news-card-title">
                            <?php echo esc_html( get_the_title() ); ?>
                        </div>
                        <div class="apice-news-card-meta">
                            登録日:<?php echo esc_html( get_the_date( 'Y/m/d H:i' ) ); ?> 
                            ID:<?php echo esc_html( $post_id ); ?>
                        </div>
                    </div>

                    <div class="apice-news-card-body">

                        <form method="post">

                            <input type="hidden" name="apice_news_admin_action" value="update_news_candidate">
                            <input type="hidden" name="apice_news_post_id" value="<?php echo esc_attr( $post_id ); ?>">
                            <?php wp_nonce_field( 'apice_news_admin_update_' . $post_id, 'apice_news_admin_nonce' ); ?>

                            <div class="apice-news-form-grid">

                                <div class="apice-news-form-field">
                                    <label>元記事URL</label>
                                    <div class="apice-news-readonly">
                                        <?php if ( ! empty( $source_url ) ) : ?>
                                            <a class="apice-news-admin-link" href="<?php echo esc_url( $source_url ); ?>" target="_blank" rel="noopener">
                                                元記事を開く
                                            </a>
                                        <?php else : ?>
                                            URL未設定
                                        <?php endif; ?>
                                    </div>
                                </div>

                                <div class="apice-news-form-field">
                                    <label>カテゴリ</label>
                                    <div class="apice-news-readonly">
                                        <?php echo esc_html( $source_category !== '' ? $source_category : '未設定' ); ?>
                                    </div>
                                </div>

                                <div class="apice-news-form-field apice-news-form-field-full">
                                    <label for="news_text_<?php echo esc_attr( $post_id ); ?>">NEWS表示文</label>
                                    <textarea id="news_text_<?php echo esc_attr( $post_id ); ?>" name="news_text"><?php echo esc_textarea( $news_text ); ?></textarea>
                                </div>

                                <div class="apice-news-form-field">
                                    <label for="news_target_<?php echo esc_attr( $post_id ); ?>">表示先NEWS</label>
                                    <select id="news_target_<?php echo esc_attr( $post_id ); ?>" name="news_target">
                                        <option value="" <?php selected( $news_target, '' ); ?>>選択してください</option>
                                        <option value="TECN NEWS" <?php selected( $news_target, 'TECN NEWS' ); ?>>TECN NEWS</option>
                                        <option value="ダイソーNEWS" <?php selected( $news_target, 'ダイソーNEWS' ); ?>>ダイソーNEWS</option>
                                        <option value="どこの国NEWS" <?php selected( $news_target, 'どこの国NEWS' ); ?>>どこの国NEWS</option>
                                        <option value="LDAC / Bluetooth NEWS" <?php selected( $news_target, 'LDAC / Bluetooth NEWS' ); ?>>LDAC / Bluetooth NEWS</option>
                                        <option value="在庫管理 / DX NEWS" <?php selected( $news_target, '在庫管理 / DX NEWS' ); ?>>在庫管理 / DX NEWS</option>
                                        <option value="TECNおすすめ" <?php selected( $news_target, 'TECNおすすめ' ); ?>>TECNおすすめ</option>
                                        <option value="非表示" <?php selected( $news_target, '非表示' ); ?>>非表示</option>
                                    </select>
                                </div>

                                <div class="apice-news-form-field">
                                    <label for="approval_status_<?php echo esc_attr( $post_id ); ?>">承認ステータス</label>
                                    <select id="approval_status_<?php echo esc_attr( $post_id ); ?>" name="approval_status">
                                        <option value="未確認" <?php selected( $approval_status, '未確認' ); ?>>未確認</option>
                                        <option value="修正中" <?php selected( $approval_status, '修正中' ); ?>>修正中</option>
                                        <option value="承認済み" <?php selected( $approval_status, '承認済み' ); ?>>承認済み</option>
                                        <option value="非表示" <?php selected( $approval_status, '非表示' ); ?>>非表示</option>
                                    </select>
                                </div>

                                <div class="apice-news-form-field">
                                    <label class="apice-news-checkbox-label">
                                        <input type="checkbox" name="display_flag" value="1" <?php checked( $display_flag, '1' ); ?>>
                                        表示対象にする
                                    </label>
                                </div>

                                <div class="apice-news-form-field">
                                    <label for="x_post_status_<?php echo esc_attr( $post_id ); ?>">X投稿ステータス</label>
                                    <select id="x_post_status_<?php echo esc_attr( $post_id ); ?>" name="x_post_status">
                                        <option value="未投稿" <?php selected( $x_post_status, '未投稿' ); ?>>未投稿</option>
                                        <option value="投稿済み" <?php selected( $x_post_status, '投稿済み' ); ?>>投稿済み</option>
                                        <option value="投稿しない" <?php selected( $x_post_status, '投稿しない' ); ?>>投稿しない</option>
                                    </select>
                                </div>

                                <div class="apice-news-form-field apice-news-form-field-full">
                                    <label for="memo_<?php echo esc_attr( $post_id ); ?>">メモ</label>
                                    <textarea id="memo_<?php echo esc_attr( $post_id ); ?>" name="memo"><?php echo esc_textarea( $memo ); ?></textarea>
                                </div>

                            </div>

                            <div class="apice-news-actions">
                                <button type="submit" class="apice-news-save-button">このNEWS候補を保存</button>

                                <?php if ( $edit_link ) : ?>
                                    <a class="apice-news-admin-link" href="<?php echo esc_url( $edit_link ); ?>">
                                        ダッシュボードで詳細編集
                                    </a>
                                <?php endif; ?>
                            </div>

                        </form>

                    </div>
                </div>

            <?php endwhile; ?>

        <?php else : ?>

            <div class="apice-news-empty">
                NEWS候補はまだ登録されていません。WordPress管理画面の「NEWS候補 > 新規追加」から登録してください。
            </div>

        <?php endif; ?>

    </div>

    <?php
    wp_reset_postdata();

    return ob_get_clean();
}

add_shortcode( 'apice_news_admin', 'apice_news_admin_shortcode' );

H2-8 コードのポイント

第6回のコードでは、固定ページ側からNEWS候補を更新するために、フォーム送信処理を追加しています。

まず、フォームから送信されたかどうかを確認します。

apice_news_admin_action という値が update_news_candidate になっている場合、固定ページ側からNEWS候補を更新しようとしていると判断します。

次に、apice_news_post_id から更新対象のNEWS候補IDを取得します。

そのIDが apice_news_candidate の投稿タイプであることを確認します。

さらに、現在のユーザーに、そのNEWS候補を編集できる権限があるか確認します。

そして、nonceを確認します。

nonceは、WordPressでフォーム送信時の安全性を高めるための仕組みです。

今回のコードでは、NEWS候補ごとにnonceを発行し、保存時に正しいnonceかどうかを確認しています。

これにより、意図しない外部からの更新を防ぎます。

更新処理では、選択肢を許可リストで確認しています。

たとえば、表示先NEWSは、あらかじめ許可した値だけを保存します。

TECN NEWS。

ダイソーNEWS。

どこの国NEWS。

LDAC / Bluetooth NEWS。

在庫管理 / DX NEWS。

TECNおすすめ。

非表示。

これ以外の値は保存しません。

承認ステータスも同様です。

未確認。

修正中。

承認済み。

非表示。

X投稿ステータスも、未投稿、投稿済み、投稿しないの中から保存します。

自由入力欄であるNEWS表示文とメモは、sanitize_textarea_field() を使って安全に保存します。

表示フラグは、チェックボックスがONなら1、OFFなら0として保存します。

このように、固定ページ側から保存できるようにしながらも、ログイン確認、権限確認、nonce確認、入力値の整理を行っています。

H2-9 固定ページ側で動作確認する

コードを差し替えたら、固定ページ「TECN NEWS候補管理」を開きます。

第5回の一覧テーブルではなく、NEWS候補ごとのカードが表示されていれば、第6回版に切り替わっています。

各カードには、NEWS候補のタイトル、登録日、ID、元記事URL、カテゴリ、NEWS表示文、表示先NEWS、承認ステータス、表示フラグ、X投稿ステータス、メモ、保存ボタンが表示されます。

まずはテスト用のNEWS候補で確認します。

NEWS表示文を少し変更します。

表示先NEWSを変更します。

表示対象にするチェックをONまたはOFFにします。

承認ステータスを承認済みにします。

X投稿ステータスを投稿済みにします。

メモを追加します。

その後、「このNEWS候補を保存」ボタンを押します。

画面上部に、

NEWS候補を更新しました。

と表示されれば、保存処理は成功です。

さらに、ページを再読み込みしても変更した値が残っていれば、固定ページ側からの更新が正しく保存されています。

H2-10 ダッシュボード側にも反映されることを確認する

固定ページ側で保存した内容は、NEWS候補のカスタムフィールドに保存されています。

そのため、ダッシュボード側のNEWS候補編集画面でも同じ値を確認できます。

固定ページ側でNEWS表示文や承認ステータスを変更したあと、WordPress管理画面の、

NEWS候補 > NEWS候補一覧

を開きます。

該当するNEWS候補を編集します。

第4回で作成した「NEWS候補 詳細情報」の入力欄を確認します。

固定ページ側で変更したNEWS表示文、表示先NEWS、表示フラグ、承認ステータス、X投稿ステータス、メモが反映されていれば成功です。

これにより、次の2つの管理ルートが成立します。

WordPress操作に慣れている人は、ダッシュボード側で編集できます。

NEWS担当者は、固定ページ側の専用UIで編集・承認できます。

どちらから編集しても、同じNEWS候補データを更新します。

この状態になると、TECN NEWS候補管理 V1は、実務運用にかなり近づきます。

H2-11 現在の固定ページUIの注意点

第6回の固定ページUIは、初版としては分かりやすい構成です。

ただし、現在の方式では、取得したNEWS候補をすべてカード形式で表示します。

たとえば、NEWS候補が10件あれば、10件分の編集カードが表示されます。

20件あれば、20件分の編集カードが表示されます。

そのため、NEWS候補の件数が増えてくると、画面が長くなる可能性があります。

ただし、初版では大きな問題ではありません。

第7回以降で作るバッチ処理では、対象を絞ってNEWS候補に取り込む予定です。

たとえば、直近7日または直近30日の公開済み記事だけを対象にする。

通常投稿だけを対象にする。

すでにNEWS候補化されている記事は除外する。

最大件数を決める。

このようにすれば、固定ページ側に表示されるNEWS候補が極端に増えすぎることを避けられます。

また、運用しながら必要になれば、次のような改善もできます。

未確認だけ表示する。

表示先NEWSで絞り込む。

承認済みを非表示にする。

一覧から1件を選んで詳細編集する方式にする。

保存後に一覧上部へ戻る。

一括承認ボタンを付ける。

初版では、まず固定ページ側で編集・承認・保存できることを優先します。

その後、実際の運用を見ながらブラッシュアップしていくのがよいです。

H2-12 第6回でできるようになったこと

第6回では、固定ページ側でNEWS候補を編集・承認できる担当者UIを作りました。

今回できるようになったことを整理します。

固定ページ「TECN NEWS候補管理」に、NEWS候補ごとの編集カードを表示できるようになりました。

NEWS表示文を固定ページ側から編集できるようになりました。

表示先NEWSを固定ページ側から変更できるようになりました。

表示フラグを固定ページ側からON/OFFできるようになりました。

承認ステータスを固定ページ側から変更できるようになりました。

X投稿ステータスを固定ページ側から変更できるようになりました。

メモを固定ページ側から編集できるようになりました。

保存ボタンで更新できるようになりました。

保存後に更新メッセージを表示できるようになりました。

必要に応じて、ダッシュボード側の詳細編集画面へ移動できるようになりました。

これにより、NEWS担当者は、WordPressダッシュボード全体を細かく操作しなくても、固定ページ側のNEWS管理画面で日常的な確認・承認作業を行えるようになりました。

一方で、ダッシュボード側の編集機能も残しています。

そのため、詳細な修正や管理者による確認はダッシュボード側で行い、日常の承認作業は固定ページ側で行う、という使い分けができます。

H2-13 第6回でまだやらないこと

第6回では、固定ページ側でNEWS候補を編集・承認できるようにしました。

ただし、まだ自動取り込みや自動表示までは行っていません。

まず、新規投稿記事を自動的にNEWS候補へ登録する処理は、まだ作っていません。

現時点では、NEWS候補は手動で登録するか、ダッシュボード側から追加する必要があります。

次に、承認済みNEWSを実際の記事本文へ自動差し込みする処理も、まだ作っていません。

たとえば、

で囲んだコメントブロック内に最新NEWSを差し込む処理は、次の段階です。

また、TECN全体NEWS、在庫管理NEWS、どこの国NEWS、LDAC / Bluetooth NEWSなど、表示先NEWSごとに最新7件を表示するショートコードも、まだ第6回では作っていません。

第6回の目的は、あくまで担当者が固定ページ側でNEWS候補を確認・編集・承認できる状態にすることです。

ここまでできたことで、次に新規投稿記事を自動的にNEWS候補へ取り込む準備が整いました。

H2-14 次回は新規投稿記事をNEWS候補へ自動登録する

次回は、新規投稿記事をNEWS候補へ自動登録する処理を作ります。

TECNに新しい記事を投稿したら、その記事情報をNEWS候補に取り込む仕組みです。

たとえば、毎日1回、公開済みの新規投稿を確認します。

まだNEWS候補に登録されていない記事だけを抽出します。

その記事のタイトル、URL、カテゴリ、公開日などを取得します。

そして、NEWS候補として自動登録します。

このとき、承認ステータスは未確認にします。

表示フラグはOFFにしておきます。

表示先NEWSは、カテゴリから仮設定できるようにします。

たとえば、在庫管理カテゴリの記事なら、在庫管理 / DX NEWS。

どこの国カテゴリの記事なら、どこの国NEWS。

LDACやBluetooth関連の記事なら、LDAC / Bluetooth NEWS。

このように仮設定しておくと、担当者は固定ページ側で確認し、必要に応じて修正・承認するだけで済みます。

この処理は、WordPress内部のWP-Cronを使って1日1回実行できます。

WP-Cronは、WordPressに用意されている定期実行の仕組みです。

GASの時間主導トリガーと完全に同じではありませんが、考え方は近いです。

WordPressにアクセスがあったタイミングで、予定時刻を過ぎた処理があれば実行されます。

TECNのように月3万PV前後のアクセスがあるサイトで、1日1回起動すればよい処理であれば、初版ではWP-Cronで十分です。

また、動作確認用として、固定ページ側に「新規投稿をNEWS候補に取り込む」手動実行ボタンを付けると便利です。

通常運用ではWP-Cronで1日1回自動実行。

確認や緊急時には固定ページ側の手動ボタンで実行。

この形にすると、かなり実務的になります。

H2-15 第6回のまとめ

第6回では、固定ページ側でNEWS候補を編集・承認できる担当者UIを作りました。

第5回までは、固定ページ側ではNEWS候補一覧を確認するだけでした。

第6回では、固定ページ側からNEWS表示文、表示先NEWS、表示フラグ、承認ステータス、X投稿ステータス、メモを編集・保存できるようにしました。

これにより、担当者はWordPressダッシュボード全体を細かく操作しなくても、専用のNEWS候補管理ページだけで日々の確認・承認作業を進められます。

また、ダッシュボード側の編集機能も残しているため、WordPressに慣れている管理者は従来通り詳細編集できます。

固定ページ側の専用UIと、ダッシュボード側の管理機能。

この2つを併用できる形にしたことで、TECN NEWS候補管理 V1はかなり実務的な管理システムに近づきました。

現時点では、固定ページ側にNEWS候補をすべてカード形式で表示しています。

件数が増えてきた場合は、一覧から1件を選ぶ方式や、未確認だけを表示する方式に改善できます。

ただし、初版としては、まず固定ページ側で編集・承認・保存できることが重要です。

次回は、新規投稿記事を自動的にNEWS候補へ取り込むバッチ処理を作ります。

WordPressのWP-Cronを使い、1日1回、新規投稿記事を確認し、まだNEWS候補になっていない記事をNEWS候補として登録する仕組みへ進みます。

DXジュン プロフィール写真

筆者プロフィール|DXジュン(Apice Technology 代表)

「tecn」を運営している DXジュン です。
Apice Technology株式会社の代表として、20年以上にわたり Web制作・業務システム開発・業務改善支援に携わっています。

普段は中小企業向けに、在庫管理・予約管理・受発注管理など、業務を効率化するためのシステム開発やDX支援を行っています。

tecnでは、業務改善のヒントやWebシステムの仕組み、「技術が暮らしを少し便利で楽しくする」をテーマに、現場目線で分かりやすく情報発信しています。

最近は在庫管理のDX化に力を入れており、SKU・JAN・棚卸・バーコード運用など、現場で役立つ実践的なノウハウを発信しています。

また、小規模事業者向けの無料ツール 「アピスminiシリーズ」も公開しています。

業務改善に役立つ無料ツールや在庫管理システムを公開しています

無料在庫管理システムを見る アピスminiシリーズを見る

🔗 Apice Technology(会社HP)
🔗 音を楽しむ【耳スタ】
🔗 在庫管理システムの機能紹介

記事が皆さまの仕事や日常のヒントになれば幸いです。

AI活用 生産性アップ・便利 WordPress 未分類
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
  • WordPressでLPをAIと一緒に作る具体的なやり方|素人でもSWELLでデザイナー不要のランディングページ公開まで到達する手順

関連記事

  • WordPressでLPをAIと一緒に作る具体的なやり方|素人でもSWELLでデザイナー不要のランディングページ公開まで到達する手順
    2026年7月4日
  • SWELLで特定の固定ページだけLP化する方法|WordPressでグローバルメニュー・目次・サイドバーをページ単位で非表示にする手順 | AI 丸投げ
    2026年7月4日
  • 問い合わせmini V1.0 運用マニュアル|自動返信・下書き確認・要確認で問い合わせ対応を効率化する
    2026年7月3日
  • Cursor AIは無料で使える?料金プランの違いと無料版でできることを解説
    Cursor AIは無料で使える?料金プランの違いと無料版でできることを解説
    2026年7月2日
  • 問い合わせmini V1.0 WEB UI 画面  モックアップ|問い合わせ対応を自動化 無料TOOL 
    2026年7月2日
  • 問い合わせmini V1.0 WEB UI 仕様
    2026年7月2日
  • 問い合わせmini V1.0 シート構成・カラム定義
    2026年7月2日
  • 問い合わせmini V1.0 仕様書
    2026年7月2日

コメント

コメントする コメントをキャンセル

アピス在庫管理システム
アピス在庫管理導入講座

カテゴリー

  • AIに対してのプロンプト
  • AI活用
  • Bluetoothコーデック基礎
  • Canva
  • Chrome ブラウザー
  • Dropbox
  • ECサイト
  • GAS・JavaScript
  • GAS等仕様書・設定・操作手順
  • HTML・CSS
  • IT TOOL一覧
  • IT導入補助金
  • LDAC-Bluetooth
  • mini:GAS仕様 設定手順等
  • OBS-Studio
  • PC・スマホ便利技
  • PC関連
  • SEO・ブログ運営
  • Shopify
  • SKU・JAN・商品コード
  • STEPmini
  • WEB制作・開発
  • Windows
  • WordPress
  • ZOOM
  • アクセス解析
  • アピスmini・IT-Tool
  • アピス在庫管理
  • イヤホン
  • エクセル・ワード
  • お知らせ
  • スポーツ・アウトドア用品
  • セキュリティ
  • セルフオーダーシステム
  • どこの国・ブランド
  • ネットで販売
  • バーコード
  • ビジネス支援ツール
  • ブログ
  • ブログ収益化
  • ブログ運営
  • プロンプト
  • レッスン施術サービス
  • 会議室予約
  • 充電器・バッテリー
  • 動画
  • 受発注管理
  • 問い合わせmini
  • 回線・インターネット
  • 在庫管理
  • 学習・挑戦記
  • 家事代行予約
  • 家電ガジェット
  • 技術MEMO
  • 接続&音質トラブル
  • 政治・経済
  • 時事・経済・グローバル
  • 未分類
  • 業務効率化
  • 生産性アップ・便利
  • 画像生成
  • 画像生成AI
  • 端末別設定
  • 美容院予約
  • 見積
  • 見積管理
  • 請求管理
  • 電気自動車(EV)

最近の投稿

  • WordPressでNEWS配信システムを作る実践講座|第6回:固定ページ内でNEWS候補を編集・承認できる担当者UIを作る
  • WordPressでLPをAIと一緒に作る具体的なやり方|素人でもSWELLでデザイナー不要のランディングページ公開まで到達する手順
  • SWELLで特定の固定ページだけLP化する方法|WordPressでグローバルメニュー・目次・サイドバーをページ単位で非表示にする手順 | AI 丸投げ
  • 問い合わせmini V1.0 運用マニュアル|自動返信・下書き確認・要確認で問い合わせ対応を効率化する
  • Canva マジック消しゴムの使い方を徹底解説|写真の不要なものを消す方法

アーカイブ

  • 2026年7月
  • 2026年6月
  • 2026年5月
  • 2026年4月
  • 2026年3月
  • 2026年2月
  • 2026年1月
  • 2025年12月
  • 2025年11月
  • 2025年10月
  • 2025年9月
  • 2025年8月
  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月

APICE

問い合わせ

アピステクノロジー|tec note

 〒224-0032 神奈川県横浜市都筑区茅ケ崎中央42−21 第2佐藤ビル 203

電話番号: 045-532-4480

お問い合せ

© tecn.

目次