初めてWordPressテーマを自作してみた。知識が無い素人でも、調べながらやってみる。#3【いろいろな機能を実装する】

目次

Webサイトとして、公開するためのページは前回の#2で作成しました。

より良くするために、今回は様々な機能を作りこんでいきます。

ランキング機能を作りたい

HTML作成時点からイメージしていた、週間ランキングを作りたいです。

どうやらプラグイン等を使えば簡単にランキング機能は作れるようです。検索すれば色々出てきます。しかし、今回は自分の手で作りたいです。プラグインなしで作る方法を検索すると、大体同じ結果が出てきます。そこから勉強して、自分で作ってみます。

まずは真似して作ってみる

以下のサイトを参考。というかググったら、どこも同じ内容の記事ばっかりなので、どの記事でもいいです。記事書いた本人は実装したことあるのかな・・・?なーんかどの記事もコピペっぽい。とりあえず真似る。

https://it-web-life.com/wordpress_popular_articles_no_plugin/

エラー時function.php

HTMLCOPY
//投稿IDに対するアクセス回数を取得する
function getViewCount($postid){
    $key = 'post_views_count';
    $count = get_post_meta($postid, $key, true);
    if(!$count==''){
        return $count;
    }else{
        delete_post_meta($postid, $key);
        add_post_meta($postid, $key, '0');
        return "0";
    }
}

//投稿IDに対するアクセス回数を記録する
function setViewCount($postid) {
    $key = 'post_views_count';
    $count = get_post_meta($postid, $key, true);
    if(!$count==''){
        $count++;
        update_post_meta($postid, $key, $count);
    }else{
        delete_post_meta($postid, $key);
        add_post_meta($postid, $key, '0');
    }
}

真似たが、動いている気配がない・・・。

現状を把握するために、カウントを出してみたが、0回。すべてelseのほうに行っている。つまりカスタムフィールドに値ができていないっぽい。もしくはget_post_metaで値が取れていない。

add_post_metaとget_post_metaの仕様を把握しなければ・・・

いろいろ出力して試してみたら、そもそもカスタムフィールドはちゃんとつくられて、データの中身の0も取得できている。しかし、条件分岐でelseの方に流れている・・・。おそらく条件分岐の設定が悪そうですね。

結論から言うと、条件分岐における「!」の使い方がミスっていました。

!$count===””と記載していて、このcountはカスタムフィールドからの取得結果としています。なので、countが無いならelseになり、カスタムフィールドを作成して0を設定するという処理が走る予定でした。

その書き方ではなく、!($count===”)のように括弧で括ると予定通り動きました。

function.php

HTMLCOPY
/**
 * 共通機能・管理機能
 *
 */


//投稿IDに対するアクセス回数を取得する
function getViewCount($postid){
    $key = 'post_views_count';
   
    $count = get_post_meta($postid, $key, true);
    echo 'getViewCount:count'.$count;
    if(!($count==='')){
        return $count .'view';
    }else{
        delete_post_meta($postid, $key);
        add_post_meta($postid, $key, '0');
        return "0ビュー";
    }
}

//投稿IDに対するアクセス回数を記録する
function setViewCount($postid) {
    $key = 'post_views_count';
    $count = get_post_meta($postid, $key, true);
    if(!($count==='')){
        $count++;
        update_post_meta($postid, $key, $count);
    }else{
        $count = 0;
        delete_post_meta($postid, $key);
        add_post_meta($postid, $key, '0');
    }
}

アクセス数を投稿一覧に表示したい

ランキングの動きが正しいか判断するためにも、アクセス数を把握する必要があります。

毎回、echoで表示してみるのは面倒。

なので、投稿一覧管理画面で各記事のアクセス数が分かるように改修しました。以下のサイトを参考にしてます。

https://takayakondo.com/wordpress-customfield-list/

さらにアクセス数順にソートできるようにもしました。以下のサイトを参考です。

https://into-the-program.com/wordpress-posts-sort-custom-field-value/

function.php

HTMLCOPY
/* ========================================================
管理画面:投稿の投稿一覧にカスタムフィールドの値を表示させる
=========================================================*/
function manage_posts_columns($columns) {
    $columns['post_views_count'] = "アクセス数";
    return $columns;
}
function add_column($column_name, $post_id) {
    if( $column_name == 'post_views_count' ) {
        $stitle = get_post_meta($post_id, 'post_views_count', true);
    }
    if ( isset($stitle) && $stitle ) {
        echo esc_html($stitle);
    } else {
        echo __('None');
    }
}
add_filter( 'manage_posts_columns', 'manage_posts_columns' );
add_action( 'manage_posts_custom_column', 'add_column', 10, 2 );

//カスタムフィールドによるソートを可能にする
function posts_sortable_columns($sortable_column) {
    $sortable_column['post_views_count'] = 'post_views_count';
    return $sortable_column;
}
add_filter('manage_edit-post_sortable_columns', 'posts_sortable_columns');
//カスタム投稿タイプの場合
//add_filter('manage_edit-{post_type}_sortable_columns', 'posts_sortable_columns');

//カスタムフィールドでソートする際のパラメータ
function posts_columns_sort_param($vars){
    if(isset($vars['orderby']) && 'post_views_count' === $vars['orderby'] ) {
        $vars = array_merge(
            $vars,
            array(
                'meta_key' => 'post_views_count',
                'orderby' => 'meta_value_num', //対象が文字列の場合は「meta_value」を指定
            )
        );
    }
    return $vars;
}
add_filter('request', 'posts_columns_sort_param');

ランキングの見た目を整える

機能は作ったので、ランキング表示の見た目を整えていきます。

その前に、ランキングのPHP処理はindex.phpの中に記載されていましたが、各ページで使いたいので共通部品にしています。投稿一覧のcontent.phpと同じくtemplate-partsにしています。popular.phpという名前で作成し、コピペで転記しました。

スマホで見る時を想定した横幅が小さいレイアウトだと、HTMLで作ったデザインと比べて、現状はレイアウトが崩れています。

なぜ崩れるのだろう・・・?とりあえず、色々試して絞り込んでいく。

開発者ツールでコードの違いを見ると、各記事を囲んだaタグあるか無いかだったので、消してみたら元のHTMLのようになった。

つまり、1記事全体をaタグで括るのではなく、各列をごと(画像列、文字列に分けて)に括ると、縦並びではなく、横並びになって、問題解決。

もう一つの問題として、サムネなし時に表示したいNoThumnailsが縦に長くなる。

背景色やテキスト位置は修正できたが、枠自体は変えられない。svgタグで高さが決まっているっぽい。

色々試していく・・・。

svgタグをimgタグに変えたら小さくなった。が、次は背景色が変更できなくなった。

どうやらSVGタグの仕様っぽい。Widthとかの指定をしても、キャンバスという概念があって、オブジェクトは小さくならないらしい。なるほど、よく分からん・・・。

とにかくviewBoxというプロパティを設定して、画像のPXを指定するとその大きさになった。サイズの調整はこれでOK。

次の問題としてviewBoxに1280×720指定すると、文字がメチャクチャ小さくなった

おそらく文字のpxはWebサイト全体の文字サイズと同じだからだと思う。つまり文字は16pxで、画像全体が指定した1280×720になったので、比率として100分の1ぐらいに文字が小さくなったと思われる。

対応としては、画像サイズを256×144まで小さくした。画像なら荒くなりそうなものだが、別に本物の画像があるわけではなく、背景色をつけて文字を表示しているだけなので、拡大縮小の影響はないと判断しました。

また、若干、文字が上にずれてしまう事象も発生しました。上下中央に位置するためのプロパティはdominant-baseline=”central”だったので、それも指定したらイメージ通りになりました。

popular.php

PHPCOPY
<!-- ランキング -->
<?PHP
$args = new WP_Query(
    array(
        'post_type' => 'post', //投稿タイプ
        'posts_per_page' => 3, //表示数
        'meta_key' => 'pv_count', //カスタムフィールド名
        'orderby' => 'meta_value_num', //カスタムフィールドの値
        'order' => 'DESC' //降順で表示する
    )
);
if ( $args->have_posts() ):
?>
<div class="container overflow-hidden mb-4" id="surukoto-rank">
    <div class="row mx-4 pb-3 my-3 border-bottom surukoto-rank-head">
        Weekly Most Popular
    </div>
    <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-2 g-md-4 px-4">
   
    <?php while ( $args->have_posts() ) : $args->the_post(); ?>
        <div class="col-12 col-md-6 col-lg-4">
            <div class="row">
               
                    <div class="col-4 col-md-12 align-self-center">
                        <a href="<?php esc_url(the_permalink()); ?>">
                            <?php if (has_post_thumbnail()):?>
                                <img src="<?php the_post_thumbnail_url(); ?>" class="card-img-top" alt="<?php get_the_title(); ?>" />
                            <?php else: ?>
                                <svg class="card-img-top" viewBox="0 0 256 144">
                                    <rect width="100%" height="100%" fill="#55595c"/>
                                    <text x="50%" y="50%" fill="#eceeef" text-anchor="middle" dominant-baseline="central">no thumbnail</text>
                                </svg>
                            <?php endif; ?>
                        </a>
                    </div>
                    <div class="col-8 col-md-12">
                        <a href="<?php esc_url(the_permalink()); ?>">
                            <span class="surukoto-rank-text"><?php echo get_the_modified_date(); ?></span>
                            <p class="surukoto-rank-title"><?php the_title(); ?></p>
                        </a>
                    </div>
               
            </div>
        </div>
    <?php endwhile; ?>
    </div>
</div>
<?php endif; wp_reset_postdata();?>

週間ランキング機能にする

現状は、ランキングを決めるためのアクセス数カウントが特にリセットもされないので、今は累計になっている。期間が決まったランキングにしたいです。

以下のサイトを参考にして、週間ランキングにします。

https://ikisakianco.com/posts/2016/06/wordpress-noplugin-popular-posts/

主な変更点としては、

カウント機能は1週間として、配列数字をWにする。0~6が曜日ごとに入るはず

sum_countは配列の合計。週間のアクセス数をカウントする。

リセット機能は基本的には同じ。Wにするだけです。

クローン機能は毎日、カウント累計が8日目になった値を消すように、デイリーにしました。

うまく動くかは1週間経たないと分からないので、とりあえずはこれで。ゆっくり検証して、後々作りこんでいきます。

function.php

PHPCOPY
//投稿IDに対するアクセス回数を取得する
//アクセス数をカウントする
function set_post_views() {
    $postID = get_the_ID();
    $num = (int)date_i18n('w'); // 現在時間で番号取得
    $key = 'pv_count';
    $count_key = '_pv_count';
    $count_array = get_post_meta( $postID, $count_key, true );
    //$sum_count = get_post_meta( $postID, $key, true );

    if( !is_array($count_array) ) { //配列ではない
        $count_array = array();
        $count_array[$num] = 1;
    } else { //配列である
        if ( isset( $count_array[$num] ) ) { //カウント配列[n]が存在する
            $count_array[$num] += 1;
        } else { //カウント配列[n]が存在しない
            $count_array[$num] = 1;
        }
    }
    //アクセス数を更新する
    update_post_meta( $postID, $count_key, $count_array );
    update_post_meta( $postID, $key, array_sum($count_array) );
}
 
//アクセス数をリセットする
function reset_post_views() {
    $num = (int)date_i18n('w');
    $key = 'pv_count';
    $reset_key = '_pv_count';

    $args = array(
    'posts_per_page'   => -1,
    'post_type' => 'post',
    'post_status'=>'publish',
    'meta_key' => $reset_key,
    );

    $reset_posts = get_posts($args);
    if($reset_posts):
        foreach($reset_posts as $reset_post):
            $postID = $reset_post->ID;
            $count_array = get_post_meta( $postID , $reset_key, true );

            if ( isset( $count_array[$num] ) ) { //カウント配列[n]が存在する
            $count_array[$num] = 0;
            }

            //アクセス数をリセットする
            update_post_meta( $postID, $reset_key, $count_array );
            update_post_meta( $postID, $key, array_sum( $count_array ) );
        endforeach;
    endif;
}
//リセット関数を実行するアクションフックを追加
add_action( 'set_day_event', 'reset_post_views' );

//実行間隔の追加
function my_interval( $schedules ) {
    // 1時間ごとを追加
    $schedules['day'] = array(
        'interval' => 86400,
        'display' => 'every day'
    );
    return $schedules;
}
add_filter( 'cron_schedules', 'my_interval' );

//アクションフックを定期的に実行するスケジュールイベントの追加
function my_activation() {
    if ( ! wp_next_scheduled( 'set_day_event' ) ) {
    wp_schedule_event( strtotime( 'tomorrow' ), 'day', 'set_day_event' );
    }
}
add_action('wp', 'my_activation');
 
  //ボットの判別
function isBot() {
    $bot_list = array (
        'Googlebot',
        'Yahoo! Slurp',
        'Mediapartners-Google',
        'msnbot',
        'bingbot',
        'MJ12bot',
        'Ezooms',
        'pirst; MSIE 8.0;',
        'Google Web Preview',
        'ia_archiver',
        'Sogou web spider',
        'Googlebot-Mobile',
        'AhrefsBot',
        'YandexBot',
        'Purebot',
        'Baiduspider',
        'UnwindFetchor',
        'TweetmemeBot',
        'MetaURI',
        'PaperLiBot',
        'Showyoubot',
        'JS-Kit',
        'PostRank',
        'Crowsnest',
        'PycURL',
        'bitlybot',
        'Hatena',
        'facebookexternalhit',
        'NINJA bot',
        'YahooCacheSystem',
        'NHN Corp.',
        'Steeler',
        'DoCoMo',
    );
    $is_bot = false;
    foreach ($bot_list as $bot) {
        if (stripos($_SERVER['HTTP_USER_AGENT'], $bot) !== false) {
            $is_bot = true;
            break;
        }
    }
    return $is_bot;
}

プロフィール機能を作りたい

プロフィールはトップページのどこかに書こうかと思っていましたが、後々に使いまわせるようにtemplate-partsで作成しようと思います。profile.phpで作ります。

プロフィールといえば、人物のアイコンや写真を表示するイメージがあるので、そこから手を付けます。WordPressにはプロフィール機能が管理画面に用意されていて、そこから画像やプロフィール文言を登録していたと思います。

なのでいつも通り、画像を登録しようとしたら・・・登録する機能がありません

どうやらGravatarという機能を使わないとダメらしい。これはWordpress開発元が提供しているようで、Wordpressへのアカウント登録?が必要らしいです。うーん、どうせならGravatarや他のプラグインも使わずに自分で表示させたいです。調べて作ります。

プロフィール画像登録機能を作る

このサイトが参考になりそうです。

https://ucozi.com/wordpress-profile-image/

  • function_existsってなんだ?
    • 引数で指定した関数名がすでに定義されているかどうか判定するため関数。つまり、既に関数名が使われていたら間違って関数を上書きしないようにするため、IFの条件にこの関数を使って、使われていたら関数定義を行わないようにする、みたいな使い方をするらしいです。
  • get_the_posts_author_idってなんだ?
    • これはWordpressフォルダをGrepかけてもヒットしない。ググってもそれっぽい情報が出ない。
    • こんな機能って存在するのか?ミスってない?後述されているユーザーメタ情報取得のところもuploadedっぽいところがupladedになっている。コピペの匂いがする。自分で試していないんちゃうん?と勝手に疑ってます。
    • 結論、完全な真似は止めて、流れは参考につつ中身は自分で解決します。この記事の人も自分では理解していないと書いてますし。

頑張ってみたが、良く分からなくなってきた。結局、たどり着いたのは以下のサイト。ここでプロフィール写真をGravatarなし&プラグインなしで変更することができました。

https://nelog.jp/wordpress-original-profile-image-custom

ただし、そのまま張り付けるとエラーになったので、エラーになった部分「get_the_post_author_id()」をget_the_author_meta(‘ID’);に変更して実行しました。

function.php

PHPCOPY
///////////////////////////////////////
// 自前でプロフィール画像の設定
///////////////////////////////////////
//プロフィール画面で設定したプロフィール画像
if ( !function_exists( 'get_the_author_avatar_url' ) ):
    function get_the_author_avatar_url($user_id){
      if (!$user_id) {
        $user_id = get_the_author_meta('ID');
      }
      return esc_html(get_the_author_meta('avatar_url', $user_id));
    }
endif;
    //ユーザー情報追加
    //このフックはユーザーが自分のプロフィールページを表示しているときのみトリガーされる。
    //プロフィールページの下部に新しいフィールドまたはデータを出力するときに使用される。
    //現在のユーザーだけでなく、すべてのプロフィールページに適用する場合は、edit_user_profileフックも使用する。
    add_action('show_user_profile', 'add_user_profile');
    function add_user_profile($user) {
        ?>
        <h2>プロフィール画像</h2>
        <table class="form-table">
            <tr>
                <th>
                    <label for="avatar">プロフィール画像URL</label>
                </th>
                <td>
                    <input type="text" name="avatar_url" size="70" value="<?php echo get_the_author_avatar_url($user->ID); ?>" placeholder="画像URLを入力してください">
                    <p class="description">Gravatarよりこちらのプロフィール画像が優先されます。240×240pxの正方形の画像がお勧めです。</p>
                </td>
            </tr>
        </table>
        <?php
    }
    //フォームに入力した値を保存する
    add_action('personal_options_update', 'update_avatar_url');
    function update_avatar_url($user_id) {
        if ( current_user_can('edit_user',$user_id) ){
            update_user_meta($user_id, 'avatar_url', $_POST['avatar_url']);
        }
    }
    //プロフィール画像を変更する
    add_filter( 'get_avatar' , 'get_uploaded_user_profile_avatar_demo' , 1 , 5 );
    if ( !function_exists( 'get_uploaded_user_profile_avatar_demo' ) ):
    function get_uploaded_user_profile_avatar_demo( $avatar, $id_or_email, $size, $default, $alt ) {
      if ( is_numeric( $id_or_email ) )
        $user_id = (int) $id_or_email;
      elseif ( is_string( $id_or_email ) && ( $user = get_user_by( 'email', $id_or_email ) ) )
        $user_id = $user->ID;
      elseif ( is_object( $id_or_email ) && ! empty( $id_or_email->user_id ) )
        $user_id = (int) $id_or_email->user_id;
      if ( empty( $user_id ) )
        return $avatar;
      if (get_the_author_avatar_url($user_id)) {
        $alt = !empty($alt) ? $alt : get_the_author_meta( 'display_name', $user_id );;
        $author_class = is_author( $user_id ) ? ' current-author' : '' ;
        $avatar = "<img alt='" . esc_attr( $alt ) . "' src='" . esc_url( get_the_author_avatar_url($user_id) ) . "' class='avatar avatar-{$size}{$author_class} photo' height='{$size}' width='{$size}' />";
      }
      return $avatar;
    }
    endif;

仕組みの解析

コピペで動くものはできたので、どういう理屈で動いているのか調査してみる。

  • get_the_author_upladed_avatar_url_demo機能:プロフィール画像のURLを返却する
    • http://localhost/surukoto/wp-content/themes/surukoto/img/profile1.jpgが実際に返却されている。
    • 肝としては、get_the_author_meta関数。これで返却URLを作成している。
    • フィールドのupladed_avatarが理解できない。
      • どうやらこれはupdate_avatar_to_user_profile_demoで追加しているっぽい。
  • add_avatar_to_user_profile_demo:プロフィール画像変更枠をページに追加する。
    • add_actionでshow_user_profileアクションにフックすると、プロフィール表示時に動く。プロフィールページ下部に新しいフィールドやデータを表示したい場合によく使うらしいです。
  • add_action(‘personal_options_update’, ‘update_avatar_to_user_profile_demo’);
    • 現在のユーザーが自分のプロファイルを編集している場合に発生するアクション。プロフィール画面でページが読み込まれる前に発生するらしい。これも全ユーザーに適用する場合はedit_user_profile_update フックも必要らしい。
    • これでフックしている関数のupdate_avatar_to_user_profile_demoについて。
      • if ( current_user_can(‘edit_user’,$user_id) ){
        • いわゆる権限チェックですね。
        • wp-admin/includes/schema.phpに権限の記載がある。そこを見ると、Administratorグループにedit_user権限を追加していることを確認できる。
        • つまり、プロフィールページにアクセスしたときのユーザーが管理者権限かどうかをチェックしていると思われる。管理者なら、update_user_meta($user_id, ‘upladed_avatar’, $_POST[‘upladed_avatar’]);を実行。
      • update_user_meta~はユーザーメタデータを更新している。
        • つまり、ユーザーIDxx(まぁ自分になるだろう)のメタデータのupladed_avatarキーに対して、$_POST[‘upladed_avatar’]データで更新する。
        • そして、キーがなかった場合は、新規追加するとのこと。
  • add_filter( ‘get_avatar’ , ‘get_uploaded_user_profile_avatar_demo’ , 1 , 5 );
    • フィルターget_avatar を使うとget_avatar 関数が返すアバターを変えられるらしい。この書き方だと、指定されたユーザーを取得して、IDが1ならget_uploaded_user_profile_avatar_demo関数を実行する流れ。
    • このget_avatar フィルターを使うときには気を付ける部分があるらしい。
      • ユーザーのIDまたはオブジェクトまたはメールアドレスが渡される。探しているキーがどれか不明なのですべて確認する必要があるとのこと。
      • htmlのimgタグ全体を返す模様。これにはクラスやSrc属性、Alt属性を含むので、URLだけでなく全体を再生成する必要があるとのこと。
    • 関数の流れとしては、
      • まずは数字かどうかチェックする。数字ならメアドではなくユーザーIDが渡されていると判断。
      • elseifとして、文字列かつ渡されたメアドとユーザーのメアドと一致するかチェックし、一致すれば、ユーザーIDを取得。
      • elseifとして、渡された値がオブジェクトかつ、ユーザーIDを含むなら、ユーザーIDをオブジェクトから取得する
      • ここまででユーザーIDが取得できていないなら、ユーザーのアバターを表すimgタグ全体を返す。
      • ここまででプロフィールに設定しているアバター画像があれば次に進む
        • $alt = !empty($alt) ? $alt : get_the_author_meta( ‘display_name’, $user_id );;は三項の条件演算子。altが空で無いなら、そのままaltを持ち、空なら、get_the_author_metaを返す。って感じ。
        • altはget_avatar_data() の実行値。:アバターの高さ、幅とかアバターに関するデフォルトデータを取得
        • ユーザーが現在のユーザーかどうかチェック
        • avatarのimgタグを組みなおして返却。
      • という流れですね。

ここら辺の仕組みについては以下のサイトも参考になりました。

https://www.imamura.biz/blog/22720

画像URLを直接打ち込んで登録するのではなく、ボタンからアップロードできるようにしたい

以下のサイトを参考にして、アップローダーも付けました。

https://nelog.jp/media-uploader-javascript-api

function.php

PHPCOPY
add_action('show_user_profile', 'add_user_profile');
function add_user_profile($user) {
    $name='avatar_url';
    $value=get_the_author_avatar_url($user->ID);
    ?>
    <h2>プロフィール画像</h2>
    <table class="form-table">
        <tr>
            <th>
                <label for="avatar">プロフィール画像URL</label>
            </th>
            <td>
                <input type="text" name="<?php echo $name; ?>" size="70" value="" placeholder="画像URLを入力してください">
                <input type="button" name="<?php echo $name; ?>_slect" value="選択" />
                <input type="button" name="<?php echo $name; ?>_clear" value="クリア" />
                <p class="description">Gravatarよりこちらのプロフィール画像が優先されます。240×240pxの正方形の画像がお勧めです。</p>
            </td>
        </tr>
        <tr>
            <th></th>
            <td>
                <div id="<?php echo $name; ?>_thumbnail" class="uploded-thumbnail">
                    <?php if ($value): ?>
                        <img src="<?php echo $value; ?>" alt="選択中の画像" width="240" height="240">
                    <?php endif ?>
                </div>
            </td>
        </tr>
    </table>

    <script type="text/javascript">
    (function ($) {
        var custom_uploader;
        $("input:button[name=<?php echo $name; ?>_slect]").click(function(e) {
            e.preventDefault();
            if (custom_uploader) {
                custom_uploader.open();
                return;
            }

            custom_uploader = wp.media({
                title: "画像を選択してください",
                /* ライブラリの一覧は画像のみにする */
                library: {
                    type: "image"
                },
                button: {
                    text: "画像の選択"
                },
                /* 選択できる画像は 1 つだけにする */
                multiple: false
            });

            custom_uploader.on("select", function() {
                var images = custom_uploader.state().get("selection");
                /* file の中に選択された画像の各種情報が入っている */
                images.each(function(file){
                    /* テキストフォームと表示されたサムネイル画像があればクリア */
                    $("input:text[name=<?php echo $name; ?>]").val("");
                    $("#<?php echo $name; ?>_thumbnail").empty();
                    /* テキストフォームに画像の URL を表示 */
                    $("input:text[name=<?php echo $name; ?>]").val(file.attributes.sizes.full.url);
                    /* プレビュー用に選択されたサムネイル画像を表示 */
                    $("#<?php echo $name; ?>_thumbnail").append('<img src="'+file.attributes.sizes.full.url+'" width="240" height="240" />');
                });
            });
            custom_uploader.open();
        });

        /* クリアボタンを押した時の処理 */
        $("input:button[name=<?php echo $name; ?>_clear]").click(function() {
            $("input:text[name=<?php echo $name; ?>]").val("");
            $("#<?php echo $name; ?>_thumbnail").empty();
        });

    })(jQuery);
    </script>
    <?php
}
function my_admin_scripts() {
    //メディアアップローダの javascript API
    wp_enqueue_media();
}
add_action( 'admin_print_scripts', 'my_admin_scripts' );

やっと管理画面側にプロフィールを登録する枠ができて、プロフィール設定ができるようになりました。後は皆にプロフィールを見せるためのprofile.phpを整えていきます。

profile.phpを整えていく

以下のサイトを参考にSNSアイコンを取得します。

https://notes-de-design.com/website/tool/use-cdn-download-fontawesome/

フォロー枠は以下のサイトを参考にしました。

https://blog.yoshinonaco.com/blogcustom-profile/

profile.php

PHPCOPY
<div class="container overflow-hidden mb-4" id="surukoto-profile">
    <div class="row mx-4 pb-3 my-3 border-bottom surukoto-profile-head">
        記事書いたりサイト運営してる人
    </div>
    <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-2 g-md-4 px-3 mx-3 align-items-center">
        <div class="col-12 col-md-6 col-lg-4 text-center">
            <div class="surukoto-profile-icon">
                <?php echo get_avatar( $post->post_author, 120); ?>
            </div>
            <div class="surukoto-profile-name">    
                <?php the_author(); ?>
            </div>
        </div>
        <div class="col-12 col-md-6 col-lg-4">
            <div class="surukoto-profile-description">
                <?php the_author_meta('user_description'); ?>
            </div>
        </div>
        <div class="col-12 col-md-12 col-lg-4 text-center surukoto-profile-follows p-2">
            <div class="surukoto-profile-follow-buttons">
                <a href="https://surukoto.jp" class="surukoto-profile-follow-button"><i class="fa-solid fa-house"></i></a>
                <a href="https://twitter.com/taishi_tera" class="surukoto-profile-follow-button"><i class="fa-brands fa-twitter"></i></a>
                <?php //  <a href="https://www.youtube.com/channel/UChAhuPh2lSsHEOUsYAFk1KQ" class="surukoto-profile-follow-button"><i class="fa-brands fa-youtube"></i></a> ?>
            </div>
        </div>
    </div>
</div>

ヘッダーナビからリンク後のブラウザバックをリンク前ではなく、前画面にしたい

ヘッダーナビゲーションにページ内リンクがありますが、リンク先に移動して、ブラウザバックをすると、ページ内リンクをした場所(つまりヘッダーナビゲーション)に戻ります。そのような動作ではなく、画面単位にバックさせたいです。つまり、前画面に戻る動きにしたいです。

ジャンプスクロールの実装

前画面に戻らせるには、そもそもの遷移をジャンプスクロールにすれば実現できそうです。以下のサイトが参考になりそう?

https://web-camp.io/magazine/archives/85351

素のJavascript で動くようにしたい。さらに以下のサイトを参考にします。

https://flex-box.net/js-smoothscroll/

ちなみにJavaScriptを書く場所は、新しくloaded-script.jsというファイルを作って記載しています。

問題発生。なぜかdocument.querySelector(“.surukoto-nav”)がnullになってしまう。開発者ツール上で同じ文を実行したら取得できます。

予想では多分、HTML上の読み込み順な気がします。Headerが先に実行されて、本文が何もない状況とか?

色々試してみると、document.bodyはNullで、document.headは取得できることが分かりました。つまり、Headしか無いタイミングで読み込んでしまっていると想定します。

Footerのbody閉じタグ直前に読み込むように修正しました。Function.phpではなく、直でscriptタグを記載してファイルを読み込んでます。

正常に動きました!戻るを押下しても、上のヘッダーナビに戻るのではなく、ページが戻ることを確認しました。

また、フッターに直で、と記載していましたが、wp_enqueue_scriptsで登録するようにしました。その際に第5引数をtrueにするとFooterで読み込めるようにできるようです。

loaded-script.js

HTMLCOPY
const navMenu = document.querySelector(".surukoto-nav");
const triggerList = navMenu.querySelectorAll('a[href^="#"]');
for (let i = 0; i < triggerList.length; i++){
  triggerList[i].addEventListener('click', (e) => {
    e.preventDefault();
    let href = triggerList[i].getAttribute('href');
    let targetElement = document.getElementById(href.replace('#', ''));
    const rect = targetElement.getBoundingClientRect().top;
    const offset = window.pageYOffset;
    const gap = 0;
    const target = rect + offset - gap;
    window.scrollTo({
      top: target,
      behavior: 'smooth',
    });
  });
}

footer.php

PHPCOPY
        <!-- フッター -->
        <footer class="footer py-3 mt-5 bg-dark text-light">
            <div class="container text-center">
                <ul class="nav justify-content-center mb-3">
                    <li class="nav-item">
                    </li>
                    <li class="nav-item">
                    </li>
                    <li class="nav-item">
                    </li>
                </ul>
           
            <p class="footer-copyrigtht"><small>Copyright &copy;2022 Surukoto LAB, AllRights Reserved.</small></p>
        </div>
        </footer>
        <!-- ここまでフッター -->
        <?php
            wp_footer();
        ?>
  </body>
</html>

多くのサイトによくある「上に戻るボタン」を作りたい

以下のサイトを参考にしました。

https://flex-box.net/js-scrolltop/#co-index-4

うーん、そのままコピペだと動きませんね・・・。コンソールに情報を出すと、無限ループになっていました。同サイトに記載しているモダンな方にしました。

JSに機能を実装し、footer.phpでアイコンを作り、CSSでデザインを整えています。

作成ファイル

loaded-script.js

HTMLCOPY
const PageTopBtn = document.getElementById('js-scroll-top');
PageTopBtn.addEventListener('click', () =>{
  window.scrollTo({
    top: 0,
    behavior: 'smooth'
  });
});

footer.php

PHPCOPY
        <!-- フッター -->
        <footer class="footer py-3 mt-5 bg-dark text-light">
            <div class="container text-center">
                <ul class="nav justify-content-center mb-3">
                    <li class="nav-item">
                    </li>
                    <li class="nav-item">
                    </li>
                    <li class="nav-item">
                    </li>
                </ul>
           
            <p class="footer-copyrigtht"><small>Copyright &copy;2022 Surukoto LAB, AllRights Reserved.</small></p>
        </div>
        </footer>
        <!-- ここまでフッター -->
        <!-- トップ遷移用 Start-->
        <div id="js-scroll-top" class="scroll-top"><i class="fa-solid fa-angles-up"></i></div>
        <!-- トップ遷移用 End-->
        <?php
            wp_footer();
        ?>
  </body>
</html>

style.css

CSSCOPY
/* -----------------------
    フッター > トップ遷移
  ----------------------- */
    .scroll-top {
      position: fixed;
      bottom: 10%;
      z-index: 100;
      background-color: rgb(88, 88, 88);
      width: 30px;
      height: 30px;
      color: #fff;
      line-height: 30px;
      text-align: center;
      border-color: #fff;
    }
    .scroll-top:hover {
      cursor: pointer;
      opacity: 0.7;
    }

    @media (min-width: 767px) {
      .scroll-top {
        width: 50px;
        height: 50px;
        line-height: 50px;
      }
    }

細かい部分は色々気になる箇所もありますが、いったんはこれで完成。

使いながら、改善していきます。

Weekly Most Popular
記事書いたりサイト運営してる人
シイタ / siita
シイタ / siita
現役サラリーマン/システムエンジニアです。 会社外でも、自分に自信を持って活躍できるようになりたい。金銭的にも安心できるようになりたい。という気持ちから技術向上や不労所得を得るために、日々活動することを記録し、共有していきます。