WP_Query タブ

<!-- タブボタン -->
<div class="tab-panel-a">

<?php
$query = new WP_Query(
array(
'post_type' => 'info-post',
'posts_per_page' => -1,
'orderby'        => 'date',
'order'          => 'ASC',
)
);
?>
<?php
if ($query->have_posts()) :
$i = 0;
?>
<ul class="tab-group">
<?php while ($query->have_posts()) : $query->the_post();
$i++;
$tab_class = ($i === 1) ? 'is-active' : '';
?>
<li class="tab <?php echo esc_attr($tab_class); ?>"><?php the_title(); ?></li>

<?php endwhile; ?>

</ul>
<?php endif;
wp_reset_postdata(); ?>
<!-- //タブボタン -->

<!-- パネル -->
<?php
$query = new WP_Query(
array(
'post_type' => 'info-post',
'posts_per_page' => -1,
'orderby'        => 'date',
'order'          => 'ASC',
)
);
?>
<?php
if ($query->have_posts()) :
$i = 0;
?>

<div class="panel-group">

<?php while ($query->have_posts()) : $query->the_post();
$i++;
$panel_class = ($i === 1) ? 'is-show' : '';
?>


<div class="panel <?php echo esc_attr($panel_class); ?>">
<!--タブ1内容-->

<?php if (have_rows('info_pdf')) : ?>
<?php while (have_rows('info_pdf')) : the_row(); ?>
  <?php $info_file = get_sub_field('info_file'); ?>
  <?php if ($info_file) : ?>

    <li class="">
      <a target="_blank" href="<?php echo esc_url($info_file['url']); ?>"><?php echo esc_html($info_file['caption']); ?></a>

    </li>
  <?php endif; ?>
<?php endwhile; ?>
<?php endif; ?>

</div>


<?php endwhile; ?>
</div>
<?php endif;
wp_reset_postdata(); ?>

</div><!--tab-panel-a-->```

カスタムポスト一覧 管理画面の並び順変更

/*-------------------------------------------*/
/* カスタムポスト menu-post 管理画面の並び順変更 */
/*-------------------------------------------*/
add_action('pre_get_posts', 'menu_post_admin_order');
function menu_post_admin_order($query)
{

  if (
    is_admin()
    && $query->is_main_query()
    && $query->get('post_type') === 'menu-post'
  ) {

    // 並び順を昇順に
    $query->set('order', 'ASC');

    // 並び替え基準(用途に応じて)
    // $query->set('orderby', 'menu_order');
    // $query->set('orderby', 'title');
    $query->set('orderby', 'date');
  }
}

メッセージ表示

add_action('admin_notices', function () {
  $screen = function_exists('get_current_screen') ? get_current_screen() : null;
  if (!$screen) return;

  if ($screen->base !== 'edit' || $screen->post_type !== 'info-post') return;

  echo '<div class="notice notice-info"><p>'
    . esc_html__('【注意】公開日を更新したら、表示順も変わります。公開ボタンを押して保存してください。', 'textdomain')
    . '</p></div>';
});```

カスタムタクソノミー item_cat 一覧に画像を追加

/*----------------------------------------
  カスタムタクソノミー item_cat 一覧に画像を追加
----------------------------------------*/

// 1. カラム追加
add_filter('manage_edit-item_cat_columns', 'add_item_cat_image_column');
function add_item_cat_image_column($columns) {
    $new = [];

    // 表示したいカラム名
    $new['item_img'] = '画像';

    // 画像を最初に入れる場合の並び替え
    return array_slice($columns, 0, 1, true)
         + $new
         + array_slice($columns, 1, null, true);
}

// 2. カラム内容の出力
add_filter('manage_item_cat_custom_column', 'add_item_cat_image_column_content', 10, 3);
function add_item_cat_image_column_content($content, $column_name, $term_id) {

    if ($column_name === 'item_img') {

        // ACFで登録した画像(フィールド名 menu_img の場合)
        $image = get_field('menu_img', 'item_cat_' . $term_id);

        if ($image) {
            $url = esc_url($image['url']);
            $content = '<img src="' . $url . '" style="width:60px;height:auto;border-radius:4px;">';
        } else {
            $content = '—';
        }
    }

    return $content;
}

カスタム投稿タイプ「○○-post」にタクソノミー「○○_cat」を表示

/* --------------------------------------------
 * カスタム投稿タイプ「item-post」にタクソノミー「item_cat」を表示
 * -------------------------------------------- */

// 投稿一覧に列を追加
add_filter('manage_○○-post_posts_columns', 'add_menu_cat_column');
function add_menu_cat_column($columns)
{
  $columns['○○_cat'] = 'カテゴリ';
  return $columns;
}

// 各投稿のタームを表示
add_action('manage_○○-post_posts_custom_column', 'add_menu_cat_column_content', 10, 2);
function add_menu_cat_column_content($column, $post_id)
{
  if ($column === '○○_cat') {
    $terms = get_the_terms($post_id, 'item_cat');
    if (!empty($terms) && !is_wp_error($terms)) {
      $names = wp_list_pluck($terms, 'name');
      echo implode(', ', $names);
    } else {
      echo '—';
    }
  }
}```

wp ページ別css読み込み

functions.php

function defer_specific_css_loading($tag, $handle)
{
  $handles_to_defer = ['destyle', 'font-awesome', 'elementor'];

  if (in_array($handle, $handles_to_defer, true)) {
    $tag = str_replace("media='all'", "media='print' onload=\"this.media='all'\"", $tag);
    $tag = str_replace('media="all"', 'media="print" onload="this.media=\'all\'"', $tag);
  }
  return $tag;
}
add_filter('style_loader_tag', 'defer_specific_css_loading', 10, 2);

function insp_enqueue_styles()
{
  $base_ver = get_field('css_ver', 'option') ?: wp_get_theme()->get('Version');

  // 外部ライブラリCSS
  wp_enqueue_style('destyle', 'https://cdn.jsdelivr.net/npm/destyle.css@3.0.2/destyle.css', [], '3.0.2', 'all');
  wp_enqueue_style('font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css', [], '6.4.0', 'all');
  wp_enqueue_style('swiper', 'https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css', [], '11.0.0', 'all');

  // テーマ内CSS
  $styles = [
    'style'     => 'style-min.css',
    'style-sp'  => 'style-sp-min.css',
    'design'    => 'css/design.css',
    'sp'        => 'css/sp.css',
    'elementor' => 'css/elementor.css',
    'original' => 'css/original.css',
    'before_after' => 'css/page-before_after.css',
    'first' => 'css/page-first.css',
    'menu' => 'css/page-menu.css',
    'commitment' => 'css/page-commitment.css',
    'staff-post' => 'css/post-staff.css',
  ];

  $page_styles = [
    'before_after' => ['before_after'],  // before/afterで読み込む
    'first' => ['first'],  // firstで読み込む
    'menu' => ['menu'],  // menuで読み込む
    'commitment' => ['commitment'],  // commitmentで読み込む
    'staff-post' => ['staff-post-all'],  // staff-postに関わるすべで読み込む
  ];

  foreach ($styles as $handle => $rel_path) {
    // デフォルトは「読み込まない」
    $load = false;

    if (in_array($handle, ['style', 'style-sp', 'design', 'sp', 'elementor', 'original',], true)) {
      $load = true;
    }

    // ページ別読み込み
    if (isset($page_styles[$handle])) {
      foreach ($page_styles[$handle] as $slug) {

        // 固定ページスラッグ
        if (is_page($slug)) {
          $load = true;
          break;
        }

        // --- staff-post のすべてのページ ---
        if ($slug === 'staff-post-all') {

          if (
            is_singular('staff-post') ||                // 詳細
            is_post_type_archive('staff-post') ||       // アーカイブ
            is_tax('staff_cat') ||                      // タクソノミー例
            (is_search() && get_query_var('post_type') === 'staff-post') // 検索
          ) {
            $load = true;
            break;
          }
        }
      }
    }

    // 読み込むべき CSS だけ enqueue
    if ($load) {
      $file_path = get_theme_file_path($rel_path);
      $ver = is_readable($file_path) ? filemtime($file_path) : $base_ver;
      wp_enqueue_style($handle, get_theme_file_uri($rel_path), [], $ver, 'all');
    }
  }
}
add_action('wp_enqueue_scripts', 'insp_enqueue_styles');```

パララックス GSAP(GreenSock Animation Platform)+ ScrollTrigger

html

<div class="parallax-wrap" data-parallax data-y="10%" data-scale="1.2" data-delay="1.2">
  <img src="/path/to/image.jpg" alt="parallax image">
</div>

JS

読み込み

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>

JS

/*===================================================================
パララックス
===================================================================*/

gsap.registerPlugin(ScrollTrigger);

const items = document.querySelectorAll("[data-parallax]"); // data-parallax属性を持つ要素を取得

// 各パララックス要素に対して処理を行う
for (const item of items) {
  const y = item.getAttribute("data-y") ?? "5%"; // itemのdata-y属性を取得。未設定の場合は'5%'をデフォルト値として使用
  const scale = item.getAttribute("data-scale") ?? "1.1"; // itemのdata-scale属性を取得。未設定の場合は'1.1'をデフォルト値として使用
  const delay = parseFloat(item.getAttribute("data-delay")) || 1.5; // itemのdata-delay属性を数値に変換して取得。未設定の場合は'1.5'をデフォルト値として使用
  const img = item.querySelector("img"); // itemの中にあるimg要素を取得

  gsap.set(item, { overflow: "hidden" }); // itemのoverflowをhiddenに設定
  gsap.set(img, { scale: scale }); // imgのscaleに上記で設定した「scale」を適用

  gsap.fromTo(
    // gsap.fromToでアニメーションを設定
    img, // 対象の要素をimgで指定
    {
      y: `-${y}`, // アニメーション開始時のy位置
    },
    {
      y: y, // アニメーション終了時のy位置
      scrollTrigger: {
        // スクロールトリガーを設定
        trigger: item, // itemをトリガーとなる要素として指定
        start: "top bottom", // 要素の上端がビューポートの下端に達したときに開始
        end: "bottom top", // 要素の下端がビューポートの上端に達したときに終了
        scrub: delay, // スクロールに追従してアニメーションを行う(デフォルトでは1秒の遅延)
      },
      ease: "none", // イージング関数を指定しない(線形アニメーション)
    }
  );
}

CSS

.parallax-wrap {
  position: relative;
  overflow: hidden;
  display: block;
}

.parallax-wrap img {
  width: 100%;
  height: auto;
  display: block;
  transform: translateY(0); /* JSに上書きされる前の初期状態 */
}

swiperを一定速度で流れるように

  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
  <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

html

  <div class="swiper">
    <!-- Additional required wrapper -->
    <div class="swiper-wrapper">

      <?php $gallery_urls = get_field('gallery'); ?>
      <?php if ($gallery_urls) :  ?>
        <?php foreach ($gallery_urls as $gallery_url): ?>
          <div class="swiper-slide"><img src="<?php echo esc_url($gallery_url); ?>" /></div>
        <?php endforeach; ?>
      <?php endif; ?>

    </div>

  </div>

JS

// カルーセル
const carousel = new Swiper(".swiper", {
  loop: true,
  slidesPerView: "auto",
  spaceBetween: 30,
  speed: 5000, // 数字を大きくするとゆっくり
  autoplay: {
    delay: 0, // 常に動かす
    disableOnInteraction: false,
    // pauseOnMouseEnter: true // ホバーで止めたいとき
  },
  freeMode: {
    enabled: true,
    momentum: false, // ユーザー操作後の加減速を無効化
  },

  loopAdditionalSlides: 10, // ループ切替の“息継ぎ”軽減
});

SCSS

.swiper{
  padding: 40px 0;
  overflow: hidden;

  .swiper-wrapper {
    transition-timing-function: linear !important; //★重要
  }

  .swiper-slide {
    width: 250px; /* バナー幅は自由に調整 */
    flex-shrink: 0;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    text-align: center;
  }

  .swiper-slide img {
    width: 100%;
    display: block;
  }
}