【WordPressエラー】Warning: Cannot modify header information – headers already sent by

エラー内容

functions.phpを作成し、編集していたところエラー発生。

「functions.php」の1行目のコメントアウトを削除したところ解消しました。

<!-- カスタムフィールドの値をタイトルに自動で反映    -->
<?php
add_action('acf/save_post', 'replace_post_title');
function replace_post_title( $post_id ) {

    // タイトルの入ったフィールドを取得
    $newtitle = get_field("news_text",$post_id);

	//タイトルが空でない場合は更新
    if( $newtitle ) {
        $args = array(
			"ID"=>$post_id,
			"post_title" => $newtitle
		);
		wp_update_post($args);
    }
}

▽1行目のコメントアウトを削除

<?php
add_action('acf/save_post', 'replace_post_title');
function replace_post_title( $post_id ) {

    // タイトルの入ったフィールドを取得
    $newtitle = get_field("news_text",$post_id);

	//タイトルが空でない場合は更新
    if( $newtitle ) {
        $args = array(
			"ID"=>$post_id,
			"post_title" => $newtitle
		);
		wp_update_post($args);
    }
}

参考サイト

https://irodori-design-web.com/blog/blog-1446
【WordPressエラー】「Warning: Undefined variable $post in …」「Warning: Attempt to read property “ID” on null in …」

PHP7.3からPHP8.0に変更がありWordPressでエラーメッセージが発生しました。

表題のエラーがPHP8.0より通知ではなく、独立エラーとして扱われるようになった為です

エラー内容

「get_the_terms」記事に基づくタクソノミーの取得のための下記の記述でエラー発生

<?php 
$terms = get_the_terms($post->ID, 'tag-workshop');
if ($terms) {
foreach ($terms as $term) {
echo '<a class="tagc-tag-workshop" tag-id="' . $term->term_id . '" href="' . get_permalink() . '">' . $term->name . '</a>';
}
?>

Warning: Undefined variable $post in …

Warning: Attempt to read property “ID” on null in …

(解決策)変数を定義する

Undefined variable $postとは変数の未定義によるエラーです

global $post;を追記することによりエラー解消しました

<?php 
global $post;
$terms = get_the_terms($post->ID, 'tag-workshop');
if ($terms) {
foreach ($terms as $term) {
echo '<a class="tagc-tag-workshop" tag-id="' . $term->term_id . '" href="' . get_permalink() . '">' . $term->name . '</a>';
}
?>

参考サイト

【PHP7から8へ切替】Warning: Undefined variableが表示された場合の修正方法
https://it-column.mjeinc.co.jp/archives/3513

WordPressのグローバル変数「$post」とは?中身や使い方について解説
https://tcd-theme.com/2024/01/wp-post-object.html

PHP8.0でWordPressの「Attempt to read property “ID” on null」のエラーを解決したい
https://ja.stackoverflow.com/questions/85387/php8-0%e3%81%a7wordpress%e3%81%ae-attempt-to-read-property-id-on-null-%e3%81%ae%e3%82%a8%e3%83%a9%e3%83%bc%e3%82%92%e8%a7%a3%e6%b1%ba%e3%81%97%e3%81%9f%e3%81%84

【Googleタグマネージャー】「Page Path」で設定したが正しく発火しない

▽タグを作成したが発火しない

トリガーの設定は「Page Path」

トリガーの設定は「Page Path」で「含む」です。

パスはドメインの後ろの文字列です

発火しない理由

「パス(/○○/)」に全角文字が含まれているからかと思われます。

▽WordPressパーマリンク設定で投稿名にチェックしているため、記事タイトルを日本語で書くと日本語パーマリンクになります

日本語パーマリンクの注意点

日本語パーマリンク(全角文字を含む)はコピーする際にエンコードされます。

(1. エンコード前)
https://internet.mints.ne.jp/googleタグマネージャーpage-pathで設定したが正しく発火し/

(2. 貼り付け後)
https://internet.mints.ne.jp/google%e3%82%bf%e3%82%b0%e3%83%9e%e3%83%8d%e3%83%bc%e3%82%b8%e3%83%a3%e3%83%bcpage-path%e3%81%a7%e8%a8%ad%e5%ae%9a%e3%81%97%e3%81%9f%e3%81%8c%e6%ad%a3%e3%81%97%e3%81%8f%e7%99%ba%e7%81%ab%e3%81%97

(解決策)トリガーの設定でエンコード後のパスを設定する

さいしょの発火しない設定方法は(1. エンコード前)のパスを設定していました。

パスを(2. 貼り付け後)…エンコードされたものを設定したところ正しく発火しました。

参考サイト

https://kitsunecode.net/blog-homepage/permalink-japanese/#:~:text=%E3%83%AF%E3%83%BC%E3%83%89%E3%83%97%E3%83%AC%E3%82%B9%E3%81%A7%E3%83%91%E3%83%BC%E3%83%9E%E3%83%AA%E3%83%B3%E3%82%AF,%E3%82%B9%E3%83%A9%E3%83%83%E3%82%B0%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%8B%E3%82%89%E3%81%A7%E3%81%99%E3%80%82

「Advanced Custom Fields」の内容を自動でタイトルに反映させたい

カスタムフィールドの値を自動でタイトルに反映させたい

▽投稿画面の編集項目をカスタムフィールドの値のみ(お知らせ内容のテキスト)にしています。

▽タイトルがないので、(タイトルなし)となります。
そこで「カスタムフィールドの値を自動でタイトルに反映させたい」ということになりました。

functions.phpを編集

// wordpressでタイトルを空白で投稿した時に、自動的にタイトルを挿入する
// https://teratail.com/questions/38598
add_action('acf/save_post', 'replace_post_title');
function replace_post_title( $post_id ) {

    // タイトルの入ったフィールドを取得
    $newtitle = get_field("news_text",$post_id);

	//タイトルが空でない場合は更新
    if( $newtitle ) {
        $args = array(
			"ID"=>$post_id,
			"post_title" => $newtitle
		);
		wp_update_post($args);
    }
}

※news_textはフィールド名です↓

参考サイト

WordPressでカスタムフィールドを自動保存したい
https://teratail.com/questions/38598

All-in-One WP Migration Unlimited Extensionにて「Unlimited Extension は最新バージョンではありません。使用前にプラグインを更新する必要があります。」

アップデート手順

1)「All-in-One WP Migration」をインストール、有効化

2)「all-in-one-wp-migration-unlimited-extension」をインストール

▽プラグインを有効化

3)バージョンを更新

▽「アップデートを確認」か「更新」をクリック

Maximum upload file size: Unlimited

さくらインターネットにて管理画面より「php.ini」を下記の通りに設定しおりますが、サイズ1Gのインポートもできました。

▽「php.ini」
upload_max_filesize = 512M

▽ワードプレス「All-in-One WP Migration」インポート画面
Maximum upload file size: Unlimited

【生成AI】【illustrator】テキストからベクター生成の使い方(バージョン28.0~新機能)

テキストからベクター生成の使い方

▽長方形ツールで表示させたい場所に作成

▽「ウィンドウ」→「プロパティ」をクリックするとプロパティ、「テキストからベクター生成(Beta)」が表示されます

▽プロンプトに生成したい画像の検索ワードを入力するとバリエーションが表示されます

似たようなテイストのイラストを作成する方法

▽「参照アセット」を有効化し「ピッカー」をクリックし似たテイストにしたい画像を選択→「生成(Beta)」をクリック

参考サイト

【イラレの生成AI】 テキストからベクター作成の使い方【Illustrator】
https://321web.link/illustrator-generative-vecter

https://www.tactsystem.co.jp/blog/catalog_36
【WordPress】本文入力欄を非表示にする方法

「カスタム投稿タイプ」、「カスタムフィールド」を利用しているときに、本文入力欄が不要な場合があると思います。

非表示にする方法の紹介です

functions.phpを編集する

// 本文入力欄非表示
add_action( 'init' , 'my_remove_post_support' );
function my_remove_post_support() {
     remove_post_type_support('非表示にしたいカスタム投稿タイプスラッグ','editor'); 
}

【Googleサーチコンソール】検索画面で表示させたくない「Googleのインデックス削除」

Googleのインデックス削除とは

Googleのインデックス削除を申請すると検索画面で該当ページが表示されなくなります

不要なページのインデックス削除はSEOの観点からも重要

Googleサーチコンソールでインデックス削除の手順

▽削除したいURLのあるサイトのプロパティを選択し「削除」をクリック

▽「新しいリクエスト」クリック

▽URLの入力し「次へ」

▽「リクエストを送信」クリック

検索結果反映には1日ほどかかります

インデックス削除されているか確認する方法

site:該当URLで検索

参考サイト

https://rank-quest.jp/column/column/index-removals
【Googleサーチコンソール】プロパティタイプ「ドメイン」と「URLプレフィックス」違い

「ドメイン」と「URLプレフィックス」の2種類のプロパティタイプ

Googleサーチコンソールでプロパティを追加する場合「ドメイン」と「URLプレフィックス」の2種類のプロパティタイプがあります。

それぞれの特徴は下記の通り

プロパティタイプが「ドメイン」

  • wwwあり/なし、http/https、サブドメインすべてのドメインを1つのプロパティで確認できる
    • https://ntorelabo.com/(httpsでwwwあり)
    • http://www.ntorelabo.com/(httpでwwwあり)
    • https://ntorelabo.com/(httpsでwwwなし)
    • http://ntorelabo/(httpでwwwなし)
    • https://○○.ntorelabo/(サブドメイン)
    • https://www.ntorelabo/○○/(サブディレクトリ)
  • サブドメイン、サブディレクトリのみデータの確認ができない
  • プロパティの追加方法がDNSレコードの確認のみ

プロパティタイプが「URLプレフィックス」

  • 該当URLのみのため、wwwあり/なし、http/httpsの違いは対応できない
    例)URLプレフィックス「https://ntorelabo.com/(httpsでwwwなし)」であれば、↓以下が対象
    • https://ntorelabo.com/(httpsでwwwなし)
    • https://ntorelabo.com/〇〇〇〇/(httpsでwwwなし・サブディレクトリ)
  • プロパティの追加方法が4種(ドメインより簡単)
    • HTMLファイルのアップロード
    • metaタグの追加
    • Googleタグマネージャーのアカウントを利用
    • Googleアナリティクスのアカウントを利用
【初心者】WordPressでjQuery使用するときの注意「Uncaught TypeError: $ is not a function」

Uncaught TypeError: $ is not a function

WordPressでjQueryを使用し「Uncaught TypeError: $ is not a function」と表示され、処理がされないとなりました。

そもそも「$(function(){})」とは

「$(function(){})」の記述によって中の処理はHTMLを読み込んでから実行されます

→この記述がないとHTMLの指定を含まれるjQueryのプログラムでエラーとなります

Uncaught TypeError: $ is not a function」の原因

WordPressで「$」マークを使うとjQueryが動作しない場合があります。

※一般的に「jQuery」を省略し「$」と記述します

↓WordPressでデフォルトで読み込まれるjQueryに「noConflict」という関数があります、そのため$の使用ができません

Uncaught TypeError: $ is not a function」の解決策

「$」が使用できないので、下記の通り書き直します

▼修正前

$(function(){ 
      $('○○')○○;
});

▼修正後

jQuery(function() {
      jQuery('○○')○○;
});
ネームサーバーをLOLIPOPに設定していて、DNSレコード設定がしたい場合(Googleサーチコンソールのプロパティの確認で必要)

Googleサーチコンソールでプロパティを追加する際にプロパティタイプをドメインを選択した場合、DNSレコードの確認が必要になります。(↓所有権の証明)

そこでDNSレコードの設定をすることになるのですが、LOLIPOPではできません。

ですが、LOLIPOPのサーバー契約のまま(サイトの表示等のサービスを利用)DNSレコードの設定をする方法がありますので、本記事投稿しました。

やや複雑な手順で、DNSレコードの意味や、各サーバー、ドメイン会社の特徴を理解しておく必要があります。

ネームサーバーをロリポップに設定している場合

今回該当パターンを確認すると下記2通り

  • ロリポップでドメインを取得し、ロリポップのサービス(サイトの表示やメール)を利用
  • 他社でドメインを取得し、ドメイン適用先でロリポップを選択

上記の場合ネームサーバーがロリポップに設定されます。

ロリポップではDNSレコードの設定ができない

ロリポップのネームサーバーを選択すると、DNSレコードの設定ができません。

ロリポップでネームサーバーを設定するとDNSレコードは下記の通りになりますが、

mytalk.siteINA163.44.185.218
mytalk.siteINMX10mx01.lolipop.jp
mytalk.siteINNSuns01.lolipop.jp
mytalk.siteINNSuns02.lolipop.jp
mytalk.siteINTXTv=spf1 include:_spf.lolipop.jp ~all

ネームサーバー設定をすると、ネームサーバー以外のレコード値も自動的に設定されるようです。

お名前ドットコムで取得したドメインでロリポップにネームサーバー設定をしている場合、ロリポップのDNSを利用していることになります。この場合、お客様任意のレコード情報を設定することはできません。ロリポップを利用するために必要なレコードが自動で設定されております。

プライマリネームサーバー: uns01.lolipop.jp セカンダリネームサーバー: uns02.lolipop.jp

詳細は以下のリンクをご参照ください。

https://lolipop.jp/?a8=YRvtwRALNEc6Zvn0zhcfFz06io95nFHX4FPpFMoKusHcDFnKQEPR_EPL86uFSqvYuRQoNFP2tjZ5xs00000000404001

「ロリポップのDNS」はお客様任意のレコード情報を設定することができません
https://support.lolipop.jp/hc/ja/articles/4403084397203-%E3%83%AD%E3%83%AA%E3%83%9D%E3%83%83%E3%83%97%E3%81%AEDNS%E3%81%A7%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E6%83%85%E5%A0%B1%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E3%81%A9%E3%81%86%E3%81%97%E3%81%9F%E3%82%89%E3%81%84%E3%81%84%E3%81%A7%E3%81%99%E3%81%8B

DNSレコードの設定が可能なネームサーバーをロリポップ以外で設定する

DNSレコードの設定はしたいが、ロリポップのサービスは使用したい場合

DNSレコードの設定が可能な会社(ムームードメイン、Xserver …)にて下記の通り設定します

  • Aレコード、MXレコードはそのまま
  • ネームサーバーの値をロリポップから変更した先の値に変更
  • TXTで追記したい内容を編集
    (※1 記述方法はサーバー会社ごとに違うhttps://kiraba.jp/about-multi-spf-records-setting/
    (※2 _spf.lolipop.jpがないと正しくメールを使えない可能性がある(送信元ネームサーバーの認識、特定ができない→迷惑メールとされるかもしれない)

DNSレコード取得ツール

http://webadmin.jp/tooldns/

捕捉情報

Aレコードはサイト表示のため

MXレコードはメールを使うため

ネームサーバーの切り替えは(最大で)72時間

Xserverドメインで取得した独自ドメインをロリポップで使用

手順

▼Xserverレンタルサーバの管理画面にログインし対象のドメインを選択

▼ドメインの契約情報のネームサーバー設定の「設定変更」を選択

▼その他のサービスで利用するを選択しネームサーバー1、ネームサーバー2に下記の通り入力

ネームサーバー1uns01.lolipop.jp
ネームサーバー2uns02.lolipop.jp

確認画面へ進むをクリック

▼「設定を変更する」をクリック

▼ロリポップユーザー専用画面にて

公開(アップロード)フォルダについては複数のドメインを運用する場合は必ず入力

参考サイト

https://monefree.com/lolipop-xsever
【LOLIPOP】サブディレクトリにインストールしたWordPressをドメイン直下で表示

インストール手順

<サーバーの管理画面>
WordPressのインストール

▼インストール先にwpディレクトリを指定

▼インストール履歴

<WordPress管理画面>

▼「/wp」を削除し、画面左下の「変更を保存」ボタンをクリック

(wpフォルダ内とは別でドメイン直下にも)

↓.htaccess(ドメイン直下に生成)


# BEGIN WordPress
# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は
# 動的に生成され、WordPress フィルターによってのみ修正が可能です。
# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

↓.htaccess(wpフォルダ内)


# BEGIN WordPress
# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は
# 動的に生成され、WordPress フィルターによってのみ修正が可能です。
# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /wp/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wp/index.php [L]
</IfModule>

# END WordPress

↓こちらの手順はとばしてしまいました、、が問題なさそう。次回は実施したいと思います。

〇パーマリンク設定を保存する

設定 > パーマリンク へ移動し、何も変更せずに[変更を保存] をクリックします。
この操作で、WordPressに更新を伝えます。

<FTPソフト>
ファイル複製し編集

下記の通りのファイル構成です

〇wpフォルダ内index.phpファイルをダウンロード

▼変更前

# BEGIN WordPress
# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は
# 動的に生成され、WordPress フィルターによってのみ修正が可能です。
# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /wp/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wp/index.php [L]
</IfModule>

# END WordPress

▼変更後

# BEGIN WordPress
# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は
# 動的に生成され、WordPress フィルターによってのみ修正が可能です。
# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

〇wpフォルダ内のindex.phpをダウンロードし下記の通り編集

▼変更前

<?php
/**
 * Front to the WordPress application. This file doesn't do anything, but loads
 * wp-blog-header.php which does and tells WordPress to load the theme.
 *
 * @package WordPress
 */

/**
 * Tells WordPress to load the WordPress theme and output it.
 *
 * @var bool
 */
define( 'WP_USE_THEMES', true );

/** Loads the WordPress Environment and Template */
require __DIR__ . '/wp-blog-header.php';

▼変更後

<?php
/**
 * Front to the WordPress application. This file doesn't do anything, but loads
 * wp-blog-header.php which does and tells WordPress to load the theme.
 *
 * @package WordPress
 */

/**
 * Tells WordPress to load the WordPress theme and output it.
 *
 * @var bool
 */
define( 'WP_USE_THEMES', true );

/** Loads the WordPress Environment and Template */
require __DIR__ . '/wp/wp-blog-header.php';

ドメイン直下にアップロード

以上でドメイン直下でサイトの表示が確認できました

<補足>

サイト表示したときログインしているにもかかわらず、管理バーが表示されなかったのですが、WordPressをログインしなおしたら、表示されました。

複数のサブディレクトリにそれぞれWordPressサイトを作成し、ドメイン直下のindex.phpの記述によって切り替えができそうです

参考サイト

WordPressがドメイン直下ではなくサブディレクトリにインストールされている場合、「Override the base URL of the sitemap」を設定する必要があります。
https://nandemo-nobiru.com/wp-5941

【ロリポップ版】WordPressインストール方法・始め方
https://webst8.com/blog/lolipop-wordpress-open

ロリポップからWordPressを簡単インストールする方法を解説
https://communityserver.org/contents/4319

サブディレクトリ(/wp/)にインストールしたwordpressをドメイン直下に表示する方法【ルートディレクトリを変更】
http://kawatama.net/web/974#google_vignette

サブディレクトリにWordPressを作成した場合のサイトマップはどうすれば良いですか?
https://support.google.com/webmasters/thread/166288539/%E3%82%B5%E3%83%96%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%ABwordpress%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F%E5%A0%B4%E5%90%88%E3%81%AE%E3%82%B5%E3%82%A4%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E3%81%AF%E3%81%A9%E3%81%86%E3%81%99%E3%82%8C%E3%81%B0%E8%89%AF%E3%81%84%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F?hl=ja

サーチコンソールHTMLタグを2つ設置可能かどうか
https://support.google.com/webmasters/thread/122051612/%E3%82%B5%E3%83%BC%E3%83%81%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%ABhtml%E3%82%BF%E3%82%B0%E3%82%922%E3%81%A4%E8%A8%AD%E7%BD%AE%E5%8F%AF%E8%83%BD%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B?hl=ja

https://15cc.com/design/wordpress-subdirectory
https://wordpress-web.and-ha.com/wordpress-security
LOLIPOPサーバーで「All-in-One WP Migration」のアップロードファイルサイズ変更方法

ロリポップサーバー ユーザー専用ページ

▼ユーザー専用ページの「サーバーの管理・設定」→「PHP設定」を選択

▼CGI版のPHPに変更

▼設定項目のupload_max_filesizeが「2M」、「2M」しか設定できません

そのため.htaccessに設定を追記する方法で行います

▼php_value,php_flagを利用可能にするを「On」に変更

.htaccessを編集

.htaccessの編集は「ダウンロード」を押して事前にバックアップをとっておくことをおすすめします

▼対象のドメイン.htaccessを下記の通り編集

以下の内容を追記

php_value memory_limit 512M
php_value upload_max_filesize 512M
php_value post_max_size 512M

# BEGIN WordPress
# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は
# 動的に生成され、WordPress フィルターによってのみ修正が可能です。
# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

php_value memory_limit 512M
php_value upload_max_filesize 512M
php_value post_max_size 512M

▼WordPress管理画面からサイズ変更が確認できました

参考サイト

https://www.vektor-inc.co.jp/post/lolipop-upload-max-filesize
php_value memory_limit 128M
php_value upload_max_filesize 100M
php_value post_max_size 100M

ロリポップでWordPressの最大アップロードサイズを変更する方法
https://webst8.com/blog/lolipop-maximum-upload

php_value memory_limit 512M
php_value upload_max_filesize 512M
php_value post_max_size 512M

↓PHPをバージョン変更後、 WordPressが表示できなくなった

PHPのバージョン変更後、WordPressに関するエラーについて恐れ入りますがWordPress本体や各プラグインは弊社にて開発を行っていないため、ご利用のWordPress本体を含めテーマやプラグインが変更後のPHPのバージョンに対応しているか配布元に対応バージョンをご確認ください。
https://support.lolipop.jp/hc/ja/articles/360048375214-PHP%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E5%A4%89%E6%9B%B4%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E6%B0%97%E3%82%92%E3%81%A4%E3%81%91%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B?a8=YRvtwRALNEc6Zvn0zhcfFz06io95nFHX4FPpFMoKusHcDFnKQEPR_EPL86uFSqvYuRQoNFP2tjZ5xs00000000404001

【お名前.com】Googleサーチコンソールで「所有権を証明できませんでした」の対応

起きていること

▼Googleサーチコンソールでプロパティを追加する際、下記の通り

対応方法

▼お名前ドットコムにログインしドメイン設定を選択

▼「DNS設定/転送設定」を選択

▼該当ドメイン選択後、次へクリック

DNSレコード設定を利用するの「設定する」をクリック

▼下記表のとおり各欄を入力後、追加をクリック

ホスト名TYPETTLVALUE優先状態
空白
(所有権の証明を行うドメイン名)
TXT3600google-site-verification=**********
(※Google管理コンソール内で取得した文字列)
なし有効

参考サイト

各レコードの意味は以下ご参照ください
https://help.onamae.com/answer/7883

【ドメイン】DNS設定の変更手続きをしてから有効になるまでの期間は?
https://help.onamae.com/answer/8081

【WordPress】パンくずリスト作成(プラグインBreadcrumb NavXT)

Breadcrumb NavXT

インストールして有効化

パンくずにホームページを含める。等設定をする

テンプレートファイル編集

ファイルの表示したい箇所に下記コード

<div class="breadcrumbs" typeof="BreadcrumbList" vocab="https://schema.org/">
    <?php if(function_exists('bcn_display'))
    {
        bcn_display();
    }?>
</div>

例)↓アクションフックでfunctions.phpに記述

add_action('main_hook', function () {
?>
<div class="breadcrumbs" typeof="BreadcrumbList" vocab="https://schema.org/">
<?php if(function_exists('bcn_display'))
{
bcn_display();
}?>
</div>

<style>
		
</style>
<?php
});

参考サイト

Breadcrumb NavXTプラグインの使い方(パンくずリストの表示)

https://www.javadrive.jp/wordpress/plugin-list/index16.html

【React】Todoアプリ

todoアプリ作成

参考サイト:
https://www.youtube.com/watch?v=nRCNL9T3J98

ノードjsインストール確認、Reactひな型作成

PS C:\Users\…\react-project> node -v
v18.17.1
PS C:\Users\…\react-project> npx create-react-app react-tutorial  

→完了するとHappy hacking!の表示

不要なファイルの削除\src\App.test.js src\logo.svg \src\reportWebVitals.js \src\setupTests.js

コンポーネントの作成

▼\src\TodoList.jsを作成

VSCodeプラグインES7+ React/Redux/React-Native をインストールしていればrafceタブ補完と入力すれば下記のように関数コンポーネントが入力されます

import React from 'react'
export const TodoList = () => {
  return (
    <div>TodoList</div>
  )
}

▼App.jsを編集

インポートの記載

import { TodoList } from "./TodoList";
function App() {
  return (
    <div className="App">
      <TodoList />
    </div>
  );
}
export default App;

入力欄、ボタン作成

▼.js

import TodoList from "./TodoList";

function App() {
  return (
    <div className="App">
      <div>
        <TodoList />
        <input type="text" />
        <button>タスクを追加</button>
        <button>完了したタスクの削除</button>
        <div>残りのタスク:0</div>
      </div>
    </div>
  );
}

export default App;

1)useStateで状態を監視→変更で再レンダリング
2)propsでtodos={todos}でコンポーネント間のデータの受け渡し

▼App.js

import { useState } from "react";
import TodoList from "./TodoList";

function App() {
  const [todos, setTodos] = useState(["Todo1", "Todo2"]);

  return (
    <div className="App">
      <div>
        <TodoList todos={todos}/>
        <input type="text" />
        <button>タスクを追加</button>
        <button>完了したタスクの削除</button>
        <div>残りのタスク:0</div>
      </div>
    </div>
  );
}

export default App;

useState()

useState()は、関数コンポーネントでstateを管理(stateの保持と更新)

stateとはコンポーネントが内部で保持する「状態」

▼TodoList.js

import React from 'react'

const TodoList = ({ todos }) => {
  return (
    <div>{todos}</div>
  )
}

export default TodoList

Todo.jsを作成(各タスクをコンポーネントにおきかえる)

▼TodoList.js

import React from 'react';
import Todo from './Todo';

const TodoList = ({ todos }) => {
  return todos.map((todo) => <Todo todo={todo} />);
}

export default TodoList

▼Todo.js

import React from 'react'

const Todo = ({ todo }) => {
  return (
    <div>{todo}</div>
  )
}

export default Todo

todoをオブジェクトとして管理

▼App.js

function App() {
  const [todos, setTodos] = useState([
    { id: 1, name: "Todo1", completed: false },
  ]);

▼Todo.js

const Todo = ({ todo }) => {
  return (
    <div>{todo.name}</div>
  )
}

チェックボックスの実装(チェックオンオフは後から実装)

▼Todo.js

    <div>
        <label>
            <input type="checkbox" checked={todo.completed} readOnly />
        </label>
        {todo.name}
    </div>

タスクの追加 
useRefで要素の取得(オブジェクトにおけるスプレッド構文の追加)

▼useRefで取得した内容をconsole.log()で確認

▼App.js

import { useState, useRef } from "react";
import TodoList from "./TodoList";

function App() {
  const [todos, setTodos] = useState([
    { id: 1, name: "Todo1", completed: false },
  ]);

  // useRefでinputの値を取得
  const todoNameRef = useRef();

  // タスクを追加する
  const handleAddTodo = () => {

    const name = todoNameRef.current.value;

    // 空白のタスクを生成しない
    if(name === "") return;

    // setTodosでTodosの内容を更新
    // オブジェクトにおけるスプレッド構文の追加
    setTodos((prevTodos) => {
      return [...prevTodos, { id: "1", name: name, completed: false }];
    });

    todoNameRef.current.value = null;
  };

  return (
    <div className="App">
      <div>
        <TodoList todos={todos}/>
        <input type="text" ref={todoNameRef} />
        <button onClick={handleAddTodo}>タスクを追加</button>
        <button>完了したタスクの削除</button>
        <div>残りのタスク:0</div>
      </div>
    </div>
  );
}

export default App;

対応)Warning: Each child in a list should have a unique “key” prop.

uuidインストール

ユニークキーの生成が可能

https://www.npmjs.com/package/uuid

npm install uuid→package.jsonにてインストールの確認ができます

  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "uuid": "^9.0.1",
    "web-vitals": "^2.1.4"
  },

▼App.jsを編集

import { useState, useRef } from "react";
import { TodoList } from "./TodoList";
import { v4 as uuidv4 } from 'uuid';

function App() {
  const [todos, setTodos] = useState([
    { id: 1, name: "Todo1", competed: false }
  ]);

  const todoNameRef = useRef();

  const handleAddTodo = () => {
    // タスクを追加
    const name = todoNameRef.current.value;
    setTodos((prevTodos) => {
      return [...prevTodos, { id: uuidv4(), name: name, completed: false }]
    });
    todoNameRef.current.value = null;
  };

▼TodoList.jsを編集

export const TodoList = ({ todos }) => {
  return todos.map((todo) => <Todo todo={todo} key={todo.id}/>);
}

初期値をから行列にApp.js

function App() {
  const [todos, setTodos] = useState([]);

toggleTodoでチェックボックスを管理

▼App.jsを編集


  // チェックボックスの操作
  const toggleTodo = (id) => {

    // 直接値を変更しない為newTodosにコピーしている
    const newTodos = [...todos];

    // 引数のidとtodoのidが一致したら、completedを反転
    const todo = newTodos.find((todo) => todo.id === id);
    todo.completed = !todo.completed;
    setTodos(newTodos);
  };

  return (
    <div className="App">
      <div>
        <TodoList todos={todos} toggleTodo={toggleTodo} />
        <input type="text" ref={todoNameRef} />
        <button onClick={handleAddTodo}>タスクを追加</button>
        <button>完了したタスクの削除</button>
        <div>残りのタスク:0</div>
      </div>
    </div>
  );
}

export default App;

▼TodoList.jsを編集


const TodoList = ({ todos, toggleTodo }) => {
  return todos.map((todo) => <Todo todo={todo} key={todo.id} toggleTodo={toggleTodo} />);
}

▼Todo.jsを編集

import React from 'react'

const Todo = ({ todo, toggleTodo }) => {

    const handleTodoClick = () => {
        toggleTodo(todo.id);
    };

    return (
        <div>
            <label>
                <input 
                    type="checkbox" 
                    checked={todo.completed} 
                    readOnly 
                    onClick={handleTodoClick} 
                />
            </label>
            {todo.name}
        </div>
    )
}

export default Todo

残りのタスクの数をいれる

▼App.jsを編集


    <div className="App">
      <div>
        <TodoList todos={todos} toggleTodo={toggleTodo} />
        <input type="text" ref={todoNameRef} />
        <button onClick={handleAddTodo}>タスクを追加</button>
        <button>完了したタスクの削除</button>
        <div>残りのタスク:{todos.filter((todo) => !todo.completed).length}</div>
      </div>
    </div>

完了したタスクの削除

  // 完了したタスクの削除
  const handleClear = () => {
    const newTodos = todos.filter((todo) => !todo.completed);
    setTodos(newTodos);
  }

  return (
    <div className="App">
      <div>
        <TodoList todos={todos} toggleTodo={toggleTodo} />
        <input type="text" ref={todoNameRef} />
        <button onClick={handleAddTodo}>タスクを追加</button>
        <div>残りのタスク:{todos.filter((todo) => !todo.completed).length}</div>
        <button onClick={handleClear}>完了したタスクの削除</button>
      </div>
    </div>
  );
}

レンタルサーバで公開

参考サイト:https://zenn.dev/kiriyama/articles/538face511307d

▼package.jsonを編集

▼\public.htaccessを作成(publickフォルダに「.htaccess」のファイルを作成)

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

▼プロジェクトディレクトリで下記のコマンドでビルド

npm run build

buildというフォルダが作成されるので、その中身をFTPでアップロード

アップロードしたサイト:https://internet.mints.ne.jp/react-todo/


https://www.youtube.com/watch?list=PLX8Rsrpnn3IWPoM7-1YPDksRRkamRY25k&time_continue=8&v=XKSYF2aZnkQ&embeds_referring_euri=https%3A%2F%2Fsbucks-blog.com%2F&source_ve_path=Mjg2NjY&feature=emb_logo

Laravelの開発環境をDockerで構築し、さくらインターネットにデプロイする方法

大まかなフロー

  1. ローカルでDockerで作成した環境にLaravelをインストール
  2. srcフォルダをGithubにリポジトリを作成

ローカル環境

laravel-project/
│
├── docker/
│   ├── php/
│   │   └── Dockerfile
│   └── nginx/
│       └── default.conf
│
├── docker-compose.yml
└── src/     # まだ空

phpの設定

docker\php\Dockerfile

FROM php:8.2-fpm

# 必要なパッケージを全て最初からインストール
RUN apt-get update && apt-get install -y \
    git \
    zip \
    unzip \
    nodejs \
    npm \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    sqlite3

# PHPの拡張機能をインストール
RUN docker-php-ext-install pdo_mysql

# Composerインストール
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html

nginxの設定

docker\nginx\default.conf

server {
    listen 80;
    root /var/www/html/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Dockerの設定

docker-compose.yml

version: '3'
services:
  app:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    volumes:
      - ./src:/var/www/html

  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app

  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_USER: laravel
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
# Dockerコンテナを起動
docker-compose up -d

Laravelのインストール

# 1. まず、appコンテナに入る場合
docker-compose exec app bash

# 2. コンテナ内で実行されるComposerコマンド
composer create-project laravel/laravel .

composer create-project

  • Composerの機能で新しいプロジェクトを作成する命令
  • PHP のパッケージマネージャーである Composer の機能
src/
├── app/          # アプリケーションのコアコード
├── bootstrap/    # フレームワークの起動ファイル
├── config/       # 設定ファイル
├── database/     # データベース関連ファイル
├── public/       # Webサーバーのドキュメントルート
├── resources/    # ビュー、CSS、JSなど
├── routes/       # ルーティング定義
├── storage/      # ログ、キャッシュなど
├── tests/        # テストファイル
├── vendor/       # Composer依存パッケージ
├── .env          # 環境設定ファイル
├── artisan       # コマンドラインツール
└── composer.json # パッケージ依存関係の定義

.envファイル編集

src/.env

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:q2QBqULWSbDokQMj1CEWuMZlhr3Y8SXtF5AiAUQUAEk=
APP_DEBUG=true
APP_URL=http://localhost:8080  # ポート番号を追加

LOG_CHANNEL=stack
LOG_LEVEL=debug

DB_CONNECTION=sqlite
# DB_DATABASE=/var/www/html/database/database.sqlite  # コメントアウトして自動設定を使用

SESSION_DRIVER=file  # データベースではなくfileを使用
SESSION_LIFETIME=120

CACHE_DRIVER=file    # データベースではなくfileを使用
QUEUE_CONNECTION=sync  # データベースではなくsyncを使用

権限設定

# storage(ログ、キャッシュ用)
docker-compose exec app chown -R www-data:www-data storage
docker-compose exec app chmod -R 775 storage

# bootstrap/cache(フレームワークキャッシュ用)
docker-compose exec app chown -R www-data:www-data bootstrap/cache
docker-compose exec app chmod -R 775 bootstrap/cache

# database(SQLite用)
docker-compose exec app chown -R www-data:www-data database
docker-compose exec app chmod -R 775 database

SQLiteデータベース設定

docker-compose exec app touch database/database.sqlite
docker-compose exec app chmod 664 database/database.sqlite
docker-compose exec app chown www-data:www-data database/database.sqlite

キャッシュクリア

  • .envファイルの変更を反映するため
  • 設定の変更(DB接続情報など)を確実に適用するため
docker-compose exec app php artisan config:clear
docker-compose exec app php artisan cache:clear

マイグレーション実行

データベースのテーブルを作成

# データベースのテーブルを作成
docker-compose exec app php artisan migrate

npmのインストールと初期設定

# コンテナ内でnpm installを実行
docker-compose exec app npm install

# 開発用のビルドを実行
docker-compose exec app npm run dev

デプロイ方法

方法 1)本番環境でComposerインストールする(一般的)

vendorディレクトリの中身のライブラリがサイズが大きいので、package.json?だけ共有して、それぞれの環境でインストールするのが一般的(重たいファイルのやり取りはしたくない)

  • ✅ リポジトリが軽量
  • ✅ 各環境で最適化されたインストール
  • ❌ インストール時間が必要
  • ❌ インストール失敗のリスク
  • ❌ サーバーにComposerが必要

方法 2)vendor/ディレクトリを含めてバージョン管理して本番環境にアップロードする
→ 今回はこちらの手順を実施

  • ✅ デプロイが確実
  • ✅ Composerインストール不要
  • ❌ リポジトリが大きくなる

Gitリポジトリ設定

src/                  # Laravelプロジェクト
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── resources/
├── routes/
├── storage/
├── tests/
├── vendor/          # ★これを含める(Composerインストール不要に)
├── composer.json
├── composer.lock
└── .gitignore           # Docker関連ファイルは除外

本番環境での設定

.envファイルの作成と設定

.env.exampleをコピー

# .env ファイルを作成
cp .env.example .env

.env

APP_NAME=Laravel
APP_ENV=production
APP_DEBUG=false
APP_URL=https://siennahare23.sakura.ne.jp/laravel-d01

DB_CONNECTION=sqlite
# その他のDB設定はコメントアウト

SESSION_DRIVER=file
CACHE_DRIVER=file

権限の設定

# 権限を設定
chmod -R 775 storage bootstrap/cache

ストレージリンクの作成

アップロードされたファイル(画像など)を公開アクセス可能にする storage/app/publicpublic/storage をリンクさせる

# ストレージリンクの作成
php artisan storage:link
laravel-dir/
├── public/          # Webからアクセス可能なディレクトリ
│   └── storage -> ../storage/app/public  # シンボリックリンク
│
└── storage/
    └── app/
        └── public/  # 実際のファイル保存場所

ユーザーが画像をアップロードする→画像は storage/app/public に保存される →public/storage からアクセス可能になる

キャッシュのクリアと再生成

php artisan config:clear  # 設定ファイルのキャッシュを削除
php artisan cache:clear   # アプリケーションのキャッシュを削除
php artisan view:clear    # コンパイル済みビューファイルを削除

php artisan config:cache  # 設定ファイルを1つのファイルにまとめる
php artisan route:cache   # ルート情報をキャッシュ
php artisan view:cache    # ビューファイルをプリコンパイル

.htaccessの設定

laravel-dir/.htaccess

# PHPファイルの実行設定(.phpの拡張子のファイルをPHPスクリプトとして実行)
AddHandler application/x-httpd-php .php

# サーバー基本設定
# +SymLinksIfOwnerMatch: シンボリックリンクを許可(所有者が同じ場合のみ)
# -Indexes: ディレクトリ一覧の表示を無効化(セキュリティ対策)
Options +SymLinksIfOwnerMatch -Indexes

# デフォルトで表示するファイルをindex.phpに設定
DirectoryIndex index.php

# mod_rewriteモジュールが利用可能な場合の設定
<IfModule mod_rewrite.c>
   # URLの書き換え機能を有効化
   RewriteEngine On
   
   # ベースとなるURLパスを設定(/laravel-d01/以下のURLに対してルールを適用)
   RewriteBase /laravel-d01/
   
   # ディレクトリ一覧の表示を明示的に無効化(追加のセキュリティ対策)
   Options -Indexes
   
   # publicディレクトリへのアクセスは書き換えずにそのまま通す
   # 例:/laravel-d01/public/css/style.css → そのままアクセス可能
   RewriteRule ^public/ - [L]
   
   # ルートへのアクセス(/laravel-d01/)をpublic/index.phpへ転送
   # [L]フラグで以降のルールは適用しない
   RewriteRule ^$ public/index.php [L]
   
   # 上記以外のすべてのリクエストをpublicディレクトリ配下に転送
   # 例:/laravel-d01/about → /laravel-d01/public/about
   RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

laravel-dir/public/.htaccess

# PHPの設定
AddHandler application/x-httpd-php .php

# 基本設定
Options +SymLinksIfOwnerMatch
DirectoryIndex index.php

# mod_rewriteの設定
<IfModule mod_rewrite.c>
    RewriteEngine On
    
    # 実ファイルが存在する場合はそのまま表示
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    # それ以外はindex.phpにリダイレクト
    RewriteRule ^ index.php [L]
</IfModule>

本番環境にNPMをインストールしない

本番環境では、できるだけサーバー負荷を軽減し、セキュリティリスクも減らすために不要なソフトウェアをインストールしない方が良いです。

NPMやNode.jsは通常、フロントエンドのビルドにしか使わないため、本番環境には必須ではありません。

そのため、開発環境で必要なビルドを完了させ、生成されたファイルのみを本番環境にアップロードすることで、シンプルかつ安全な運用が可能になります。

参考サイト

必ずしも本番環境のサーバーにNPMのインストールは必要ないと思います。
開発環境でNode.jsのビルドを行い、作成されたJavaScriptファイルをアップロードするのも手です。

https://chigusa-web.com/blog/sakura-laravel/
【GTM】サンクスページがないフォームの計測

フォーム送信完了のイベントの作成

タグの作成

  • 名前:問い合わせ完了2
  • タグの種類:Google アナリティクス: GA4 イベント
  • イベント名:generate_lead
  • イベントパラメータ
    • イベントパラメータ:form_type、値:contact2
    • イベントパラメータ:form_complete_count、値:1

トリガーの設定

  • 名前:問い合わせ完了2
  • トリガーのタイプ:フォームの送信
  • 発生場所:一部のフォーム
  • 条件:Page URL 含む p=11243(※該当ページ)

注意)問い合わせが完了していない場合でも送信されればカウントされてしまいます

サンクスページを作成し、イベントの作成をする(プラグインを使用)方法がオススメです

GA4のキーイベントの設定でgenerate_leadを登録して、1回のセッションで1回のカウントを設定していると
キーイベントの回数としては正しくカウントされます

フォーム到達イベントの作成

タグの設定

  • 名前:問い合わせフォーム到達2
  • タグの種類:Google アナリティクス: GA4 イベント
  • イベント名:form_arrival
  • イベントパラメータ
    • イベントパラメータ:form_type、値:contact2
    • イベントパラメータ:form_arrival_count、値:1

トリガーの設定

  • 名前:問い合わせフォーム到達2
  • トリガーのタイプ:要素の表示
  • 選択方法:CSSセレクタ
  • 要素セレクタ:wpcf7-f11247-p11243-o1 > form > p:nth-child(6) > input(※該当のセレクタ)
  • 起動するタイミング:1ページにつき1度
  • 条件:Page URL 含む p=11243(※該当ページ)

要素セレクタの取得

該当要素のうえで右クリック>Copy>Copy selectorで内容をコピーできます


    【Googleタグマネージャー】バナー表示イベント

    バナークリックイベントの作成

    ↓ページ下部のようなIDが付与されているバナーの表示イベントを考えます。

    ▼Googleタグマネージャーの変数より【Click Element】があるか確認、なければ追加します

    タグの作成

    下記記事のボタンAクリックをコピーして作成します

    https://ntorelabo.com/?p=11193

    ▼コピーした内容のイベント名を記事中バナークリック、イベントパラメータのcta_idの値を取得したIDに変更します

    トリガーの作成

    ▼コピーした内容のイベント名を記事中バナークリック、idの値をcta_bnr_a *に変更します

    プレビューで確認

    GA4のレポート>リアルタイムのイベント数より表示を確認し、イベント公開します

    バナー表示イベントの作成

    タグの設定

    • 名前:記事中バナー表示
    • タグの種類:Google アナリティクス: GA4 イベント
    • イベント名:cta_view
    • イベントパラメータ
      • イベントパラメータ:click_id、値:cta_bnr_a
      • イベントパラメータ:cta_view_count、値:1

    トリガーの設定

    • 名前:記事中バナー表示
    • トリガーのタイプ:要素の表示
    • 選択方法:CSSセレクタ
    • 要素セレクタ:#cta_bnr_a
    • 起動するタイミング:1要素につき1度

    ※視認の最小割合…要素の何割が表示されればタグを動かかす(デフォルト50%)

    カスタム定義

    • 指標名:cta_view_count
    • イベントパラメータ:cta_view_count
    • 測定単位標準

    <バナー>

    【CSS】flexボックスでjustify-content: center;だけど子要素は左寄せにしたい場合

    ↑下の行を左寄せにしたい

    display: grid;

    display: flex;ではなくdisplay: grid;にする

    .grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, 80px);
    justify-content: center;
    max-width: 400px;
    grid-gap: 30px;
    background: #f2f2f2;
    padding: 8px;
    }

    参考サイト:https://zenn.dev/kibe/articles/f093495a22b88c

    WordPressでdrawer.js実装

    CDN読み込み

    公式サイト:
    https://git.blivesta.com/drawer

    ▼一部参考

    https://www.miso.blog/jquery-drawer

    公式サイトよりCDNの記述をコピーしてheadタグ内に張り付け

    ▼functions.php

    <?php
    add_action('wp_head', function () {
    ?>
    <!-- drawer.css -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/drawer/3.2.2/css/drawer.min.css">
    <!-- jquery & iScroll -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/iScroll/5.2.0/iscroll.min.js"></script>
    <!-- drawer.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/drawer/3.2.2/js/drawer.min.js"></script>
    <!-- bootstrap(ドロップダウンメニューにするなら必要) -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <?php 
    });

    各ファイルマークアップ

    ▼header.php

    <!DOCTYPE html>
    <html lang="ja">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta name="description" content="<?php bloginfo( 'description' )?>">
      <title><?php bloginfo( 'name' ); ?></title>
      <?php wp_head(); ?>
    </head>
    <body class="drawer drawer--right drawer--navbarTopGutter">
        <header class="drawer-navbar drawer-navbar--fixed" role="banner">
        <div class="drawer-container">
          <div class="drawer-navbar-header">
            <a class="drawer-brand" href="<?php echo home_url(); ?>"><?php bloginfo( 'name' ); ?></a>
            <button type="button" class="drawer-toggle drawer-hamburger">
              <span class="sr-only">toggle navigation</span>
              <span class="drawer-hamburger-icon"></span>
            </button>
          </div>
        </div>    
        <nav class="drawer-nav" role="navigation">
          <!-- メニューの読み込み -->
          <?php wp_nav_menu( array( 
            'theme_location' => 'my-drawer', 
            'menu_class' => 'drawer-menu', 
            'container' => false, 
            'depth' => 1,
            'add_li_class' => 'nav-item', // liタグへclass追加
            'add_a_class' => 'drawer-menu-item' // aタグへclass追加 
            ) ); ?>
        </nav>
        </header>
        <main role="main">

    下記サイトを参考にナビゲーションメニューの要素にクラス付与

    ▼functions.phpに追記

    1. ナビゲーションメニューの要クラス付与のためのフィルターイベント
    2. スタイル調節のためのCSS
    3. Drawerを動かすために、jQueryのコード
    // wp_nav_menuのliにclass追加
    function add_additional_class_on_li($classes, $item, $args)
    {
    if (isset($args->add_li_class)) {
    $classes['class'] = $args->add_li_class;
    }
    return $classes;
    }
    add_filter('nav_menu_css_class', 'add_additional_class_on_li', 1, 3);
    
    // wp_nav_menuのaにclass追加
    function add_additional_class_on_a($classes, $item, $args)
    {
    if (isset($args->add_li_class)) {
    $classes['class'] = $args->add_a_class;
    }
    return $classes;
    }
    add_filter('nav_menu_link_attributes', 'add_additional_class_on_a', 1, 3);
    
    add_action('wp_head', function () {
    ?>
    <!-- drawer.css -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/drawer/3.2.2/css/drawer.min.css">
    <!-- jquery & iScroll -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/iScroll/5.2.0/iscroll.min.js"></script>
    <!-- drawer.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/drawer/3.2.2/js/drawer.min.js"></script>
    <!-- bootstrap(ドロップダウンメニューにするなら必要) -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <style>
    .drawer-navbar {			
    left: 0;
    }
    .drawer-hamburger {
    padding: calc(1.875rem - 13px) .75rem;
    }
    </style>
    <script>
    jQuery(function ($) {
    $(document).ready(function() {
    $('.drawer').drawer();
    });
    });
    </script>
    <?php 
    });

    参考サイト)wp_nav_menuでliやa要素にclassを追加する方法
    https://zenn.dev/minnanowp/articles/823e3eabd24f20

    ▼footer.php

    </main>
    <?php wp_footer(); ?>
    <script>
    jQuery(function ($) {
    $(document).ready(function() {
    $('.drawer').drawer();
    });
    });
    </script>
    </body>
    </html>
    【WordPress】カラーパレット追加方法

    【Wordpress】カラーパレット追加方法

    ▼functions.php

    function my_wp_theme_json_data_theme( $theme_json ){
        $new_data['version'] = 2;
        // カラーパレット カスタマイズ 既存パレットに追加(単色)
        $new_data['settings']['color']['palette'] = array(
            array(
                'name'  => esc_attr__( 'Primary', 'theme_domain' ),
                'slug'  => 'primary',
                'color' => '#f4f4f4',
            ),
            array(
                'name'  => esc_attr__( 'Accent', 'theme_domain' ),
                'slug'  => 'accent',
                'color' => '#cd162c',
            )
        );
        return $theme_json->update_with( $new_data );
    }
    add_filter( 'wp_theme_json_data_theme', 'my_wp_theme_json_data_theme' );

    ▼追加CSS

    .has-primary-color {
    	color: #f4f4f4;
    }
    .has-primary-background-color {
    	background-color: #f4f4f4;
    }
    .has-primary-border-color {
    	border-color: #f4f4f4;
    }
    .has-accent-color {
    	color: #cd162c;
    }
    .has-accent-background-color {
    	background-color: #cd162c;
    }
    .has-accent-border-color {
    	border-color: #cd162c;
    }

    上記の画像ようにデフォルトに追加できまあ

    【Googleタグマネージャー】ボタンのHTML要素ID属性からイベント設定

    クリック対象にID付与する理由

    Googleタグマネージャーでボタンのクリック計測するとき、IDを付与することにより正確に計測が可能です

    WordPress編集画面でボタンにIDを付与する

    <div class="wp-block-snow-monkey-blocks-buttons smb-buttons" id="cta_btn_a"><!-- wp:snow-monkey-blocks/btn -->
    <div class="wp-block-snow-monkey-blocks-btn smb-btn-wrapper"><a class="smb-btn" href=""><span class="smb-btn__label">Button-A</span></a></div>
    <!-- /wp:snow-monkey-blocks/btn --></div>

    Googleタグマネージャーで設定する

    変数の設定

    ▼変数から「Click Element」を選択

    ※「Click Element」…HTMLの要素を取得できます

    タグの設定

    ▼下記の通り設定

    • 名前:ボタンAクリック
    • タグの種類:Googleアナリティクス:GA4イベント
    • 測定ID:GA4測定ID
    • イベント名:cta_click
    • イベントパラメータ
      (ボタンのIDごとにクリック数をカウントできるように設定)
      • cta_id (cta_btn_a)
      • cta_click_count (1)

    トリガーの設定

    • 名前:ボタンAクリック
    • トリガーのタイプ:クリック – すべての要素
    • このトリガーの発生場所:一部のクリック
    • イベント発生時にすべての条件がtrueの場合にこのトリガーを配置します:
      Click Element / CSS セレクタに一致する / #cta_btn_a*
      (※上記ボタンAのHTMLコードを参照)

    入力したら右上の保存をクリック

    プレビューで確認

    上記ボタンAをクリックするとぼたんAクリックがTags Firedに移動することが確認できます

    GAで確認

    「レポート」の「リアルタイム」の「イベント」のカードでcta_clickを確認できます

    さらにcta_clickを開くと設定した各パラメータの表示も確認できます

    カスタム定義の設定

    ▼カスタムディメンションの設定でGTAのイベントパラメータからコピーして貼り付ける

    ▼同様にカスタム指標の設定も下記の通りする

    ※即手単位は「標準」

    【Googleタグマネージャー】内部リンククリックイベント作成手順

    1)組み込み変数の設定

    ▼Googleタグマネージャーで変数を選択し組み込み変数の設定をクリック

    ▼Click URLとClick Textを追加

    2)タグの作成

    タグの設定

    • 名前:内部リンククリック(任意のもの)
    • タグの種類:Google アナリティクス: GA4 イベント
    • イベント名:internal_link_click(任意のもの)
    • イベントパラメータ
      • イベントパラメータ:click_url、値:Click URL
      • イベントパラメータ:click_text、値:Click Text
      • イベントパラメータ:internal_link_click_count、値:1

    トリガーの設定

    • トリガーの名前:内部リンククリック
    • トリガーのタイプ:クリック- リンクのみ
    • このトリガーの発生場所:一部のリンククリック
      Click URL 含む ドメイン

    3)確認

    Googleタグマネージャーのプレビュー

    GTMのプレビューで内部リンククリックがTags Firedに移動されているのを確認

    Googleアナリティクスのイベントでの設定

    ▼Googleアナリティクスで設定を確認
    →レポート→リアルタイム→internal_link_clickを選択

    • イベントパラメータ:click_url、値:Click URL
    • イベントパラメータ:click_text、値:Click Text
    • イベントパラメータ:internal_link_click_count、値:1

    上記項目が確認できます

    カスタムディメンション、カスタム指標の設定

    レポートで表示できるようカスタムディメンション、カスタム指標の設定を設定します

    ▼右下管理ボタンを選択しカスタム定義をクリック

    →Googleタグマネージャーよりイベントパラメータの内容をコピーして貼り付けます

    【Google Tag Manager】サンクスページ到達イベントの作成

    準備

    今回はプラグイン「コンタクトフォーム7」でフォームを作成、サンクスページを下記記事参考で作成しました

    https://wpmake.jp/contents/plugin/contact-form7/thanks-page

    タグの作成

    ▼サイドメニューのタグを選択し新規をクリック

    ▼タグの設定を下記の通り行います

    • タグの名前:問い合わせ完了
    • タグの種類:Google アナリティクス: GA4 イベント
    • 測定ID:GA4測定ID(GA4測定IDで変数に登録済みのものを使用)
    • イベント名:genarate_lead
    • イベントパラメータ
      • form_type contact:同じgenerate_leadで問い合わせで種類を分けたい場合を想定※1つであればなくても問題なし
      • form_complete_count:問い合わせ完了数のための指標

    トリガーの設定

    ▼新規でトリガーを作成していきます

    ▼トリガーの設定を下記の通り行います

    サンクスページのパスと直前のページ(問い合わせフォーム)のパスをそれぞれ設定

    ※referrer…直前のページ

    お問い合わせフォーム到達イベント作成

    問い合わせフォーム到達のイベントの作成も同様にしておき、

    ▼タグの設定

    タグの種類Google アナリティクス: GA4 イベント
    測定IDGoogle アナリティクス測定 ID
    イベント パラメータform_type (contact)
    form_arrival (1)

    ▼トリガーの設定

    トリガーのタイプページビュー
    このトリガーの発生場所一部のページビュー
    イベント発生時にこれらすべての条件が true の場合にこのトリガーを配信しますPage Path 含む 問い合わせフォームページパス

    プレビューでイベント発火を確認

    イベント作成したところプレビューにてイベントが発火しない問題が発生

    ▼WordPress管理画面のメニュー設定のパーマリンクから、パーマリンク構造を「基本」から「投稿名」にして、改めてトリガーのページパスを変更したところ発火しました。

    今まで作成したページのURLの変更が困るため、ほかの解決策としてトリガーの設定で「Page Path」から「Page URL」に変更したところ正しく発火しました

    GoogleアナリティクスGA4

    指標、ディメンション

    • 指標…数字
    • ディメンション…分析軸(指標の切り口)

    代表的な指標

    指標名内容
    アクティブユーザ数ユニークユーザー数
    表示回数ページビュー
    セッションWebサイトへの訪問回数
    エンゲージメント率ユーザーにとって価値のある訪問の割合
    ※10秒以上閲覧 or 2ページ以上閲覧 or CVイベント発生
    イベント数Webサイトで発生したユーザーの行動すべて

    代表的なディメンション

    指標名内容
    年齢、性別
    デバイスカテゴリデスクトップ、モバイル、タブレット
    デフォルトチャネルグループユーザーが訪問した際の大まかな参照元
    (自然検索、他サイトからの訪問、広告)
    ページパスとスクリーンクラスページパスはURLのドメイン部分を除いたもの
    ※スクリーンクラスはアプリのためのディメンション
    ランディングページユーザーがWebサイトに訪れた時に最初に見たページ

    カスタム指標、カスタムディメンション

    もともと備わっていない、独自に設定した指標、ディメンション

    イベント

    Webサイト内でのユーザーの行動
    …訪問、ページビュー、クリック

    • 自動収集イベント
    • 拡張計測機能イベント
    • 推奨イベント
    • カスタムイベント

    自動収集イベント

    イベント名発生タイミング※自動で収集
    first_visitユーザが初めてWebサイトに訪問
    session_startユーザがWebサイトに訪問
    page_viewユーザがページを開いた
    user_engagementWebサイトが選択された状態が1秒以上続いた

    拡張計測機能イベント

    イベント名発生タイミング※自動で収集
    scrollユーザがページの90%地点までスクロールした
    clickユーザが外部リンクをクリック
    view_search_resultsユーザがWebサイト内の検索結果を表示した
    file_downloadユーザがファイルをクリック

    推奨イベント

    自身で登録する必要がある

    決められた名前を使用

    イベント名発生タイミング※自動で計測されない
    genarate_leadユーザがお問い合わせフォームから送信した
    sign_upユーザが会員登録した
    loginユーザがログインした
    purchaseユーザが購入した

    カスタムイベント

    自身で登録する必要がある

    任意の名前を使用

    ↓例

    イベント名※任意…下記は例として発生タイミング※自動で計測されない
    cta_viewユーザがバナーやボタンを表示した
    cta_clickユーザがバナーやボタンクリック
    【Next.js】ライブラリ使わないでカルーセルスライダー

    demo(Next.jsの静的ビルドファイルをiframeで表示したもの)

    Next.jsを使って無限ループ機能付きのシンプルなカルーセルを実装します(画像スライドショーの基本的な機能をおさえつつ、メンテナンスしやすいコードを目指します)

    このカルーセルには以下の機能が含まれています:

    • ✨ 無限ループスライド
    • 🎯 自動再生機能
    • 🎨 矢印ナビゲーション
    • 📍 インジケーター
    • 📱 レスポンシブ対応

    ソースファイル

    my-nextjs-app/
    ├── src/
    │   ├── app/
    │   │   └── page.tsx                    # カルーセルを使用するページ
    │   ├── components/
    │   │   └── SimpleCarousel.tsx          # カルーセルコンポーネント
    │   └── styles/
    │       └── simpleCarousel.module.css   # カルーセル用スタイル

    page.tsx

    /**
     * カルーセルページコンポーネント
     */
    
    import React from 'react';
    import SimpleCarousel from '@/components/simpleCarousel';
    
    export default function CarouselPage() {
      // スライドのデータ定義
      // - 外部のAPIから取得する場合はここを修正
      const slides = [
        {
          id: 1,
          src: "https://picsum.photos/800/400",
          alt: "First slide"
        },
        {
          id: 2,
          src: "https://picsum.photos/800/400?random=1",
          alt: "Second slide"
        },
        {
          id: 3,
          src: "https://picsum.photos/800/400?random=2",
          alt: "Third slide"
        }
      ];
    
      return (
        <div className="container mx-auto p-4">
          <SimpleCarousel 
            slides={slides}
            autoPlayInterval={3000} // 自動再生の間隔(ミリ秒)
            showArrows={true}      // 矢印ナビゲーションの表示
            showIndicators={true}  // インジケーターの表示
          />
        </div>
      );
    }

    simpleCarousel.tsx

    /**
     * シンプルなカルーセルコンポーネント
     * 
     * 特徴:
     * - 無限ループ機能
     * - 自動再生
     * - 矢印ナビゲーション
     * - インジケーター
     * - レスポンシブ対応
     */
    
    'use client'; // クライアントサイドでの実行を指定
    
    import React, { useState, useRef, useEffect, useCallback } from 'react';
    import styles from '@/styles/simpleCarousel.module.css';
    
    // スライドデータの型定義
    interface SlideData {
      id: number;    // スライドの一意のID
      src: string;   // 画像のURL
      alt: string;   // 代替テキスト
    }
    
    // コンポーネントのプロパティの型定義
    interface CarouselProps {
      slides: SlideData[];        // スライドデータの配列
      autoPlayInterval?: number;  // 自動再生の間隔(ミリ秒)
      showArrows?: boolean;      // 矢印ナビゲーションの表示/非表示
      showIndicators?: boolean;  // インジケーターの表示/非表示
    }
    
    const SimpleCarousel: React.FC<CarouselProps> = ({
      slides,
      autoPlayInterval = 3000,
      showArrows = true,
      showIndicators = true
    }) => {
      // State管理
      const [currentSlide, setCurrentSlide] = useState<number>(slides.length);  // 現在のスライドインデックス
      const [isTransitioning, setIsTransitioning] = useState(false);           // トランジション中かどうか
      const slideContainerRef = useRef<HTMLDivElement>(null);                  // スライドコンテナのref
    
      // 無限ループのためのスライド配列を作成(前後に1セットずつ追加)
      const extendedSlides = [...slides, ...slides, ...slides];
    
      // スライド変更のハンドラー(useCallbackでメモ化)
      const handleSlideChange = useCallback((direction: 'next' | 'prev'): void => {
        if (isTransitioning) return;  // トランジション中は処理をスキップ
        
        setIsTransitioning(true);
        if (direction === 'next') {
          setCurrentSlide(prev => prev + 1);
        } else {
          setCurrentSlide(prev => prev - 1);
        }
      }, [isTransitioning]);
    
      // 自動再生のための効果
      useEffect(() => {
        const timer = setInterval(() => {
          handleSlideChange('next');
        }, autoPlayInterval);
    
        // クリーンアップ関数
        return () => clearInterval(timer);
      }, [autoPlayInterval, handleSlideChange]);
    
      // トランジション終了時の処理
      useEffect(() => {
        if (!isTransitioning) return;
    
        const transitionEndHandler = () => {
          setIsTransitioning(false);
          
          // 最後のクローンまで来た場合、最初に戻す
          if (currentSlide >= slides.length * 2) {
            setCurrentSlide(slides.length);
          }
          // 最初のクローンより前に来た場合
          else if (currentSlide < slides.length) {
            setCurrentSlide(slides.length * 2 - 1);
          }
        };
    
        const container = slideContainerRef.current;
        container?.addEventListener('transitionend', transitionEndHandler);
    
        // クリーンアップ関数
        return () => {
          container?.removeEventListener('transitionend', transitionEndHandler);
        };
      }, [currentSlide, slides.length, isTransitioning]);
    
      // 特定のスライドに直接移動する関数
      const goToSlide = (index: number): void => {
        if (isTransitioning) return;
        setIsTransitioning(true);
        setCurrentSlide(index + slides.length);
      };
    
      // 実際のスライドインデックスを計算(表示用)
      const actualSlideIndex = ((currentSlide % slides.length) + slides.length) % slides.length;
    
      return (
        <div className={styles.carousel}>
          <div className={styles.slideContainer} ref={slideContainerRef}>
            {/* スライドラッパー */}
            <div 
              className={styles.slideWrapper}
              style={{ 
                transform: `translateX(-${currentSlide * 100}%)`,
                transition: isTransitioning ? 'transform 0.5s ease-in-out' : 'none'
              }}
            >
              {/* スライドの表示 */}
              {extendedSlides.map((slide, index) => (
                <div 
                  key={`${slide.id}-${index}`} 
                  className={styles.slide}
                  style={{ position: 'relative', overflow: 'hidden', width: '100%', height: '400px' }}
                >
                  {/* eslint-disable-next-line @next/next/no-img-element */}
                  <img
                    src={slide.src}
                    alt={slide.alt}
                    style={{
                      position: 'absolute',
                      top: 0,
                      left: 0,
                      width: '100%',
                      height: '100%',
                      objectFit: 'cover'
                    }}
                  />
                </div>
              ))}
            </div>
    
            {/* 矢印ナビゲーション */}
            {showArrows && (
              <>
                <button
                  onClick={() => handleSlideChange('prev')}
                  className={`${styles.arrowButton} ${styles.prevButton}`}
                  aria-label="Previous slide"
                  disabled={isTransitioning}
                >
                  ←
                </button>
                <button
                  onClick={() => handleSlideChange('next')}
                  className={`${styles.arrowButton} ${styles.nextButton}`}
                  aria-label="Next slide"
                  disabled={isTransitioning}
                >
                  →
                </button>
              </>
            )}
    
            {/* インジケーター */}
            {showIndicators && (
              <div className={styles.indicators}>
                {slides.map((_, index) => (
                  <button
                    key={index}
                    onClick={() => goToSlide(index)}
                    className={`${styles.indicator} ${
                      actualSlideIndex === index ? styles.indicatorActive : ''
                    }`}
                    aria-label={`Go to slide ${index + 1}`}
                    disabled={isTransitioning}
                  />
                ))}
              </div>
            )}
          </div>
        </div>
      );
    };
    
    export default SimpleCarousel;

    simpleCarousel.module.css

    /* styles/simpleCarousel.module.css */
    .container {
        max-width: 1200px;
        margin: 0 auto;
        padding: 2rem 1rem;
      }
      
      .title {
        font-size: 1.5rem;
        font-weight: bold;
        margin-bottom: 2rem;
      }
      
      .carousel {
        position: relative;
        width: 100%;
        max-width: 48rem;
        margin: 0 auto;
        overflow: hidden;
      }
      
      .slideContainer {
        position: relative;
        overflow: hidden;
        border-radius: 0.5rem;
        aspect-ratio: 2/1;
      }
      
      .slideWrapper {
        position: absolute;
        display: flex;
        width: 100%;
        height: 100%;
      }
      
      .slide {
        flex: 0 0 100%;
        width: 100%;
        height: 100%;
      }
      
      .slide img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
      
      .arrowButton {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        background-color: rgba(255, 255, 255, 0.8);
        border-radius: 50%;
        padding: 0.5rem;
        cursor: pointer;
        border: none;
        z-index: 1;
      }
      
      .arrowButton:hover {
        background-color: rgb(255, 255, 255);
      }
      
      .prevButton {
        left: 1rem;
      }
      
      .nextButton {
        right: 1rem;
      }
      
      .indicators {
        position: absolute;
        bottom: 1rem;
        left: 50%;
        transform: translateX(-50%);
        display: flex;
        gap: 0.5rem;
        z-index: 1;
      }
      
      .indicator {
        width: 0.5rem;
        height: 0.5rem;
        border-radius: 50%;
        background-color: rgba(255, 255, 255, 0.5);
        border: none;
        cursor: pointer;
        padding: 0;
      }
      
      .indicatorActive {
        background-color: rgb(255, 255, 255);
      }

    注意点と対策
    (Hot Module Replacement: HMR)に関連するエラー

    Next.jsの開発環境でのホットリロード(Hot Module Replacement: HMR)に関連するエラーが発生します。

    エラーの原因

    1. CSSモジュールを使用している際に、HMRがCSSファイルを更新しようとする
    2. 古いスタイルシートを削除しようとする際に、すでに要素が削除されているためエラーが発生
      (無限にスライド流れるようクローンを作成する際の記述)

    対策

    グローバルCSSとして管理

    /* globals.css */
    .carousel { ... }

    CSS-in-JSライブラリの使用

    import styled from 'styled-components';

    next.config.jsでの設定

    module.exports = {
    webpack: (config) => {
    // HMRの設定をカスタマイズ
    return config;
    }
    }
    【WordPress】アクションフック、フィルターフック使用方法

    アクションフックとは

    処理の追加が可能です

    functions.php で add_action や add_filter を記述していきます

    ※本サイトはWPcodeにて行いました

    参考サイト:https://idasalon.com/?p=250#index_id3

    add_action('フック名', function () {
        実行する処理
    });

    ↓実際このページでコンテンツ開始部分に表示

    add_action('arkhe_before_entry_content', function () {
        if (is_single(10922)) {
        ?>
        <p style="font-size: 1.2rem; background: #eee; padding: 4px 10px;">※アクションフックにて表示しています</p>
        <?php
        }
    });

    https://arkhe-theme.com/ja/manual/hooks

    https://arkhe-theme.com/ja/manual/hooks

    フロントページにタグクラウドを追加

    フックを使えば「ホームページの表示」を「最新の投稿」にしていてもカスタマイズできます

    add_action('arkhe_start_front_main', function () {
    	$args = array(
    		'smallest' => 1,
    		'largest' => 1,
    		'unit' => 'em',
    		'number' => 30,
    		'orderby' => 'count',
    		'order' => 'DESC',
    		'format' => 'list'
    	);
    	$args['taxonomy'] = array('post_tag','category');
    	wp_tag_cloud( $args );
    	?>
    	<style>
    		ul.wp-tag-cloud {
    			display: flex;
    			flex-wrap: wrap;
    			margin-bottom: 2.5rem;
    			gap: 8px;
    			padding-left: 0;
    		}
    		.wp-tag-cloud li {
    			list-style: none;
    		}
    		.wp-tag-cloud li a {
    			background: #f7f7f7;
    		}
    	</style>
    	<?php
    });
    https://norando.net/wordpress-tag-cloud
    「Googleタグマネージャー」アカウントを作る→「GA4」を設定する方法

    Google Tag Manager(GTM)とは

    Google Tag Managerで扱うタグとはWebサイトとマーケティングツール間で情報をやりとりするためのコードです

    Googleアナリティクス、Google広告など、、

    <script></script>のような形式で記述される場合が多いです

    Googleタグマネージャーを使用すればhtmlの編集をせずにタグの管理が可能です

    タグ:タグ
    トリガー:タグを動かすきっかけ
    変数:タグに追加で情報を設定

    GTMアカウント作成

    Googleタグマネージャーで検索

    アカウントの各項目を設定

    • アカウントは会社名や個人を特定できるもの
    • コンテナはドメイン名(Webサイトごとに作成する場合があります)

    【Google拡張機能】Tag Assistant Companion

    • タグの動作確認
    • Googleタグマネージャーのプレビュー機能使用時に開発者ツールが使える

    ※Tag Assistant Legacyのサポートが終了したためTag Assistant Companionを使用

    【Google拡張機能】Adswerve

    Googleタグマネージャーの仮想環境を作れる(管理権限のないサイトでも可能)

    【WordPressサイト】Googleタグマネージャー導入方法

    方法(1)プラグイン「GTM4WP」での設定方法

    1)GTM4WPをインストール

    新規プラグイン追加で「gtm4wp」と検索

    2)GoogleタグマネージャーIDを張り付ける

    Container code ON/OFFがバグでOFFになるので、ONにして再度保存しなおす

    方法(2)プラグイン「WPcode」での設定方法

    ▽Googleタグマネージャーより貼り付けるコードをコピー

    ▽ワードプレス管理画面の「コードスぺニット」→「ヘッダーとフッター」をクリックして、コピーした内容を張り付け

    ※オリジナルテーマの仕様等WordPressをカスタムしている場合「wp_head()」「wp_body_open()」がないと挿入されません

    How To Add Google Tag Manager To WordPress 
    https://wpcode.com/how-to-add-google-tag-manager-to-wordpress

    GoogleタグマネージャーにGA4を設定する方法

    1)GA4のアカウント、プロパティを作成する

    https://ntorelabo.com/?p=10699#i

    2)GA4の測定IDを定数に登録する

    「GA4の測定ID」とは

    イベントの設定で非常に使用します

    →定数でGTMに登録しワンクリックで使えるようにしておくと便利です

    〇Googleアナリティクスで測定IDを確認

    ↓Googleアナリティクスで「管理(歯車アイコン)」→「データストリーム」クリックすると詳細内容に測定IDが表示されます

    〇Googleタグマネージャーの画面で「定数」として登録

    ↓「変数」→「新規」をクリック

    ↓Googleタグマネージャーの画面で変数として登録

    ↓定数を選択

    ↓測定IDを張り付ける

    3)「GA4設定タグ」を作成

    「GA4設定タグ」とは

    • イベント計測の基本となるタグ
    • 計測するすべてのページで発火

    GA4設定タグ作成手順

    サイドのメニューからタグから新規を選択

    タグのタイプを「Googleアナリティクス」「Googleタグ」選択

    先ほど変数に登録したGoogleアナリティクスの測定IDを選択

    トリガーは「Initialization – All Pages」を選択

    (公式推奨)Googleアナリティクスのタグは全てのページに埋め込む必要があるため

    (参考サイト)
    [GTM] GA4設定タグとイベントタグの関係
    https://ayudante.jp/column/2023-07-14/12-00

    公開で設定完了

    Googleアナリティクス導入

    Googleアナリティクスとは

    無料で使用可能で、非常に高機能なツールです。

    サイト全体のアクセス数、ページ別、流入元の状況など、数多くのデータが確認できます。

    UAとGA4

    GA4(第四世代)が2020年登場、UA(従来のGoogleアナリティクス)は2023年7月にサポートが終了しました。

    • UAはWebサイトのページ単位の計測
    • GA4はアクセス解析がユーザー中心 例)複数デバイスでもユーザを認識可能

    導入手順

    Googleアナリティクスアカウントの作成(事前にGoogleアカウントの作成外必要)

    データ保持期間を14か月に変更する

    プロパティの設定

    アカウント名会社名、名前(半角アルファベット)
    プロパティ名分析したいサイト(ドメイン)の名前
    ※Webサイト単位
    レポートのタイムゾーン国内向けのサイトの場合日本に変更
    通貨国内向けのサイトの場合日本円に変更

    データストリームの設定

    ウェブサイトのURLアクセス解析を行いたいサイトのURL
    ストリーム名サイトの名称

    データストリームの作成後測定IDが確認できます。

    トラッキングコード、測定IDについて

    種別書式概要
    トラッキングIDUA-XXXXXXXプロパティを一意に特定するID
    Googleアナリティクスでデータを計測するためにはトラッキングIDが必須
    UAプロパティの計測時に活用するID
    測定IDG-XXXXXXXGA4プロパティの計測時に活用するID

    GA4のアカウント構造

    アカウント1つのアカウントで、最大で50個のプロパティ
    プロパティ1つのWebサイトにつき1つ設定
    プロパティごとに、トラッキングIDが発行されます
    データストリーム複数作成することもできますが、基本的には1つだけ作成

    WebサイトとGoogleアナリティクスとの連携

    下記の手順でタグの内容を確認できます

    対象のストリームを選択し、「ページ下部のタグの実装手順を表示する」をクリック

    「手動でインストール」タブを選択し、

    headタグ内に以下のコードを追加する

    リアルタイムレポートより測定出来ているかの確認

    「レポート」→「リアルタイム ページ」→「過去30日間のページパスとスクリーンクラス」で確認

    ※別のブラウザのタブで該当Webサイトにアクセスしておく

    Webサイト /m/cc/, /m/s/ データストリーム データ収集の設定 測定ID: G-XXXXXXXX URL設定 拡張測定の設定 リアルタイム 過去30分の アクセスデータ 標準レポート 24-48時間後の 集計データ データの流れ: 1. Webサイトからデータ収集 2. データストリームで設定に基づき処理 3. リアルタイムと標準レポートに反映
    GA4 レポートの種類 リアルタイムレポート 過去30分のデータをリアルタイムで表示 主な確認項目: ・アクティブユーザー数 ・過去30分間のページパス ・ユーザー属性 ・アクセス元 主な用途: ・設定直後の動作確認 ・現在のアクセス状況確認 ・キャンペーン実施時の即時確認 レポートスナップショット 24-48時間後に利用可能な詳細データ レポートの種類: ・ユーザー ・集客 ・エンゲージメント ・マネタイズ 主な用途: ・詳細なアクセス分析 ・期間ごとの比較 ・改善施策の効果測定
    ホームページ制作の流れ

    ホームページ制作フロー

    • ホームページ作成の依頼をうける
    • 業務内容をヒアリングする
      • サーバ契約、ドメインの取得
      • ワイヤーフレーム、デザインカンプ、参考のサイト、ロゴ、画像、テキストの有無
    • 制作の流れを共有確認
    • デザインがない場合
      • 既にWordPressをインストールしてあり、WordPressログイン情報、FTP情報を教えていただき制作に入る。

    Webサイトが表示される仕組み

    1. WebブラウザからURLを指定
    2. DNSサーバーがドメイン名からIPアドレス

    サーバーとドメイン

    ドメインとは

    ドメインは英語で「領土」「領域」「範囲」を意味しており、Web上での住所といえます。

    ドメインとURLの違い

    URLとは、インターネット上にアップされたすべてのウェブサイトにはURLがあてられており、ブラウザ上でURLを入力することにより、サイトの閲覧が可能になります。

    WebサイトのURLは基本的に以下の3つの要素から構成されています。

    • スキーム:https://
    • ドメイン:○○○.com
    • サブディレクトリ:?p=10440

    https://ntorelabo.com/?p=10440

    URLの核となる部分がドメイン

    独自ドメインとサブドメイン

    独自ドメインは、基本的に同じ名前のものは存在せず、取得後に変更することもできません。サブドメインとは、独自ドメインを分割する場合に使用されます。

    例)Yahoo!ニュース

    Yahoo!のURLをみてみると「https://www.yahoo.co.jp/」の「yahoo.co.jp」にあたる部分が独自ドメインとなります。

    一方Yahoo!ニュースでは「https://news.yahoo.co.jp/」というドメイン名になっていて、独自ドメイン「yahoo.co.jp」に加えて「news」が追加されていることがわかります。この「news」にあたる部分がサブドメインになります。

    https://news.yahoo.co.jp/
         ↑サブドメイン

    独自ドメインの活用法

    • 専用のメールアドレスをりようできる
    • SEOで有利に評価される

    サブドメインの活用方法

    • 1つの独自ドメインの下で複数のWebサイトを運用できる → ドメイン費用を抑えることが可能

    サブドメインとサブディレクトリ

    【本体ドメイン】…○○○.com
    【サブディレクトリ】…○○○.com/△△/
    【サブドメイン】…△△△.○○○.com

    サブディレクトリ
    サブドメイン
    https://help.sakura.ad.jp/domain/2149/?_gl=1%2Agpspir%2A_gcl_aw%2AR0NMLjE3MTEzNDExNTQuQ2p3S0NBandudi12QmhCZEVpd0FCQ1lRQXliN081cTQ4Rko3dUp2TUhSOUlsZE8zajR6RExHT1ZXZnZiME5ZeE43dW02UTBRajFabUxCb0NxTEVRQXZEX0J3RQ..%2A_gcl_au%2ANTQyNzUyNTA4LjE3MDk1MTI5NjY.
    React でアプリ作成

    StackBlitz

    githubで認証試すが利用できない

    JavaScriptにてtodoアプリ

    未完了のTODO

    完了のTODO

    React VSCode インストール

    参考記事:https://teto-tech.com/article/react-start1

    Node.jsのインストール

    ▼「my-app」を作成 → この中に環境が構築

    npx create-react-app my-app 

    ※作業フォルダにてコマンド実行しました

    ▼作業フォルダを移動

    cd my-app

    ▼編集をリアルタイムで確認

    npm start

    my-app/src/App.jsを編集すると正しく表示されました
    ※Ctrl+Cで終了

    Props分割代入

    分割代入しない場合

    export const Profile = (props) => {
     return (
      <p>私の名前は{props.name}です。{props.age}歳です。</p>
     )

    分割代入する場合

    export const Profile = (props) => {
     // propsを分割代入
     const { name, age } = props;
     return (
      <p>`私の名前は{name}です。{age}歳です。`</p>
     )

    ↓引数propsを渡す段階で分割代入

    export const Profile = ({ name, age }) => {
     return (
      <p>`私の名前は{name}です。{age}歳です。`</p>
     )

    useEffect

      useEffect(() => {
        …
      },[num, ]);

    第二引数に変更がある場合、中の処理が実行

    Reactで作成したアプリをレンタルサーバに公開する方法

    参考サイト:https://zenn.dev/kiriyama/articles/538face511307d

    ▼package.jsonを編集

    homepageという項目を追加しURLを記載

    {
      "homepage": "https://○○",
      "name": "my-app",
      "version": "0.1.0",
      "private": true,
    //省略
    }

    ▼publickフォルダに.htaccessのファイルを作成

    Options -MultiViews
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.html [QSA,L]

    ▼コマンド実行

    npm run build

    作成されたbuildフォルダの中身をアップロード
    ※buildフォルダはアップロードしない

    なぜデプロイ時にnpm run buildが必要なのか?
    https://qiita.com/bell_007/items/e84cd7a11b1d196e8bb4

    デモページ

    →実際Reactにて作成したページ

    【@wordpress/scripts】でインライン単位で文字サイズ色を変更できる(リッチテキストツールバー)オリジナルブロック作成

    パッケージインストール

    npm プロジェクトの初期化

    package.json ファイルを作成します。

    npm init -y

    @wordpress/scriptsのインストール

    (WordPress のブロックエディター用のパッケージ)

    npm install @wordpress/scripts @wordpress/blocks @wordpress/i18n @wordpress/block-editor @wordpress/components @wordpress/data react react-dom

    package.jsonにスクリプトが追記

    {
      "name": "my-theme-custom-block",
      "version": "1.0.0",
      "description": "My first WordPress custom block in a theme",
      "main": "build/index.js",
      "scripts": {
        "build": "wp-scripts build",
        "start": "wp-scripts start"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@wordpress/scripts": "^x.x.x"
      }
    }

    @wordpress パッケージの型定義ファイルインストール

    npm install --save-dev @types/wordpress__blocks
    npm install --save-dev @types/wordpress__block-editor @types/wordpress__components
    npm install @wordpress/data @wordpress/rich-text
    npm install --save-dev @types/react @types/wordpress__rich-text

    webpack

    • ES6+やTypeScriptのコードを古いブラウザでも動作するES5に変換できます。
    • モジュール間の依存関係を自動的に解析し、複数のJavaScriptファイルを1つのファイルにまとめます。
    webpackでのTypeScript処理フロー TypeScript .ts ファイル ts-loader TypeScript → JS Babel ES6+ → ES5 出力 bundle.js

    webpack.config.jsの設定

    webpack.config.jsは、webpackの設定ファイルです。

    webpack.config.js の主要構造 entry アプリケーションの 開始点を指定 output バンドルファイルの 出力先と名前を指定 module.rules ファイルの変換方法を ローダーで指定 plugins 追加の処理や最適化を プラグインで指定 resolve モジュールの解決方法を カスタマイズ mode development, production などの環境を指定

    webpack.config.js

    const defaultConfig = require('@wordpress/scripts/config/webpack.config');
    const path = require('path');
    
    module.exports = {
        ...defaultConfig,
    
        // エントリーポイントの設定
        entry: {
            lead: path.resolve(__dirname, 'wp-content/themes/originaltheme/src/lead/index.tsx'),
        },
    
        // 出力の設定
        output: {
            path: path.resolve(__dirname, 'wp-content/themes/originaltheme/build'),
            filename: '[name].js', // [name] には entry で指定したキーが入る
        },
    
        // ファイルの拡張子を省略できるようにする
        resolve: {
            extensions: ['.ts', '.tsx', '.js']
        },
    
    
        module: {
    
            // ローダーの設定
            rules: [
                {
                    test: /\.tsx?$/,
                    use: 'ts-loader',
                    exclude: /node_modules/
                }
            ]
        }
    };
    npm install ts-loader --save-dev

    tsconfig.json

    {
      "compilerOptions": {
        "target": "es5",                          // 出力するJavaScriptのバージョン
        "module": "commonjs",                     // モジュールシステム
        "strict": true,                           // 厳格な型チェックオプション
        "esModuleInterop": true,                  // ESモジュールとの互換性
        "skipLibCheck": true,                     // ライブラリの型チェックをスキップ
        "forceConsistentCasingInFileNames": true, // ファイル名の大文字小文字の一貫性を強制
        "jsx": "react",                           // JSXのサポート
        "moduleResolution": "node",               // モジュール解決方法
        "resolveJsonModule": true,                // JSONモジュールのインポートを許可
        "outDir": "./build",                      // 出力ディレクトリ
        "rootDir": "./wp-content/themes/originaltheme/src" // ソースファイルのルートディレクトリ
      },
      "include": [
        "wp-content/themes/originaltheme/src/**/*" // コンパイル対象のファイル
      ],
      "exclude": [
        "node_modules"                            // コンパイル対象外のファイル
      ]
    }

    ブロックのソースファイルを作成

    リッチテキストツールバーを使用

    インライン単位で文字サイズ文字色を変更できるブロック

    index.tsx

    import { registerBlockType } from '@wordpress/blocks';
    import { __ } from '@wordpress/i18n';
    import {
        useBlockProps,
        RichText,
        RichTextToolbarButton,
    } from '@wordpress/block-editor';
    import {
        registerFormatType,
        applyFormat,
        removeFormat,
        type RichTextValue
    } from '@wordpress/rich-text';
    import React from 'react';
    
    // ブロックの属性の型定義
    interface BlockAttributes {
        content: string;
    }
    
    // フォーマットの型定義
    interface FormatProps {
        isActive: boolean;
        value: RichTextValue;
        onChange: (value: RichTextValue) => void;
    }
    
    // WPFormat の型定義
    interface WPFormatType {
        name: string;
        title: string;
        tagName: string;
        className: string;
        interactive: boolean;
        edit: (props: FormatProps) => JSX.Element;
    }
    
    // フォーマット名の定義
    const FONT_SIZE_FORMAT = 'custom-format/font-size';
    const TEXT_COLOR_FORMAT = 'custom-format/text-color';
    
    // フォントサイズフォーマットの登録
    const fontSizeFormat: WPFormatType = {
        name: FONT_SIZE_FORMAT,
        title: __('Font Size', 'custom-format'),
        tagName: 'span',
        className: 'custom-font-size',
        interactive: false,
        edit: ({ isActive, value, onChange }: FormatProps) => {
            const fontSizes = ['0.75rem', '1rem', '2rem', '3rem', '4rem'];
    
            // フォントサイズの変更の処理の関数
            const onChangeFontSize = (size: string) => {
                const newFormat = {
                    type: FONT_SIZE_FORMAT,
                    attributes: {
                        style: `font-size: ${size};`,
                    },
                };
    
                if (isActive) {
                    onChange(removeFormat(value, FONT_SIZE_FORMAT));
                }
                onChange(applyFormat(value, newFormat));
            };
    
            return (
                <React.Fragment>
                    {fontSizes.map((size) => (
                        <RichTextToolbarButton
                            key={size}
                            icon="editor-textcolor"
                            title={`${size} ${__('Font Size', 'custom-format')}`}
                            onClick={() => onChangeFontSize(size)}
                            isActive={isActive}
                        />
                    ))}
                </React.Fragment>
            );
        }
    };
    
    // 文字色フォーマットの登録
    const textColorFormat: WPFormatType = {
        name: TEXT_COLOR_FORMAT,
        title: __('Red Text', 'custom-format'),
        tagName: 'span',
        className: 'custom-text-color',
        interactive: false,
        edit: ({ isActive, value, onChange }: FormatProps) => {
    
            // 文字色の変更の処理の関数
            const onToggleColor = () => {
                if (isActive) {
                    onChange(removeFormat(value, TEXT_COLOR_FORMAT));
                } else {
                    const newFormat = {
                        type: TEXT_COLOR_FORMAT,
                        attributes: {
                            style: 'color: red;',
                        },
                    };
                    onChange(applyFormat(value, newFormat));
                }
            };
    
            return (
                <RichTextToolbarButton
                    icon="editor-textcolor"
                    title={__('Red Text', 'custom-format')}
                    onClick={onToggleColor}
                    isActive={isActive}
                />
            );
        }
    };
    
    // フォーマットの登録
    registerFormatType(FONT_SIZE_FORMAT, fontSizeFormat);
    registerFormatType(TEXT_COLOR_FORMAT, textColorFormat);
    
    // ブロックを登録
    registerBlockType<BlockAttributes>('customtheme/cardlead', {
        title: __('カード記事リード文', 'custom-block'),
        icon: 'editor-textcolor',
        category: 'text',
    
        attributes: {
            content: {
                type: 'string',
                source: 'html',
                selector: 'p',
            },
        },
    
        edit: ({ attributes, setAttributes }) => {
            const { content } = attributes;
            const blockProps = useBlockProps({
                className: 'my-custom-class',
                style: {
                    borderTop: '8px solid #ffda00',
                    borderBottom: '8px solid #ffda00',
                    textAlign: 'center' as 'center',
                }
            });
    
            return (
                <div {...blockProps}>
                    <RichText
                        tagName="p"
                        value={content}
                        onChange={(newContent: string) => setAttributes({ content: newContent })}
                        placeholder={__('Select text and choose font size or color...', 'custom-block')}
                        allowedFormats={[
                            'core/bold',
                            'core/italic',
                            FONT_SIZE_FORMAT,
                            TEXT_COLOR_FORMAT
                        ]}
                    />
                </div>
            );
        },
    
        save: ({ attributes }) => {
            const { content } = attributes;
            const blockProps = useBlockProps.save({
                className: 'my-custom-class',
                style: {
                    borderTop: '8px solid #ffda00',
                    borderBottom: '8px solid #ffda00',
                    textAlign: 'center' as 'center',
                }
            });
    
            return (
                <div {...blockProps}>
                    <RichText.Content
                        tagName="p"
                        value={content}
                    />
                </div>
            );
        },
    });

    functions.phpで読み込み

    functions.php

    <?php
    // カスタムブロックの登録
    function my_theme_custom_block_init() {
        // register_block_type()の第一引数は「ドメイン名/ブロック名」でregisterBlockType()の第一引数と一致させる
        register_block_type( 'customtheme/cardlead', array(
            'editor_script' => 'cardlead-script',
        ) );
    }
    add_action( 'init', 'my_theme_custom_block_init' );
    
    // ブロックのスクリプトを読み込む
    function my_theme_custom_block_enqueue_assets() {
        $asset_file_cardlead = include( get_template_directory() . '/build/cardlead.asset.php' );
    
        wp_enqueue_script(
            'cardlead-script',
            get_template_directory_uri() . '/build/cardlead.js',
            $asset_file_cardlead['dependencies'],
            $asset_file_cardlead['version']
        );
    }
    add_action( 'enqueue_block_editor_assets', 'my_theme_custom_block_enqueue_assets' );
    LaravelにてECサイト作成 ログイン情報付与 Bladeコンポーネント Stripe決済

    Laravel基礎

    Laravelのルーティングについてweb.phpの使い方(src/routes/web.php)

    • URLとどのファイルを表示させるか紐づけます
    • URLパラメータの受け取りをします

    Laravelルーティングの処理パターン routes/web.php ブラウザリクエスト 直接View返却 Controller処理 クロージャ処理 パターン1: 直接ビュー表示 パターン2: Controller経由 パターン3: クロージャで処理

    Laravelコントローラーの役割

    Laravelでは、ルートで処理されるリクエストの処理を、コントローラーに記述します。

    artisanコマンドでコントローラーを作成

    # 基本的なコントローラー作成
    php artisan make:controller UserController

    ▼app/Http/Controllers/UserController.phpが作成されます

    namespace App\Http\Controllers;  // 名前空間の自動設定
    
    class UserController extends Controller  // クラスの自動生成
    {
        // 基本的なメソッド(--resourceオプション使用時)
        public function index() { }    // 一覧表示
        public function show($id) { }  // 詳細表示
    }
    artisanコマンドの動作 $ php artisan make:controller UserController app/Http/Controllers/ UserController.php コントローラークラスの自動生成完了
    • app/Http/Controllersディレクトリに新しいファイルを作成
    • 基本的なクラス構造を自動生成
    • 必要な名前空間とクラスのインポートを設定

    laravelインストール

    ▼バージョン確認(php composer node.js npm)

    ※MAMP/htdocs/作業フォルダにて

    PS C:\MAMP\htdocs\step01> php -v
    PHP 8.2.9 (cli) (built: Aug  1 2023 12:41:16) (NTS Visual C++ 2019 x64)
    Copyright (c) The PHP Group
    Zend Engine v4.2.9, Copyright (c) Zend Technologies
    PS C:\MAMP\htdocs\step01> composer --version
    Composer version 2.7.1 2024-02-09 15:26:28
    PS C:\MAMP\htdocs\step01> node -v
    v18.17.1
    PS C:\MAMP\htdocs\step01> npm -v
    9.6.7

    参考サイト:https://readouble.com/

    https://readouble.com/laravel/11.x/ja/installation.html

    ▼Composerのcreate-projectコマンドで新しいLaravelプロジェクトを作成

    PS C:\MAMP\htdocs\step01> composer create-project laravel/laravel umarche "8.*" --prefer-dist
    ※umarcheというフォルダを作成

    ▼umarcheに移動しサーバを起動

    PS C:\MAMP\htdocs\step01> cd umarche
    PS C:\MAMP\htdocs\step01\umarche> php artisan serve
    Starting Laravel development server: http://127.0.0.1:8000
    [Tue Apr  2 10:37:07 2024] PHP 8.2.9 Development Server (http://127.0.0.1:8000) started

    →記載されているURLにて表示を確認

    初期設定確認

    DB

    PHPMYADMIN

    ▼MAMP PREFERENCES Ports

    AMP PREFERENCES Ports

    • apache port:8888
    • mysql port: 8889

    Open WebStart Page → TOOLS → PHPMYADMIN

    日本語に設定Appearance settings

    データベース名:laravel_umarcheでデータベースを新規作成

    ▼ユーザ登録

    • Privileges(特権)タブを選択
    • Add user account
      • ユーザ名:umarche
      • ホスト名:%
      • パスワード:pas123
      •  Grant all privileges on database laravel\_umarche.にチェックが入っているか確認
    • go(実行)→ユーザが追加される

    laravel側で記載

    ▼umarch/.env

    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=8889
    DB_DATABASE=laravel_umarche
    DB_USERNAME=umarche
    DB_PASSWORD=pas123

    ▼接続を確認

    PS C:\MAMP\htdocs\step01\umarche> php artisan migrate
    Migration table created successfully.
    Migrating: 2014_10_12_000000_create_users_table
    Migrated:  2014_10_12_000000_create_users_table (161.48ms)
    Migrating: 2014_10_12_100000_create_password_resets_table
    Migrated:  2014_10_12_100000_create_password_resets_table (155.42ms)
    Migrating: 2019_08_19_000000_create_failed_jobs_table
    Migrated:  2019_08_19_000000_create_failed_jobs_table (179.04ms)
    Migrating: 2019_12_14_000001_create_personal_access_tokens_table
    Migrated:  2019_12_14_000001_create_personal_access_tokens_table (419.47ms)
    https://coinbaby8.com/access_denied.html

    GitHubでリポジトリを作成

    Gitのインストール

    https://git-scm.com

    コマンドプロンプトを起動しインストールを確認
    ※Windowsにて

    C:\Users\xxxx>git --version 
    git version 2.44.0.windows.1

    ※VSCodeのターミナルの場合インストール後一度開きなおす必要があるかも

    github Create a new repository

    Repository name*:
    laravel_umarche2

    VSCodeターミナルで下記コマンド

    • git init
    • git add -A
    • git add README.md git commit -m “first commit”
    • git branch -M main
    • git remote add origin git@github.com:idatokiya/laravel_umarche2.git
    • git push -u origin main
      エラーメッセージ対処→https://ntorelabo.com/?p=7427#co-index-5

    初期設定

    ブランチを分けて作業
    →VSCodeターミナル下記コマンド

    PS C:\MAMP\htdocs\step01\umarche> git switch -c sec01_initialSetting
    Switched to a new branch 'sec01_initialSetting'
    PS C:\MAMP\htdocs\step01\umarche> git branch
      main
    * sec01_initialSetting

    タイムゾーン 言語設定

    config/app.phpを編集

        /*
        |--------------------------------------------------------------------------
        | Application Timezone
        |--------------------------------------------------------------------------
        |
        | Here you may specify the default timezone for your application, which
        | will be used by the PHP date and date-time functions. We have gone
        | ahead and set this to a sensible default for you out of the box.
        |
        */
    
        'timezone' => 'Asia/Tokyo',
    
        /*
        |--------------------------------------------------------------------------
        | Application Locale Configuration
        |--------------------------------------------------------------------------
        |
        | The application locale determines the default locale that will be used
        | by the translation service provider. You are free to set this value
        | to any of the locales which will be supported by the application.
        |
        */
    
        'locale' => 'Ja',
    

    デバッグバーインストール

    composer require barryvdh/laravel-debugbar

    →composer.jsonにて確認

        "require": {
            "php": "^7.3|^8.0",
            "barryvdh/laravel-debugbar": "^3.7",
            "fruitcake/laravel-cors": "^2.0",
            "guzzlehttp/guzzle": "^7.0.1",
            "laravel/framework": "^8.75",
            "laravel/sanctum": "^2.11",
            "laravel/tinker": "^2.5"
        },

    コミット

    git add -Aでwarning

    PS C:\MAMP\htdocs\step01\umarche> git add -A
    warning: in the working copy of 'composer.json', LF will be replaced by CRLF the next time Git touches it
    warning: in the working copy of 'composer.lock', LF will be replaced by CRLF the next time Git touches it
    warning: in the working copy of 'config/app.php', LF will be replaced by CRLF the next time Git touches it
    warning: in the working copy of 'storage/debugbar/.gitignore', LF will be replaced by CRLF the next time Git touches it

    →対応
    参考サイト:https://qiita.com/WebEngrChild/items/133484ca79fc90a207d5

    git config --global core.autoCRLF false

    ▼再度git add -A

    PS C:\MAMP\htdocs\step01\umarche> git add -A
    PS C:\MAMP\htdocs\step01\umarche> git commit -m "initialSetting" 
    [sec01_initialSetting 6e98bfa] initialSetting
     4 files changed, 158 insertions(+), 3 deletions(-)
     create mode 100644 storage/debugbar/.gitignore
    PS C:\MAMP\htdocs\step01\umarche> git push origin sec01_initialSetting
    Enumerating objects: 13, done.
    Counting objects: 100% (13/13), done.
    Delta compression using up to 12 threads
    Compressing objects: 100% (7/7), done.
    Writing objects: 100% (7/7), 1.68 KiB | 858.00 KiB/s, done.
    Total 7 (delta 5), reused 0 (delta 0), pack-reused 0 (from 0)
    remote: Resolving deltas: 100% (5/5), completed with 5 local objects.
    remote: 
    remote: Create a pull request for 'sec01_initialSetting' on GitHub by visiting:
    remote:      https://github.com/idatokiya/laravel_umarche2/pull/new/sec01_initialSetting
    remote: 
    To github.com:xxx/laravel_umarche2.git
     * [new branch]      sec01_initialSetting -> sec01_initialSetting
    PS C:\MAMP\htdocs\step01\umarche> 

    Viteの採用について

    LaravelのビルドツールがLaravel MixViteに変更(2022/6/28~)

    Laravel Breezeインストール

    Laravel Breezetとは認証ライブラリのひとつで、ログイン、ユーザ登録、パスワードリセット、メールの検証、パスワードの確認などの認証機能をシンプルに実装できます。

    Tailwind CSSを使用します。

    ▼Gitのブランチ変更

    PS C:\MAMP\htdocs\step01\umarche> git switch -c sec02_larabelBreeze
    Switched to a new branch 'sec02_larabelBreeze'
    PS C:\MAMP\htdocs\step01\umarche> git branch
      main
      sec01_initialSetting
    * sec02_larabelBreeze
    PS C:\MAMP\htdocs\step01\umarche> 

    ▼composerでLaravel Breezeのパッケージをインストール

    composer require laravel/breeze "1.*" --dev

    PS C:\MAMP\htdocs\step01\umarche> composer require laravel/breeze "1.*" --dev
    ./composer.json has been updated
    Running composer update laravel/breeze
    Loading composer repositories with package information
    Updating dependencies
    Lock file operations: 1 install, 0 updates, 0 removals
      - Locking laravel/breeze (v1.10.0)
    Writing lock file
    Installing dependencies from lock file (including require-dev)
    Nothing to install, update or remove
    Package fruitcake/laravel-cors is abandoned, you should avoid using it. No replacement was suggested.
    Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead.
    Generating optimized autoload files
    > Illuminate\Foundation\ComposerScripts::postAutoloadDump
    > @php artisan package:discover --ansi
    Discovered Package: barryvdh/laravel-debugbar
    Discovered Package: facade/ignition
    Discovered Package: fruitcake/laravel-cors
    Discovered Package: laravel/breeze
    Discovered Package: laravel/sail
    Discovered Package: laravel/sanctum
    Discovered Package: laravel/tinker
    Discovered Package: nesbot/carbon
    Discovered Package: nunomaduro/collision
    Package manifest generated successfully.
    80 packages you are using are looking for funding.
    Use the `composer fund` command to find out more!
    > @php artisan vendor:publish --tag=laravel-assets --ansi --force
    No publishable resources for tag [laravel-assets].
    Publishing complete.
    No security vulnerability advisories found.

    ▼アセットをコンパイル

    PS C:\MAMP\htdocs\step01\umarche> php artisan breeze:install
    Breeze scaffolding installed successfully.
    Please execute the "npm install" && "npm run dev" commands to build your assets.
    
    PS C:\MAMP\htdocs\step01\umarche> npm install               
    npm WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
    npm WARN deprecated @babel/plugin-proposal-object-rest-spread@7.20.7: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.
    
    added 805 packages, and audited 806 packages in 34s
    
    102 packages are looking for funding
      run `npm fund` for details
    
    1 moderate severity vulnerability
    
    To address all issues (including breaking changes), run:
      npm audit fix --force
    
    Run `npm audit` for details.
    PS C:\MAMP\htdocs\step01\umarche> npm run dev               
    
    > dev
    > npm run development
    
    > development
    > mix
    
    ● Mix █████████████████████████ emitting (95%)
     emit
    
    ● Mix █████████████████████████ done (99%) plugins
     WebpackBar:done
    
    ✔ Mix
      Compiled successfully in 3.27s
                             
       Laravel Mix v6.0.49   
                       
    ✔ Compiled Successfully in 3254ms
    ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────┐
    │                                                                                                                                        File │ Size     │
    ├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
    │                                                                                                                                  /js/app.js │ 707 KiB  │
    │                                                                                                                                 css/app.css │ 31.8 KiB │
    └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────┘

    php artisan serveで表示を確認するとLogin Registerの追加を確認

    問題)Login Register画面の表示がおかしい(CSSがあたっていない)

    参考コード:https://github.com/aokitashipro/laravel_umarche/blob/main/resources/views/layouts/app.blade.php

    ▼resources/views/layouts/guest.blade.phpを編集

    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta name="csrf-token" content="{{ csrf_token() }}">
    
            <title>{{ config('app.name', 'Laravel') }}</title>
    
            <!-- Fonts -->
            <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">
    
            <!-- Scripts -->
            <!-- @vite(['resources/css/app.css', 'resources/js/app.js']) -->
            <!-- Styles -->
            <link rel="stylesheet" href="{{ asset('css/app.css') }}">
    
            <!-- Scripts -->
            <script src="{{ asset('js/app.js') }}" defer></script>
            
        </head>
        <body>
            <div class="font-sans text-gray-900 antialiased">
                {{ $slot }}
            </div>
        </body>
    </html>

    ▼resources/views/layouts/guest.app.phpを編集

    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta name="csrf-token" content="{{ csrf_token() }}">
    
            <title>{{ config('app.name', 'Laravel') }}</title>
    
            <!-- Fonts -->
            <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">
    
            <!-- Scripts -->
            <!-- @vite(['resources/css/app.css', 'resources/js/app.js']) -->
            <!-- Styles -->
            <link rel="stylesheet" href="{{ asset('css/app.css') }}">
    
            <!-- Scripts -->
            <script src="{{ asset('js/app.js') }}" defer></script>
    
        </head>
        <body class="font-sans antialiased">
            <div class="min-h-screen bg-gray-100">
                @include('layouts.navigation')
    
                <!-- Page Heading -->
                <header class="bg-white shadow">
                    <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
                        {{ $header }}
                    </div>
                </header>
    
                <!-- Page Content -->
                <main>
                    {{ $slot }}
                </main>
            </div>
        </body>
    </html>
    

    php artisan serveで改めて表示を確認すると正しく表示されることを確認

    ▼commit

    PS C:\MAMP\htdocs\step01\umarche> git config --global core.autoCRLF false
    PS C:\MAMP\htdocs\step01\umarche> git add -A
    PS C:\MAMP\htdocs\step01\umarche> git commit -m "add Breeze"
    [sec02_larabelBreeze 991eeb2] add Breeze
     53 files changed, 35895 insertions(+), 5 deletions(-)
    
    PS C:\MAMP\htdocs\step01\umarche> git push origin sec02_laravelBreeze
    Enumerating objects: 99, done.
    Counting objects: 100% (99/99), done.
    Delta compression using up to 12 threads
    Compressing objects: 100% (72/72), done.
    Writing objects: 100% (78/78), 250.66 KiB | 2.02 MiB/s, done.
    Total 78 (delta 24), reused 0 (delta 0), pack-reused 0 (from 0)
    remote: Resolving deltas: 100% (24/24), completed with 10 local objects.
    remote:
    remote: Create a pull request for 'sec02_laravelBreeze' on GitHub by visiting:
    remote:      https://github.com/idatokiya/laravel_umarche2/pull/new/sec02_laravelBreeze
    remote:
    To github.com:idatokiya/laravel_umarche2.git
     * [new branch]      sec02_laravelBreeze -> sec02_laravelBreeze

    日本語化

    ▼新しいブランチを作成

    PS C:\MAMP\htdocs\step01\umarche> git switch -c sec02_japaneseLocalization
    Switched to a new branch 'sec02_japaneseLocalization'
    PS C:\MAMP\htdocs\step01\umarche> git branch
      main
      sec01_initialSetting
    * sec02_japaneseLocalization
      sec02_laravelBreeze

    ▼日本語化対応ファイルを作成(laravel_umarche/resources/langディレクトリ)

    • ja.json
    • ja/auth.php
    • ja/pagination.php
    • ja/passwords.php
    • ja/validation-inline.php
    • ja/validation.php

    参考:https://github.com/idatokiya/laravel_umarche2/tree/sec02_japaneseLocalization

    ▼commit

    PS C:\MAMP\htdocs\step01\umarche> git config --global core.autoCRLF false
    PS C:\MAMP\htdocs\step01\umarche> git add -A
    PS C:\MAMP\htdocs\step01\umarche> git commit -m "日本語化対応"
    [sec02_japaneseLocalization a867cfb] 譌・譛ャ隱槫喧蟇セ蠢
     7 files changed, 268 insertions(+)
     create mode 160000 laravel_umarche
     create mode 100644 resources/lang/ja.json
     create mode 100644 resources/lang/ja/auth.php
     create mode 100644 resources/lang/ja/pagination.php
     create mode 100644 resources/lang/ja/passwords.php
     create mode 100644 resources/lang/ja/validation-inline.php
     create mode 100644 resources/lang/ja/validation.php
    PS C:\MAMP\htdocs\step01\umarche> git push origin sec02_japaneseLocalization
    Enumerating objects: 14, done.
    Counting objects: 100% (14/14), done.
    Delta compression using up to 12 threads
    Compressing objects: 100% (11/11), done.
    Writing objects: 100% (11/11), 4.55 KiB | 1.52 MiB/s, done.
    Total 11 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
    remote: Resolving deltas: 100% (1/1), completed with 1 local object.
    remote: 
    remote: Create a pull request for 'sec02_japaneseLocalization' on GitHub by visiting:
    remote:      https://github.com/idatokiya/laravel_umarche2/pull/new/sec02_japaneseLocalization
    remote:
    To github.com:idatokiya/laravel_umarche2.git
     * [new branch]      sec02_japaneseLocalization -> sec02_japaneseLocalization

    Tailwindcss ver3

    php artisan serveだけだと反映されない(Laravel側の簡易サーバでフロント側:Node.jsは見れない)

    npm run devnpm run watchで反映

    npm run watch
    随時、コンパイル

    ターミナル1: npm run watch
    ターミナル2: php artisan serve
    ターミナル3: Laravel各コマンド実行

    21. 準備 (ルート->コントローラ->ビュー)

    https://logsuke.com/web/programming/laravel/laravel-breeze-lang-ja

    Laravelをさくらインターネットで使用する方法

    SSH を利用

    TeraTermをダウンロード

    SSHプロトコルでサーバーを遠隔操作できるターミナルエミュレータで、Windows対応のフリーソフトです。

    ▼接続設定

    • ホスト:初期ドメイン(xxxxxx.sakura.ne.jp)…さくらインターネットコントロールパネルで確認できます
    • ユーザ名:アカウント …さくらインターネットコントロールパネルで確認できます
    • パスフレーズ:さくらインターネットコントロールパネルログインパスワード

    Welcome to FreeBSD!の表示で接続の確認ができます

    ▼終了方法について
    Tera Term のデフォルトでは、ログイン先サーバからログアウトしたり、ネットワークエラー等で接続が切れたりすると、同時に終了されます。

    https://qiita.com/risuracer/items/b6e6ccb95281d97089b2
    tailwindcss使い方

    tailwindcssメリット、デメリット

    メリット

    • class名を付与する必要がない

    デメリット

    • 事前にビルドの設定が必要

    導入方法

    npm(Node Package Manager)経由でインストール

    参考:https://logical-studio.com/develop/frontend/20220401-tailwindcss/#Tailwind_CSS_v3

    ・プロジェクトフォルダにて(tailwindcss_testフォルダ)

    初期化実施

    npm init -y

    ▼tailwindcss-test/package.jsonが作成されます

    {
      "name": "tailwindcss-test",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    

    Tailwind CSSをPostCSSプラグインとして導入するため、tailwind CSSに加えPostCSSもインストール

    ビルド時にpostcssコマンドを使うため、postcss-cliをインストール

    npm install -D tailwindcss postcss-cli autoprefixer

    Tailwind CSSとPostCSSのコンフィグファイルを生成

    npx tailwindcss init -p

    必要なディレクトリを作成

    • tailwindcss_test
      • dist
        • output.css
      • src
        • index.html
        • input.css

    ユーティリティクラスを使うファイルのパスを指定

    tailwind.config.jsを編集

    module.exports = {
      content: ["./src/**/*.{html,js}"],
      theme: {
        extend: {},
      },
      plugins: [],
    }

    ディレクティブの情報をinput.cssに入力

    @tailwind base;
    @tailwind components;
    @tailwind utilities;

    ビルドコマンドの設定

    {
      "name": "tailwindcss_test",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "postcss ./src/input.css -o ./dist/output.css --watch --verbose"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "autoprefixer": "^10.4.17",
        "postcss-cli": "^11.0.0",
        "tailwindcss": "^3.4.1"
      }
    }
    

    npm run devコマンドを実行

    →output.cssにTailwind CSSの雛形が生成

    watchコマンドが走っているため、ユーティリティクラスを追加すると自動でそのCSSが生成されます

    実際にindex.htmlを編集して試してみます

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link href="../dist/output.css" rel="stylesheet" />
      </head>
      <body>
        <h1 class="text-3xl font-bold underline text-blue-600">Hello world!</h1>
      </body>
    </html>
    

    →正しくoutput.cssに追記されます

    .text-3xl {
      font-size: 1.875rem;
      line-height: 2.25rem;
    }
    .font-bold {
      font-weight: 700;
    }
    .text-blue-600 {
      --tw-text-opacity: 1;
      color: rgb(37 99 235 / var(--tw-text-opacity));
    }
    .underline {
      text-decoration-line: underline;
    }

    WordPressとTailwind CSS

    https://note.com/zoetaka38/n/n242b145d3741
    Laravelでtodoアプリ

    Contents

    Laravel

    LaravelはPHPのフレームワークで有名です。

    2011年にリリースされた新しいフレームワークですが、世界中に普及しています。

    ECサイトや予約システム使用されることが多いです。

    MVC

    Model View Controllerパーツに分割して実装していくモデルです。

    • Model
      • データの処理、DBとのやりとりを行う
    • View
      • ユーザーに画面を表示
      • ユーザからの入力を受け付ける
    • Controller
      • ユーザからの入力をModelに依頼
      • Modelが処理したデータをViewに表示を依頼

    使われているフレームワーク

    PHP:Laravel、CakePHP、CodeIgniter、ZendFramework

    JavaScript:Backbone.js、Spine.js、JavaScriptMVC

    Laravel 利用方法 2024/02/24

    https://b-risk.jp/blog/2022/08/laravel/の記事の流れで実施

    • Windows
    • MAMPダウンロード済み
    https://b-risk.jp/blog/2022/08/laravel/

    Composerをインストール(Windows)

    https://weblabo.oscasierra.net/php-composer-windows-install/を参考

    Windows PowerShellでインストールを確認 ※一度開きなおす

    composer -V
    https://weblabo.oscasierra.net/php-composer-windows-install/

    Composerをインストール(Mac)

    下記記事を参考 ※homebrewでComposerをインストール

    https://god48.com/composer-install

    Laravelをインストール

    laravel_testディレクトリを作成

    laravel_testに移動

    composer create-project --prefer-dist laravel/laravel . "9.*"

    エラー発生

    php.iniファイルの編集が必要みたいです

    php.iniのパス

    php --ini

    参考 【PHP/Linux】php.ini の探し方と修正方法:https://developer.same-san.com/detail/php-ini

    php.iniのパスをみてみるとphp.iniはなく下記のベースファイル2種があります

    • php.ini-production
    • php.ini-development

    php.iniを編集

    2ヵ所:を削除

    extension=curl
    ;extension=ffi
    ;extension=ftp
    extension=fileinfo
    ;extension=gd
    ;extension=gettext
    ;extension=gmp

    始め上記のコメントアウトのみ実施したら、再度エラー

    エラー内容から検索した記事を参考に別の箇所をコメントアウト

    Laravelインストール時に出たzipのエラー解決備忘録:https://qiita.com/nejimawaso/items/55512b40b724e35880c3

    ;extension=soap
    ;extension=sockets
    ;extension=sodium
    ;extension=sqlite3
    ;extension=tidy
    ;extension=xsl
    extension=zip
    
    ;zend_extension=opcache

    再度Laravelインストールのためのコマンドを入力

    composer create-project --prefer-dist laravel/laravel . "9.*"

    ↓無事インストール完了

    Laravelの簡易サーバを立ち上げ

    php artisan serve

    「http://127.0.0.1:8000/」にアクセスすると画面が表示されます。

    Laravelの初期設定

    laravel_test/config/app.php

    
    'timezone' => 'Asia/Tokyo',
    
    
    'locale' => 'ja',
    
    'fallback_locale' => 'ja',
    
    'faker_locale' => 'ja_JP',
    

    laravel_test/.env
    (主に定数を設定しているファイル)

    
    APP_NAME=Laravel_Test
    

    laravel_test/.resources/views/welcome.blade.php

            <!-- <title>Laravel</title> -->
            <title>{{ config('app.name') }}</title>
    

    タイトルがLaravelからLaravel_Testに変更されます

    データベース接続情報の設定

    MAMPでデータベースの作成

    1. MAMP で「Open WebStart page」クリック
    2. ブラウザに表示されたhttp://localhost:8888/MAMP/のメニューの「TOOLS」の「PHPMYADMIN
    3. New」をクリック
    4. DB作成画面でデータベース名は「laravel_test」、照合順序は「utf8_general_ci」にして、「Create

    データベースの情報を「.env」で変更

    
    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=laravel_test
    DB_USERNAME=root
    DB_PASSWORD=root
    

    config/database.php」を編集

    デフォルトでも問題ない

            'mysql' => [
                'driver' => 'mysql',
                'url' => env('DATABASE_URL'),
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE', 'forge'),
                'username' => env('DB_USERNAME', 'forge'),
                'password' => env('DB_PASSWORD', ''),
                'unix_socket' => env('DB_SOCKET', ''),
                'charset' => 'utf8',
                'collation' => 'utf8_general_ci',
                'prefix' => '',
                'prefix_indexes' => true,
                'strict' => true,
                'engine' => null,
                'options' => extension_loaded('pdo_mysql') ? array_filter([
                    PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
                ]) : [],
            ],

    変更を反映

    ※php artisan serveを実行している状態であれば、「Ctrl + C」で停止

    php artisan config:clear

    反映後DB接続を確認するため

    php artisan migrateコマンドで確認するとエラー発生

    Illuminate\Database\QueryException

    エラー解決のためphp.iniを変更

    ;extension=pdo_firebird
    extension=pdo_mysql
    ;extension=pdo_oci

    Illuminate\Database\QueryException
    再度同エラー発生

    エラー内容のSQLSTATE[HY000] [2002] php_network_getaddresses: を調べたところデータベース接続ができていない

    .envファイルを開きデータベース情報を修正する必要があるとのこと

    改めてMySQLに接続してデータベース情報を確認
    →http://localhost:8888/MAMP/?language=Japanese

    上記を参考に.envを再度編集

    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=8889
    DB_DATABASE=laravel_test
    DB_USERNAME=root
    DB_PASSWORD=root

    php artisan config:clear php artisan migrate

    ▼コマンドを実行すると下記の通りで正しく接続できたようです

    PS C:\Users\xxxx\laravel_test> php artisan migrate     
    
       INFO  Preparing database.
    
      Creating migration table ....................................................................................... 94ms DONE
    
       INFO  Running migrations.  
    
      2014_10_12_000000_create_users_table .......................................................................... 135ms DONE
      2014_10_12_100000_create_password_resets_table ................................................................ 161ms DONE
      2019_08_19_000000_create_failed_jobs_table .................................................................... 142ms DONE
      2019_12_14_000001_create_personal_access_tokens_table ......................................................... 187ms DONE
    
    PS C:\Users\xxxx\laravel_test> 

    ▼phpMyAdminにて更新すると下記の通り反映できてました(コピペで見づらいです、、)

    Containing the word: 
    Table Ascending	Action	Rows 	Type	Collation	Size	Overhead
    	failed_jobs	 	Browse Browse	Structure Structure	Search Search	Insert Insert	Empty Empty	Drop Drop	0	InnoDB	utf8_general_ci	16.0 KiB	-
    	migrations	 	Browse Browse	Structure Structure	Search Search	Insert Insert	Empty Empty	Drop Drop	4	InnoDB	utf8_general_ci	16.0 KiB	-
    	password_resets	 	Browse Browse	Structure Structure	Search Search	Insert Insert	Empty Empty	Drop Drop	0	InnoDB	utf8_general_ci	16.0 KiB	-
    	personal_access_tokens	 	Browse Browse	Structure Structure	Search Search	Insert Insert	Empty Empty	Drop Drop	0	InnoDB	utf8_general_ci	16.0 KiB	-
    	users	 	Browse Browse	Structure Structure	Search Search	Insert Insert	Empty Empty	Drop Drop	0	InnoDB	utf8_general_ci	16.0 KiB	-
    5 tables	Sum	4	InnoDB	utf8_general_ci	80.0 KiB	0 B

    基本的なLaravelのMVC

    モデルを作成する

    「todo_lists」というテーブルを作成

    モデルマイグレーションファイルコントローラーを同時に作成

    php artisan make:model TodoList -mc

    下記の通り3つのファイルを作成されます

       INFO  Model [C:\Users\xxxxxx\laravel_test\app/Models/TodoList.php] created successfully.
    
       INFO  Migration [C:\Users\xxxxxx\laravel_test\database\migrations/2024_02_27_120807_create_todo_lists_table.php] created successfully.
    
       INFO  Controller [C:\Users\xxxxxx\laravel_test\app/Http/Controllers/TodoListController.php] created successfully.
    database\migrationsフォルダ内に作成された「日付_create_todo_lists_table.php」を編集
        public function up()
        {
            Schema::create('todo_lists', function (Blueprint $table) {
                $table->id();
                $table->string('name', 100); //追記
                $table->timestamps();
            });
        }

    php artisan migrateコマンドを実行

    phpMyAdminにて「todo_lists」というテーブルが作成

    ダミーデータを登録

    シーダー

    php artisan make:seeder TodoListSeederコードを実行

    database\seedersにTodoListSeeder.phpが作成されます

    TodoListSeeder.phpを編集

    <?php
     
    namespace Database\Seeders;
     
    use Illuminate\Database\Console\Seeds\WithoutModelEvents;
    use Illuminate\Database\Seeder;
    use Illuminate\Support\Facades\DB; //追記
     
    class TodoListSeeder extends Seeder
    {
      /**
       * Run the database seeds.
       *
       * @return void
       */
      public function run()
      {
        DB::table('todo_lists')->insert(
          [
            [
              'name' => 'テスト1',
              'created_at' => now(),
              'updated_at' => now(),
            ],
            [
              'name' => 'テスト2',
              'created_at' => now(),
              'updated_at' => now(),
            ],
            [
              'name' => 'テスト3',
              'created_at' => now(),
              'updated_at' => now(),
            ],
          ]
        );
      }
    }
    

    database\seeders\DatabaseSeeder.phpを編集

    public function run()
    {
      $this->call([
        TodoListSeeder::class
      ]);
    }

    php artisan db:seed --class=TodoListSeeder

    ダミーデータが作成されます

    コントローラーを作成

    app\Http\Controllersフォルダ内のTodoListController.phpを編集

    編集内容:ModelクラスのTodolistからデータを取得→取得した値をViewに渡す処理

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\Models\TodoList;//追記
    
    class TodoListController extends Controller
    {
      public function index(Request $request)
      {
        $todo_lists = TodoList::all();
    
        return view('todo_list.index', ['todo_lists' => $todo_lists]);
      }
    }
    

    参考:https://rocomadejapan.com/?cat=30

    ビューファイルを作成

    resources\views\todo_list\index.blade.phpという構成で作成

    <!DOCTYPE html>
    <html lang="ja">
     
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>テスト</title>
    </head>
     
    <body>
     
        @if ($todo_lists->isNotEmpty())
            <ul>
                @foreach ($todo_lists as $item)
                    <li>
                        {{ $item->name }}
                    </li>
                @endforeach
            </ul>
        @endif
     
    </body>
     
    </html>

    ルーティングを設定

    routes\web.phpに追記

    <?php
    
    use Illuminate\Support\Facades\Route;
    
    use App\Models\TodoList;//追記
    use App\Http\Controllers\TodoListController;//追記
    
    /*
    |--------------------------------------------------------------------------
    | Web Routes
    |--------------------------------------------------------------------------
    |
    | Here is where you can register web routes for your application. These
    | routes are loaded by the RouteServiceProvider within a group which
    | contains the "web" middleware group. Now create something great!
    |
    */
    
    Route::get('/', function () {
        return view('welcome');
    });
    
    Route::get('/list', [TodoListController::class, 'index']);

    php artisan serveを実行しhttp://127.0.0.1:8000/listにアクセスすると正しく表示されます

    TailwindCSSを導入

    先ほどのセクションの続きでTailwindCSSを導入します

    https://ntorelabo.com/?p=9933

    laravelディレクトリでnpm install -D tailwindcss postcss autoprefixerを実行

    続いてnpx tailwindcss init -p実行

    tailwind.config.jspostcss.config.js作成

    ▼tailwind.config.jsを編集

    /** @type {import('tailwindcss').Config} */
    module.exports = {
        content: [
            "./resources/**/*.blade.php",
            "./resources/**/*.js",
            "./resources/**/*.vue",
        ],
        theme: {
            extend: {},
        },
        plugins: [],
    }

    ▼resources\css\app.cssを編集

    @tailwind base;
    @tailwind components;
    @tailwind utilities;

    参考サイトにはnpm run devを実行とありますが、php artisan serveコマンドも起動していないとページが表示できません

    中断してphp artisan serveを実行してサイト表示させるとVite manifest not found atというエラー

    npm run buildコマンドを実行する

    参考:https://rocomadejapan.com/?p=1035

    npm run devを実行していない時には、Vite側で、manifest.jsonファイルの情報を元に、public/build/assetsのファイルを参照してくれます。

    php artisan serveでサイトが正しく表示されます

    Todoアプリ実装

    tasksテーブル作成

    php artisan make:migration create_tasks_table

    →database/migrations/日付_create_tasks_table.phpが作成されます

    ▼日付_create_tasks_table.php

    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::create('tasks', function (Blueprint $table) {
                $table->id();
                $table->string('name', 100);
                $table->boolean('status')->default(false);
                $table->timestamp('updated_at')->useCurrent()->nullable();
                $table->timestamp('created_at')->useCurrent()->nullable();
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::dropIfExists('tasks');
        }
    };
    

    php artisan migrate実行するとphpMyAdminにてtasksテーブルが正しく作成されているのが確認できます

    Taskモデルを作成

    php artisan make:model Task

    →app\Models\Task.phpが作成されます

    コントローラーを作成

    php artisan make:controller TaskController --resource

    →app\Http\Controllers\TaskController.phpが作成されます

    ルート情報を追記

    ▼routes/web.php

    use App\Http\Controllers\TaskController;
    
    Route::resource('tasks', TaskController::class);

    php artisan route:listメソッドを確認

      GET|HEAD        / ........................................................................................................................................... 
      POST            _ignition/execute-solution .................................... ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionController
      GET|HEAD        _ignition/health-check ................................................ ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController
      POST            _ignition/update-config ............................................. ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController
      GET|HEAD        api/user .................................................................................................................................... 
      GET|HEAD        list ............................................................................................................... TodoListController@index
      GET|HEAD        sanctum/csrf-cookie ....................................................... sanctum.csrf-cookie › Laravel\Sanctum › CsrfCookieController@show
      GET|HEAD        tasks .................................................................................................... tasks.index › TaskController@index
      POST            tasks .................................................................................................... tasks.store › TaskController@store
      GET|HEAD        tasks/create ........................................................................................... tasks.create › TaskController@create
      GET|HEAD        tasks/{task} ............................................................................................... tasks.show › TaskController@show
      PUT|PATCH       tasks/{task} ........................................................................................... tasks.update › TaskController@update
      DELETE          tasks/{task} ......................................................................................... tasks.destroy › TaskController@destroy
      GET|HEAD        tasks/{task}/edit .......................................................................................... tasks.edit › TaskController@edit
    
                                                                                                                                                Showing [14] routes

    ビューを作成を作成

    ▼resources/views/tasks/index.blade.phpを作成

    <!DOCTYPE html>
    <html lang="ja">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Todo</title>
    
        @vite('resources/css/app.css')
    </head>
    
    <body class="flex flex-col min-h-[100vh]">
        <header class="bg-slate-800">
            <div class="max-w-7xl mx-auto px-4 sm:px-6">
                <div class="py-6">
                    <p class="text-white text-xl">Todoアプリ</p>
                </div>
            </div>
        </header>
    
        <main class="grow">
            <div class="max-w-7xl mx-auto px-4 sm:px-6">
                <div class="py-[100px]">
                    <p class="text-2xl font-bold text-center">今日は何する?</p>
                    <form action="/tasks" method="post" class="mt-10">
                      @csrf
    
                      <div class="flex flex-col items-center">
                        <label class="w-full max-w-3xl mx-auto">
                            <input
                                class="placeholder:italic placeholder:text-slate-400 block bg-white w-full border border-slate-300 rounded-md py-4 pl-4 shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1 sm:text-sm"
                                placeholder="洗濯物をする..." type="text" name="task_name" />
                        </label>
    
                        <button type="submit" class="mt-8 p-4 bg-slate-800 text-white w-full max-w-xs hover:bg-slate-900 transition-colors">
                            追加する
                        </button>
                      </div>
    
                    </form>
                </div>
            </div>
        </main>
        <footer class="bg-slate-800">
          <div class="max-w-7xl mx-auto px-4 sm:px-6">
            <div class="py-4 text-center">
                <p class="text-white text-sm">Todoアプリ</p>
            </div>
        </div>
        </footer>
    </body>
    
    </html>

    ▼TaskController.phpを編集

        public function index()
        {
            return view('tasks.index');
        }

    php artisan serveで確認したところTailwindCSSが読み込まれていない

    ▼参考:https://rocomadejapan.com/?p=1038

    一度サーバを停止しnpm run buildを実行し再度php artisan serveで確認すると正しく表示されました

    タスクを登録

    ▼TaskController.phpを編集

        public function store(Request $request)
        {
            $task_name = $request->input('task_name');
            dd($task_name);
        }

    テストですと入力してみるとテストです” // app/Http/Controllers/TaskController.php:38と表示されstoreメソッドに渡されているのが確認できます

    storeメソッド内で受け取った値をDBへ保存する設定

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\Models\Task;//追加

    ▼TaskController.phpを編集

    public function store(Request $request)
    {
      //モデルをインスタンス化
      $task = new Task;
     
      //モデル->カラム名 = 値 で、データを割り当てる
      $task->name = $request->input('task_name');
     
      //データベースに保存
      $task->save();
     
      //リダイレクト
      return redirect('/tasks');
     
    }

    再度テストですと入力してみるとphpMyAdminを開いてtasksテーブルに登録されているのが確認きます

    バリデーション

    Validatorクラスを利用

    ▼TaskController.phpに以下を追記

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\Models\Task;//追加
    use Illuminate\Support\Facades\Validator;//追加
    
    class TaskController extends Controller
    {
       …省略…
    
        /**
         * Store a newly created resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\Response
         */
        public function store(Request $request)
        {
            $rules = [
                'task_name' => 'required|max:100',
            ];
            
            $messages = ['required' => '必須項目です', 'max' => '100文字以下にしてください。'];
            
            Validator::make($request->all(), $rules, $messages)->validate();
    
            //モデルをインスタンス化
            $task = new Task;
    
            //モデル->カラム名 = 値 で、データを割り当てる
            $task->name = $request->input('task_name');
    
            //データベースに保存
            $task->save();
    
            //リダイレクト
            return redirect('/tasks');
        }
    
       …省略…

    ▼resources\views\todo_list\index.blade.phpに追記
    ※labelの中にあるinputタグの下

    @error('task_name')
      <div class="mt-3">
          <p class="text-red-500">
              {{ $message }}
          </p>
      </div>
    @enderror

    入力画面にて以下の通り正しく表示確認できます。
    ・何も記入しないで追加→「必須項目です」の表示
    ・100文字以上で入力「100文字以下にしてください。」の表示

    タスクを表示

    ▼TaskController.phpに以下を追記

        public function index()
        {
            $tasks = Task::all();
            
            return view('tasks.index', compact('tasks'));
        }
    

    ▼resources\views\todo_list\index.blade.phpに追記

    {{-- 追記 --}}
      @if ($tasks->isNotEmpty())
          <div class="max-w-7xl mx-auto mt-20">
              <div class="inline-block min-w-full py-2 align-middle">
                  <div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
                      <table class="min-w-full divide-y divide-gray-300">
                          <thead class="bg-gray-50">
                              <tr>
                                  <th scope="col"
                                      class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900">
                                      タスク</th>
                                  <th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
                                      <span class="sr-only">Actions</span>
                                  </th>
                              </tr>
                          </thead>
                          <tbody class="divide-y divide-gray-200 bg-white">
                              @foreach ($tasks as $item)
                                  <tr>
                                      <td class="px-3 py-4 text-sm text-gray-500">
                                          <div>
                                              {{ $item->name }}
                                          </div>
                                      </td>
                                      <td class="p-0 text-right text-sm font-medium">
                                          <div class="flex justify-end">
                                              <div>
                                                  <form action="/tasks/{{ $item->id }}"
                                                      method="post"
                                                      class="inline-block text-gray-500 font-medium"
                                                      role="menuitem" tabindex="-1">
                                                      @csrf
                                                      @method('PUT')
                                                      <button type="submit"
                                                          class="bg-emerald-700 py-4 w-20 text-white md:hover:bg-emerald-800 transition-colors">完了</button>
                                                  </form>
                                              </div>
                                              <div>
                                                  <a href="/tasks/{{ $item->id }}/edit/"
                                                      class="inline-block text-center py-4 w-20 underline underline-offset-2 text-sky-600 md:hover:bg-sky-100 transition-colors">編集</a>
                                              </div>
                                              <div>
                                                  <form action="/tasks/{{ $item->id }}" method="post"
                                                      class="inline-block text-gray-500 font-medium"
                                                      role="menuitem" tabindex="-1">
                                                      @csrf
                                                      @method('DELETE')
                                                      <button type="submit"
                                                          class="py-4 w-20 md:hover:bg-slate-200 transition-colors">削除</button>
                                                  </form>
                                              </div>
                                          </div>
                                      </td>
                                  </tr>
                              @endforeach
                          </tbody>
                      </table>
                  </div>
              </div>
          </div>
      @endif
      {{-- 追記ここまで --}}

    ※先ほど同様一度サーバを停止しnpm run buildを実行し再度php artisan serveでスタイルが効きます

    タスクを編集

    ▼TaskController.phpに以下を追記

        public function edit($id)
        {
            $task = Task::find($id);
            return view('tasks.edit', compact('task'));
        }

    ▼resources/views/tasks/edit.blade.phpを作成

      <!DOCTYPE html>
      <html lang="ja">
      
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>Todo</title>
      
          @vite('resources/css/app.css')
      </head>
      
      <body class="flex flex-col min-h-[100vh]">
          <header class="bg-slate-800">
              <div class="max-w-7xl mx-auto px-4 sm:px-6">
                  <div class="py-6">
                      <p class="text-white text-xl">Todoアプリ-編集画面</p>
                  </div>
              </div>
          </header>
      
          <main class="grow grid place-items-center">
              <div class="w-full mx-auto px-4 sm:px-6">
                  <div class="py-[100px]">
                      <form action="/tasks/{{ $task->id }}" method="post" class="mt-10">
                          @csrf
                          @method('PUT')
      
                          <div class="flex flex-col items-center">
                              <label class="w-full max-w-3xl mx-auto">
                                  <input
                                      class="placeholder:italic placeholder:text-slate-400 block bg-white w-full border border-slate-300 rounded-md py-4 pl-4 shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1 sm:text-sm"
                                      type="text" name="task_name" value="{{ $task->name }}" />
                                  @error('task_name')
                                      <div class="mt-3">
                                          <p class="text-red-500">
                                              {{ $message }}
                                          </p>
                                      </div>
                                  @enderror
                              </label>
      
                              <div class="mt-8 w-full flex items-center justify-center gap-10">
                                  <a href="/tasks" class="block shrink-0 underline underline-offset-2">
                                      戻る
                                  </a>
                                  <button type="submit"
                                      class="p-4 bg-sky-800 text-white w-full max-w-xs hover:bg-sky-900 transition-colors">
                                      編集する
                                  </button>
                              </div>
                          </div>
      
                      </form>
      
                  </div>
              </div>
          </main>
          <footer class="bg-slate-800">
              <div class="max-w-7xl mx-auto px-4 sm:px-6">
                  <div class="py-4 text-center">
                      <p class="text-white text-sm">Todoアプリ</p>
                  </div>
              </div>
          </footer>
      </body>
      
      </html>

    ▼TaskController.phpに以下を追記

        public function update(Request $request, $id)
        {
            $rules = [
                'task_name' => 'required|max:100',
              ];
            
              $messages = ['required' => '必須項目です', 'max' => '100文字以下にしてください。'];
            
              Validator::make($request->all(), $rules, $messages)->validate();
            
            
              //該当のタスクを検索
              $task = Task::find($id);
            
              //モデル->カラム名 = 値 で、データを割り当てる
              $task->name = $request->input('task_name');
            
              //データベースに保存
              $task->save();
            
              //リダイレクト
              return redirect('/tasks');
        }

    タスクを完了

    ▼resources\views\todo_list\index.blade.phpに追記

    <form action="/tasks/{{ $item->id }}"
        method="post"
        class="inline-block text-gray-500 font-medium"
        role="menuitem" tabindex="-1">
        @csrf
        @method('PUT')
     
        {{-- 追記 --}}
        <input type="hidden" name="status" value="{{$item->status}}">
        {{-- 追記 --}}
     
        <button type="submit"
            class="bg-emerald-700 py-4 w-20 text-white md:hover:bg-emerald-800 transition-colors">完了</button>
    </form>

    ▼TaskController.phpに以下を追記

      public function update(Request $request, $id)
      {
      
        dd($request->status);//追記

    デバッグとして完了ボタンを押すと、下記の通り0が取得でき、
    編集画面で編集するボタンを押すとnullが取得でき成功が確認

    デバッグでstatusの値の取得が確認できたので、
    ▼TaskController.phpを編集

      public function update(Request $request, $id)
      {
      
        //「編集する」ボタンをおしたとき
        if ($request->status === null) {
          $rules = [
            'task_name' => 'required|max:100',
          ];
      
          $messages = ['required' => '必須項目です', 'max' => '100文字以下にしてください。'];
      
          Validator::make($request->all(), $rules, $messages)->validate();
      
      
          //該当のタスクを検索
          $task = Task::find($id);
      
          //モデル->カラム名 = 値 で、データを割り当てる
          $task->name = $request->input('task_name');
      
          //データベースに保存
          $task->save();
        } else {
          //「完了」ボタンを押したとき
      
          //該当のタスクを検索
          $task = Task::find($id);
      
          //モデル->カラム名 = 値 で、データを割り当てる
          $task->status = true; //true:完了、false:未完了
      
          //データベースに保存
          $task->save();
        }
      
      
        //リダイレクト
        return redirect('/tasks');
      }

    完了するボタンを押すとphpmyadminにてstatusが1に変更されているのが確認できます

    一覧表示で未完了だけ表示

    ▼TaskController.phpを編集

    public function index()
    {
      $tasks = Task::where('status', false)->get();
     
      return view('tasks.index', compact('tasks'));
    }

    タスクを削除

    <div>
      <form onsubmit="return deleteTask();"
          action="/tasks/{{ $item->id }}" method="post"
          class="inline-block text-gray-500 font-medium"
          role="menuitem" tabindex="-1">
          @csrf
          @method('DELETE')
          <button type="submit"
              class="py-4 w-20 md:hover:bg-slate-200 transition-colors">削除</button>
      </form>
    </div>
    
       …省略…
    
       <script>
        function deleteTask() {
            if (confirm('本当に削除しますか?')) {
                return true;
            } else {
                return false;
            }
        }
      </script>
    </body>

    ▼TaskController.phpを編集

      public function destroy($id)
      {
        Task::find($id)->delete();
      
        return redirect('/tasks');
      }
    PostmanでPOSTリクエストをテストする方法

    Postmanのインストール

    自分の使用しているOS(Windows、Mac、またはLinux)を選び、「Download」ボタンをクリックします。

    https://www.postman.com/downloads/

    インストーラーを実行

    アカウントを作成せずに使用する場合は「Skip and go to the app」をクリック

    参考サイト

    https://qiita.com/ponsuke0531/items/03483449ea0df505a540
    AWS認定ソリューションアーキテクト-アソシエイトレベル

    AWSとは

    AWSとは近年流行しているクラウド化で利用されているサービスです。

    AWSの資格の種類

    AWS認定試験は2023/8月時点で12種類に資格があります。

    • AWS認定Solutions Architect(ソリューションアーキテクト)アソシエイト(SAA-C02)
      システム設計
    • AWS認定Developer(デベロッパー)アソシエイト(DVA-C01)
      開発
    • AWS認定SysOps Administrator(シスオプス アドミニストレーター)アソシエイト(SOA‐C02)
      管理運用
    (設計者向け)
    ソリューションアーキテクト
    (開発者向け)
    デベロッパー
    (運用管理者向け)
    Sys Ops アドミニストレーター
    Professional LevelAWS認定
    ソリューションアーキテクト
    -プロフェッショナルレベル試験
    AWS認定
    Dev Ops エンジニア
    -プロフェッショナルレベル試験
    Associate LevelAWS認定
    ソリューションアーキテクト
    -アソシエイトレベル試験
    AWS認定
    デベロッパー
    -アソシエイトレベル試験
    AWS認定
    Sys Ops アドミニストレーター
    -アソシエイトレベル試験
    Foundation LevelAWS認定
    クラウドプラクティナー試験

    インフラエンジニアとしてどのようなことがしたいか、明確にあるほうが、 案件をアサインしやすい 例)AWSの環境構築をしたいので、キャリアは未経験ですが、AWSの資格をアソシエイトを3つプロを一つ取得しました。

    AWS認定ソリューションアーキテクト-アソシエイトレベル試験概要

    セキュアなアーキテクチャの設計30%
    弾力性に優れたアーキテクチャの設計26%
    高パフォーマンスなアーキテクチャの設計24%
    コストを最適化したアーキテクチャの設計20%
    • 試験時間:130分
    • 問題数:65問
    • 合格ライン:720点/1000点

    重要サービス
    EC2 S3 VPC IAM ELB/Auto Scaling

    IAM(AWS Identity and Access Management)
    IAM は、AWS リソースへのアクセス権限を管理するためのサービスです。IAM より、AWS アカウントで誰が何(認証・認可)を実行できるかを定義します。

    Permissions Boundary(アクセス許可境界)
    IAMユーザーやIAMロールの操作可能範囲を限定、制約を設ける機能

    リソースの記述はARN(Amazon Resource Name)形式
    arn:aws:サービス:リージョン:アカウントID:リソース

    VPC(Amazon Virtual Private Cloud)
    仮想ネットワーク

    ↓1つのVPCはリージョン内すべてのAZにまたがる

    VPCエンドポイント
    インターネットとの通信が制限されているプライベートサブネット内のAWSリソースから、インターネットゲートウェイを経由せずにVPC外のAWSサービスへアクセス可能にする機能

    EC2(Elastic Compute Cloud

    elastic … 拡張性
    AWS上に仮想サーバを作るサービス

    EC2を起動するとき元となるイメージをAMI(Amazon Machine Image)を選んで作成します。
    …AMI(Amazon マシンイメージ)は、EC2インスタンスを起動するために必要なOSミドルウェアなどのテンプレートです。

    従量課金型(使った分だけ課金)
    ・起動中(Running)→費用発生
    ・停止中(Stopped)→EBSの費用のみ発生
    ・削除済み(Terminated)→発生しない

    ELB(Elastic Load Balancing)
    アプリケーションへの負荷やCPUの稼働状況をリアルタイムにモニタリングできるロードバランサーです

    RDS(Amazon Relational Database Service)
    データベースのマネージドサービス
    Aurora AWSが独自に開発

    S3(Amazon Simple Storage Service)
    ・オブジェクトストレージサービス … データを固有のIDを持つ「オブジェクト」として扱う→ディレクトリのような階層構造を持たない
    ・AWSのストレージサービスの中で1TBあたりの保存料金が最も安い
    ・保存容量が無制限

    ストレージクラス保存料金の高い順取出し料金取出し遅延保存AZ最短保存期間
    S3 Standard
    標準(Standard)
    1なしなし3以上なし
    S3 Intelligent-Tiering
    アクセス頻度が予測不能なデータを保存する際に適している
    変動なし変動3以上なし
    S3 Standard-IA
    (S3 Standard-Infrequent Access)
    2ありなし3以上30日
    S3 One Zone-IA3ありなし130日
    S3 Glacier Instant Retrieval
    ※アーカイブデータ向け
    4ありなし3以上90日
    S3 Glacier Flexible Retrieval
    ※アーカイブデータ向け
    5あり数分~数時間3以上90日
    S3 Glacier Deep Archive
    ※アーカイブデータ向け
    6あり数時間3以上180日

    バケット
    Amazon S3のオブジェクトが保存される領域
    ・一つのバケットにはオブジェクト数が無制限で保存可能
    ・バケット名はグローバルで一意、作成したバケット名は変更は不可

    マルチパートアップロード
    S3バケットに5GBを超えるファイルをアップロードするときに利用
    ※S3バケットに保存できるオブジェクトの最大サイズは5TBですが、一度にアップロードできる最大サイズは5GB

    クロスリージョンレプリケーション
    S3オブジェクトを自動的に異なるリージョンに保存したい場合に利用

    S3 Transfer Acceleration
    ユーザーからS3バケットへ最適化したネットワークルートを経由してデータを転送する機能

    ライフサイクル
     ・移行アクション … 利用頻度に応じてストレージクラスを変更
     ・有効期限アクション … 指定された期限を超えたオブジェクトを削除

    ライフサイクルポリシー
    S3バケット内のデータに対して、ストレージクラスの変更やオブジェクトの削除を自動化する機能

    著名付きURL
    アクセスを許可したいオブジェクトに対して期限を指定してURLを発行

    バケットポリシー
    ・S3で保存しているデータにバケット単位でアクセス権限を設定する機能
    ・サーバー側の暗号化(Server-Side Encryption:SSE)を強制できます

    <サーバー側の暗号化には、以下3種類の方法があります>

    1. Server-Side Encryption:SSE
      データをS3に保存する時にサーバーで暗号化する方法
    2. SSE-KMS
      AWS KMS(AWS Key Management Service)に保存されているKMSキーを使用する
    3. SSE-C
      ユーザーが管理している鍵を使用する

    バージョニング
    オブジェクトの世代管理ができる機能

    静的Webサイトホスティング
    バケットに保存している静的コンテンツ(HTMLやJPGなど)をWebサイトとして公開できる機能

    MFA Delete
    S3のバージョニング機能で世代管理されているオブジェクトを削除する際に、MFAデバイス認証が必要となる機能

    オブジェクトロック
    S3バケットに保存したオブジェクトに対して更新・削除を制限する機能
    ・S3バケット作成時にのみ設定可能
    ・オブジェクトロックを有効にするとバージョニング機能も有効になります。
    ※主にオブジェクトが意図的に改ざん・削除されることを防止する目的で使用

    • リテンションモード … 一定期間の保護
      • ガバナンスモード … s3:BypassGovernance Retention という権限がないと変更できない
      • コンプライアンスモード … 保護期間が明けるまで誰も上書き削除ができない
    • リーガルホールド … 保護期間を設定しない

    グローバルインフラストラクチャとネットワーク

    リージョン
    日本国内には「東京リージョン」と「大阪リージョン」の2つのリージョンが存在

    アベイラビリティゾーン(AZ)

    エッジロケーション
    ユーザに近いネットワークで高速なコンテンツを配信

    CIDRブロック
    VPCで作成者はIPアドレス(CIDRブロック)をアサインできます
    /16~/28の範囲

    ルートテーブル
    ルーティング設計
    ・サブネットに1つずつ設定

    インターネットゲートウェイ(IGW)
    VPCとインターネットを接続するためのゲートウェイ

    NATゲートウェイ
    ネットワークアドレス変換機能を持ちプライベートサブネットからインターネットへの通信を可能にする

    NATインスタンス
    ・NATゲートウェイと同じくプライベートサブネットからインターネットへの通信を可能にする
    ・EC2インスタンスから作成
    ・ポート転送機能を設定可能
    ・IPv4専用

    仮想プライベートゲートウェイ(VGW)
    ・VPCごとに1つだけ紐づけることが可能

    VPCエンドポイント
    インターネットとの通信が制限されているプライベートサブネット内のAWSリソースから、インターネットゲートウェイを経由せずにVPC外のAWSサービスへアクセス可能にする機能

    VPCピアリング
    2つのVPC間でプライベートな接続をするための機能
    ・異なるVPCアカウント間でも可能

    VPCフローログ

    AWS Direct Connectゲートウェイ
    オンプレミスと物理専用線で接続するサービス 
    ※インターネットを経由しないプライベートな接続を確保
    ・ZVPCと拠点を1対1で繋ぎます

    AWS Transit Gateway
    複数のVPC、Direct Connect、VPNをスター型トポロジーで接続
    ※ハブを介して、ネットワークを接続するクラウドルーター
    →ネットワークが簡素化

    AWS Site-to-Site VPN(サイト間VPN)
    カスタマーゲートウェイ(オンプレミスのルーター)とVPCの仮想プライベートゲートウェイ(VGW:Virtual Private Gateway)を、インターネットVPN(VPNトンネル)で接続するサービス

    コンピューティングと関連サービス
    Lambda/API Gateway ECS/Fargate/EKS

    EC2(Elastic Compute Cloud

    elastic … 拡張性
    AWS上に仮想サーバを作るサービス

    EC2を起動するとき元となるイメージをAMI(Amazon Machine Image)を選んで作成します。
    …AMI(Amazon マシンイメージ)は、EC2インスタンスを起動するために必要なOSミドルウェアなどのテンプレートです。

    従量課金型(使った分だけ課金)
    ・起動中(Running)→費用発生
    ・停止中(Stopped)→EBSの費用のみ発生
    ・削除済み(Terminated)→発生しない

    スポットインスタンス
    AWSが余らせているEC2リソースを入札形式で利用

    「スポットフリート」はスポットインスタンスのオプションの一つです。必要なインスタンス数を指定することで、指定した数のスポットインスタンスが起動します。スポットインスタンスが中断されて必要なインスタンス数を下回った場合、自動的にインスタンスを補充してインスタンス数を維持します。

    ハードウェア専有インスタンス(Dedicated Instances)は、他のAWSアカウントとは分離された専用ハードウェアでEC2インスタンスを利用できる購入オプションです。物理的なCPUソケット、コア数、ホストIDは確認できません。

    ・Dedicated Hosts(専有ホスト)
    他のEC2インスタンスとは分離された専用ハードウェアで利用できる購入オプションです。
    物理的なCPUソケット、コア数、ホストIDを確認する必要がない場合、ハードウェア専有インスタンスの方が低価格で利用できるので誤りです。

    リザーブドインスタンス(RI)
    長期間の利用を約束することで、割引を受ける

    ELB
    スケールアウト時の負荷分散を担うサービス
    CLB(Classic Load Balancer):L4/L7
    ALB(Application Load Balancer):L7 CLBより後に登場、機能豊富
    NLB(Network Load Balancer):L4 HTTP(S)以外のプロトコル通信時での負荷分散で利用

    ヘルスチェック(ELBの機能)
    インスタンスが正常に動作しているかチェック

    Auto Scaling
    EC2の状況に応じて自動的にインスタンスの数を増減させる機能

    ECS(Amazon Elastic Container Service)
    Docker環境を用意
    ・Task:EC2インスタンス上で実行されるコンテナ
    Cluster:Taskを保有しているEC2インスタンス
    Task Definition:Cluster上で動作するTaskの定義

    Lambda(ラムダ)
    サーバーをプロビジョニングしなくてもプロジェクトを実行できるコンピューティングサービス

    Lambda関数
    実行するプログラムとその実行トリガーとなるイベントを事前に定義する関数
    ・割り当てるメモリ用
    ・タイムアウトまでの時間
    ・Lambdaに割り当てるIAMロール
    ・VPC内外

    ストレージサービス
    S3 EBS EFS FSx Storage Gateway Snow Family

    EBS(Elastic Block Store)
    ブロックストレージ
    「Elastic」…用途に合わせて柔軟な使用ができる

    汎用SSD(gp3)3,000IOPS
    開発環境を構築する時に最適
    1GB〜16TB
    プロビジョンドIOPS(io2)64,000IOPS
    マルチアタッチ
    4GB〜16TB
    スループット最適化HDD(st1)500IOPS
    大量のデータ
    125GB〜16TB
    コールドHDD(sc1)250IOPS
    EBSの中で一番低コスト
    アクセス頻度の低いログデータやバックアップデータの保存
    125GB〜16TB

    EFSElastic File System
    Amazon EFSはNFS(Network File System)プロトコルをサポートするファイルストレージサービス

    ▼EFSのパフォーマンスモード

    汎用モードファイルサービスなど一般的な用途を想定したモードで、レイテンシーを優先する場合に使用するモードです。
    最大I/Oパフォーマンスモード・レイテンシーが汎用モードに比べ、わずかに長くなる
    ・合計スループットを優先する場合に使用

    ▼EFSのスループットモード

    バーストスループットモード・ベースラインとなるスループットが設定されている
    ・一時的なスループットの上昇にも耐えられるバースト機能を持っている
    プロビジョニングスループットモードバーストモードで許容されている以上の要件がある場合に使用
    エラスティックスループットモード・自動的にスケールアップダウン
    ・パフォーマンスもーどが汎用モード時のみ利用可

    FSx
    ファイルストレージサービス
    ・FSx for Windowsファイルサーバー
    ・FSx for Lustre
    ・FSx for NetApp ONTAP
    ・FSx for OpenZFS

    FSx for Windowsファイルサーバー
    Windows上にファイルシステムを提供
    SMBプロトコルを使用…主にWindowsコンピュータ間において、ファイル共有やプリンタ共有に使用されるプロトコル

    Storage Gateway
    オンプレミスにあるデータをクラウドに連携させるための受け口

    AWS Storage GatewayのS3ファイルゲートウェイは、オンプレミスからNFS(Network File System)またはSMB(Server Message Block)を使用してS3バケットへアクセスできるようにするゲートウェイタイプです。ローカル(オンプレミス)にキャッシュストレージを持つため低レイテンシでのアクセスも可能です。

    データベースサービス
    RDS/Aurora Redshift DynamoDB ElastiCache

    ▼AWSのデータサービス

    タイプサービス
    リレーショナル
    SQL
    Amazon Aurora、Amazon RDS、Amazon Redshift
    NoSQL キー値Amazon DynanoDB
    NoSQL インメモリAmazon ElastiCache、Amazon MemoryDB for Redis
    NoSQL ドキュメントAmazon DocumentDB
    NoSQL ワイドカラムAmazon Keyspaces
    NoSQL グラフAmazon Neptune
    時系列Amazon Timestream
    台帳AmazonQLDB

    Amazon RDS
    ・マルチAZ構成
    ・リードレプリカ

    Amazon Aurora
    ・DBクラスタ
    ・Auroraレプリカ

    データベースへの負荷に応じて動的にレプリカインスタンスを増減するAuto Scaling機能を備えています。

    Redshift
    ・データウェアハウス向け(データの「倉庫」
    ・拡張性
     →MPP…処理を複数のノードで分散(スケールアウト)
     →シェアードナッシング…各ノードがディスクを共有しない(I/O性能の劣化を回避)

    Redshift Spectrum
    Redshift内にデータを取り込むことなくクエリの実行が可能

    DynamoDB
    ・Key‐Value型
    ・NoSQL
    ・階層的なデータ構造をもったJSON形式のデータの扱いについてもサポート

    DynamoDBでは自動的に3つのAZにデータが保存されます

    DynamoDB Accelerator(DAX)
    DynamoDBの前段にキャッシュクラスタを構成→性能向上

    <Amazon DynamoDBには2つのバックアップ方法があります>
    オンデマンドバックアップ…ユーザーが任意のタイミングで作成するバックアップ
    ポイントインタイムリカバリ(PITR)…差分バックアップが定期的に自動で取得(35日前まで遡ることができます)

    DynamoDB Streams
    Amazon DynamoDBのDynamoDB Streams(ストリーム)とは、テーブルに対して行われた直近の24時間の変更(追加や更新、削除)をログに保存する機能です。

    ElastiCache
    ・インメモリ型データベース
    1)Memcached:再起動ですべてのデータが消える
    2)Redis:Memcachedよりも多くのデータ型が利用可能、データ永続性能

    マネジメント、ガバナンス
    CloudWatch CloudTrail Elastic Beanstalk CloudFormation Trusted Advisor AWS Systems Manager

    Amazon CloudWatch
    AWSサービスやオンプレミス(自社運用)のシステムを監視するサービス
    状態に応じたアクションを取らせることができます。

    メトリクスCloudWatchが監視する様々なリソースの情報は「メトリクス」と呼ばれます(インスタンスのCPU使用率やディスクの使用状況

    標準メトリクスCPU使用率、
    ディスク読み取り書き込み量、
    ネットワーク使用率
    カスタムメトリクスメモリ使用量、
    ディスク空き容量・使用状況、
    プロセス情報

    AWS CloudTrail
    AWSサービスに対して「いつ」「誰によって」「どのような操作が行われたのか」を記録・保存するサービスです
    ・管理イベント … ユーザーのログイン、EC2インスタンスの作成 など
    ・データイベント … S3上のオブジェクト(データ)の操作、Lambda関数の実行
    ・インサイトイベント … 通常と異なる操作(書き込みAPIの呼び出し)

    Amazon CloudWatch Logs
    Amazon CloudWatch LogsはAWSサービスやEC2インスタンスのOSやアプリケーションのログを収集し、一元管理するサービスです
    例)CloudTrailにおけるAWSサービスの操作ログや、VPCフローログ

    AWS CloudFormation
    AWSのリソースをコード化しプロビジョニング(構築)するサービスです。
    →IaC(Infrastructure as Code)

    AWS Elastic Beanstalkはアプリケーションが動作する定番の環境を自動で構築するサービスです。開発者は、用意された環境にアプリケーションをアップロードするだけでデプロイ(実行環境への展開)を行うことができます

    AWS Systems Manager Session Manager
    ・EC2インスタンスへマネジメントコンソールやAWS CLIからセキュアにログインできる機能
    ・プライベートサブネットにあるインスタンスへも踏み台サーバーなしで接続が可能

    セキュリティ、アイデンティティ、コンプライアンス
    WAF/Shield KMS/CloudHSM

    AWS Shield
    DDoS攻撃からの保護に特化したサービス

    AWS WAF(Web Application Firewall)
    脆弱性を突く攻撃(クロスサイトスクリプティングやSQLインジェクションなど)から、Webアプリケーションを保護するサービスです
    Web ACL地理的制限

    Network Load Balancer(NLB)とClassic Load Balancer(CLB)には対応していないので利用できません

    AWS Network Firewall
    ・VPC向けのファイアウォール機能
    ・侵入防止システム(IPS)やドメイン名によるトラフィックのフィルタリングなど、セキュリティグループやネットワークACLよりもさらに高度な機能
    ・VPC上のアウトバウンド及びインバウンド両方のトラフィックを検査可能
    ・特定のドメイン名を含むURLへのアクセスのみを許可したり、特定の送信元からのトラフィック以外は全てブロックするなど、きめ細かな通信の制御が可能

    ネットワーク、コンテンツ配信
    Route 53 CloudFront Global Accelerator Direct Connect/VPN

    CloudFront
    AWSが提供する高速でセキュアなコンテンツ配信ネットワークサービス
    ・「地理的制限」というクライアントからのアクセスを国別に制限できる機能があります

    フィールドレベル暗号化
    フィールドレベル暗号化は、ユーザーから送信されたHTMLフォームのPOSTリクエストのうち、一部のフィールドを暗号化し、特定のアプリケーションでのみ復号可能とするCloudFrontの機能です。

    アプリケーション統合
    SQS SNS

    SQS(Amazon Simple Queue Service)
    フルマネージドのメッセージキューイングサービスであり、サービス同士の橋渡しを担います。SQSはプル型なので、受信側の都合の良いタイミングでSQSへポーリング(問い合わせ)を行って、メッセージを受け取りま

    SNS(Amazon Simple Notification Service)
    プッシュ型のメッセージングサービス
    SNSはプッシュ型なので、サブクライバー(受信者)の状態に関わらずメッセージを配信します。
    トピックという単位で情報を管理

    分析
    Kinesis EMR Glue Athena

    AWS kinesisには大きく分けて3つの機能があります。

    • Amazon Kinesis Data Streams
    • Amazon Kinesis Data Firehose
    • Amazon Kinesis Data Analytics

    Kinesis Data Streams
    Kinesis Data Streamsはストリーミングデータを収集します。ストリーム上のデータは分析や機械学習などを行うアプリケーションがリアルタイムに読みだして処理します。

    Kinesis Data Firehose
    Kinesis Data FirehoseはストリーミングデータをAmazon S3やRedshiftなどへ配信するサービスです

    AWS Glue
    フルマネージドのサーバーレスETLサービス
    複数のデータソース(S3やDynamoDBなど)からデータを抽出し、変換・統合したデータをターゲット(Redshiftなど)へ格納
    ・クローラーはデータソースからデータの抽出を行い、データカタログを作成

    【チートシート】Linuc Lv1-102 実務での使用例も解説

    Linucとは

    Linuc(リナック)は、日本のNPO法人LPI-Japanが提供するLinux技術者向け資格試験です。2018年に開始され、従来のLPICに代わる新しい認定制度です。LPICを取得している人は簡単な手続きでLinuc資格を取得できます。

    Linucの概要

    Linucは、レベル1からレベル3までの3段階があり、上がるほど難易度が高くなります。

    • レベル1: 初級者向け(学習目安:半年~1年)
    • レベル2: 中級者向け(3~4年経験目安)
    • レベル3: 上級者向け

    試験は順番に取得する必要があり、レベル2を受験するにはレベル1が、レベル3を受験するにはレベル2が必要です。

    学ぶことで得られるメリット

    • 実践的なスキルの向上
      IT業界で必要とされる基本的なLinux操作を実践的に学べるため、サーバー運用やシステム管理に役立ちます。
    • キャリアアップに繋がる資格
      Linuxの基礎から応用まで網羅することで、インフラエンジニアやクラウドエンジニアとしてのスキルが証明できます。

    試験内容

    LinuC レベル1 出題範囲詳細 101試験 1.01 Linuxのインストールと仮想マシン • Linuxのインストール、起動、停止 • 仮想マシン・コンテナの概念と利用 • ブートプロセスとsystemd 1.02 ファイル・ディレクトリの操作 • ファイルの所有者とパーミッション • ハードリンクとシンボリックリンク 1.03 GNUとUnixのコマンド • コマンドライン操作とフィルタ • 正規表現とテキスト処理 1.04 リポジトリとパッケージ管理 • aptコマンドとDebianパッケージ • yumコマンドとRPMパッケージ 1.05 ハードウェアとファイルシステム • ハードウェアの基礎知識と設定 • ディスクレイアウトとパーティション • ファイルシステムの管理とマウント 102試験 1.06 シェルおよびスクリプト • シェル環境のカスタマイズ • シェルスクリプトの作成と実行 1.07 ネットワークの基礎 • インターネットプロトコルの基礎 • ネットワーク構成と問題解決 • クライアント側のDNS設定 1.08 システム管理 • アカウント管理とジョブスケジュール • ローカライゼーションと国際化 1.09 重要なシステムサービス • システム時刻とログの管理 • メール配送エージェント(MTA)の基本 1.10 セキュリティ • セキュリティ管理とホスト設定 • 暗号化とクラウドセキュリティ 1.11 オープンソースの文化 • オープンソースの概念とライセンス • コミュニティとエコシステム • 試験時間: 90分 • 問題数: 60問 • 合格基準: 70%以上 • 形式: 多肢選択式

    1.01:Linuxのインストールと仮想マシン・コンテナの利用

    1.06:シェルおよびスクリプト

    bash
    Bourne Again Shell

    環境設定ファイル

    ログイン時に実行される

    1)/etc/profile
    2)~/.bash_profile
    3)~/.bash_login
    4)~/.profile

    【全ユーザ】/etc/profileログイン時 1 1環境変数などaliasやfunction。
    【全ユーザ】/etc/bash.bashrcbash起動時 2環境変数を設定 alias
    Debian系
    【全ユーザ】/etc/bashrcbash起動時 5alias
    RedHat系
    【各ユーザ】~/.bash_profileログイン時 2 3環境変数など
    【各ユーザ】~/.bash_loginログイン時 3
    【各ユーザ】~/.profileログイン時 4
    【各ユーザ】~/.bashrcbash起動時 4aliasの設定
    【各ユーザ】~/.bash_logoutログアウト時ログアウト時実行させたい処理

    -dファイル名がディレクトリ名なら真
    -fファイルの場合は真
    -eファイルが存在するなら真
    -Lシンボリックリンクなら真
    -r読み取り可能なら真
    -w書き込み可能なら真
    -x実行可能なら真

    1.07:ネットワークの基礎

    /etc/hostname ファイル
    ホスト名が記述されている

    /etc/hosts ファイル
    ホスト名とIPアドレスの対応

    NetworkManager
    ネットワークを管理するサブシステム

    nmcli
    NetworkManagerではnmcliコマンドでネットワークの設定、接続の管理、状態の管理

    ip
    ネットワークインターフェイスやルーティングテーブル、ARPテーブルを管理

    ifconfig

    IPアドレスIPアドレスを設定する
    netmask サブネットマスクサブネットマスクを設定
    upネットワークインターフェースを有効化
    downネットワークインターフェースを無効化

    ifup ifdown
    ネットワークインターフェースの有効/無効化の操作

    ping

    traceroute

    tracepath tracepath6

    hostname [ホスト名]
    ホスト名を指定している場合ホスト名を変更、ホスト名を指定していない場合現在のホスト名を表示

    nmap
    ポートの状態

    netstat
    ネットワークに関する様々な情報を表示

    ss
    最近のディストリビューションではnetstatに代わって使用されている

    -n –numericサービス名の名前解決を行わない(ポート番号を表示)
    -r –resolve名前解決を行う
    「domain」の後ろには、通常はそのコンピュータが所属するドメインを指定します。
    このようにすると、名前解決の際にホスト名だけを入力したとき、
    domainの後ろに記述したドメイン名を付加して名前解決を行ってくれます。
    -e –extended詳細情報を表示
    -o –optionsタイマー情報も表示する
    -m –memory各ソケットのメモリの使用量も表示する
    -p –processesソケットを使用しているプロセスも表示する
    netstatソケット、インターフェイスごとのネットワーク統計など表示
    ss「ソケット」についての情報などを表示
    ※従来から移行 netstat → ss
    lsoflsofコマンドは、プロセスが開いているファイルを表示するコマンドですが、
    -iオプションを指定すると、開いているポートを確認できます。実行にはroot権限が必要です。
    nmap攻撃者がネットワーク経由で開いているポートを確認する行為をポートスキャンといいます。nmapコマンドでポートスキャンを行えます
    fuserポートを開いているプロセスを特定するには、fuserコマンドも使えます。

    nc(netcat)
    ネットワーク通信の確認

    ルーティングテーブルを表示
    route
    netstat -r
    ip route
    ip route show

    route
    ルーティングテーブルの表示、操作

    ifconfigコマンドインターフェースの状況を確認、設定
    ipコマンドOPTION [a(address 全てのIPアドレスを表示link route neigh ..]
    COMMAND [show add del]
    hostnameコマンドシステムのホスト名を確認したり、変更
    OPTION “-I(–all-ip-addresses)全てのIPアドレスを表示
    nmcliコマンドNetworkManagerを制御して、ネットワーク状況を確認、設定

    route ip route
    ▼追加
    route add default gw 172.17.0.1
    ip route add default via 172.17.0.1
    route add -net 192.168.0.0 gw 172.17.0.1 netmask 255.255.0.0 eth0
    ip route add 10.1.1.0/24 via 192.168.1.1

    ▼削除

    ip route delete default

    /etc/resolv.conf
    どこにあるDNSサーバを使用するか設定

    /etc/nsswitch.conf
    名前解決の手段の順序で使用するかを設定

    getentコマンド
    getentコマンドは、指定したデータベースからユーザーやグループの情報一覧を表示することができます。
    nsswitch.confの設定を確認するのに役立つ

    ドメイン→アドレス
    nslookup に代わる dig、host

    host
    ホストやドメインに関する情報を表示、デフォルトではホスト名とIPアドレスの変換をするコマンド

    dig
    digコマンドはDNSサーバに登録されている情報を詳しく表示
    digコマンド形式……dig @server domain query-type
    query-type例
    A: ネットワークアドレス (省略時)
    NS: ネームサーバ
    MX: メールサーバの情報
    SOAドメインのゾーン情報
    ANY: 知っているすべての情報
    TXT:テキスト情報

    システム管理

    重要なシステムサービス

    dateコマンド
    システム時刻を参照して現在の日時が表示されます。
    date [MMDDhhmm[[CC]YY][.ss]]
    「2020年3月4日10時」# date 030410002020

    date “+%Y%m%d”
    「年/月/日(曜日)」

    hwclockコマンド
    ハードウェア時刻の参照や設定を行います。設定にはroot権限が必要です。

    オプション
    -r –showハードウェア時刻を表示
    -w –systohcシステム時刻をハードウェア時刻に
    -s –hctosysハードウェア時刻をシステム時刻に

    timedatectlコマンド
    timedatectlコマンドで日付と時刻、タイムゾーンを管理できます。

    サブコマンド
    status現在の状態を表示(デフォルト)
    set-time 時刻時刻を設定
    set-time 日付日付を設定
    set-time 日付 時刻日付と時刻を設定
    set-timezone タイムゾーンタイムゾーンを設定
    list-timezonesタイムゾーン一覧を表示する
    set-ntp yes|noNTPを使うかどうか

    /usr/share/zoneinfoディレクトリ
    タイムゾーンの情報は、/usr/share/zoneinfoディレクトリ以下のバイナリファイルに格納

    ntpdateコマンド
    ntpdateコマンドを使うと、NTPサーバーから正確な時刻を取得できます。

    /etc/ntp.conf
    NTPサーバーの設定は/etc/ntp.confで行います。


    Chrony
    Chronyはntpd/ntpdateの代替となるNTPサーバー/クライアントソフトウェアです。デーモンプロセスchronydと、クライアントコマンドchronycから構成されます。

    chronyc [サブコマンド]
    chronydの管理はchronycコマンドで行います。

    syslog
    Linuxではsyslogを使って、さまざまなイベントをログファイルに記録したり、コンソールに表示したりできるようになっています。
    システムのログ(シスログ)を取得して処理するソフトウェアには、syslogのほか、rsyslogsyslog-ngなどが使われています。

    rsyslogの設定は、/etc/rsyslog.confファイルおよび/etc/rsyslog.dディレクトリ以下のファイルで行います。

    ファシリティ
    ログメッセージ生成元のプログラムは、メッセージにファシリティとプライオリティをタグ付けして出力します。ファシリティ(facility)はメッセージの生成元を表します。

    ファシリティ
    auth authpriv認証システム
    croncron
    deamon各種デーモン
    kernカーネル
    lpr印刷システム
    mailメールサービス
    userユーザーアプリケーションの出力
    local0~local7ローカルシステム

    loggerコマンド
    loggerコマンドを使ってログメッセージを生成することもできます。

    systemd-journaldデーモン
    systemdの動作するシステムではsystemd-journaldデーモンを動作させ、ログの一元管理を行います。systemd-journaldはsystemdから起動したプロセスの標準出力やsyslogへのログメッセージをバイナリ形式で記録します。

    /etc/systemd/journald.conf
    systemd-journaldの設定は/etc/systemd/journald.confで行います。

    systemd-catコマンド
    systemdを採用したシステムでは、systemd-catコマンドを使って、コマンドの実行結果をジャーナルに書き込むことができます。

    journalctlコマンド
    systemdを採用したシステムでは、journalctlコマンドを使ってsystemdのログ(ジャーナル)を閲覧できます。

    オプション
    -a –a省略せず表示
    -b –boot
    -f –follow新規に追加されたログをリアルタイムを表示
    -k –dmesgカーネルからのメッセージを表示
    -l –full全て表示
    -n –lines指定行数分表示
    (デフォルト10行)
    –no-pagerデフォルトで使われるlessコマンドを使用しない
    -o –output
    -r –reverse最古のログから表示(デフォルト)
    →最新のログから表示
    –since指定した日付時刻以降
    -u –unit特定のユニット
    –until指定した日付時刻まで表示

    logrotateコマンド
    logrotateコマンドを実行すると、ただちにログのローテーションを実施できます。-fオプションで設定ファイルを指定します。


    MTA
    電子メールを取り扱うソフトウェアには、MTA(Message Transfer Agent)やMDA(Mail Delivery Agent)、MUA(Mail User Agent)があります。

    mailqコマンド
    メールキューの内容を表示するには、mailqコマンドを使います。

    mailコマンド
    コマンドラインでメールを送信したり、受信メールを確認するには、mailコマンドを使います。

    /etc/aliasesファイル
    /etc/aliasesファイルを利用すると、メールアドレスの別名(エイリアス)を設定できます。
    この設定を有効にするには、newaliasesコマンドを使います。

    .forwardファイル
    各ユーザーのホームディレクトリに.forwardファイルを用意し、その中に転送先のメールアドレスを記述します。この方法は、一時的にメールを転送したい場合などに便利です

    セキュリティ

    SUID(Set User ID)
    所有者がrootユーザーであるプログラムにSUID(Set User ID)を設定すると、一般ユーザーが実行した場合でも、そのプログラムはroot権限で動作します

    chageコマンド
    有効期限の設定はchageコマンドで行います。

    オプション
    -l –list有効期限を表示
    -m –mindaysパスワード変更日数の最低日数を設定
    -M –maxdaysパスワードの最大有効期限日数を設定
    -d –lastdayパスワードの最終更新日を設定
    -W –warndays有効期限切れが何日前から警告するか設定
    -I –inactive有効期限後アカウントがロックされるまでの日数を設定
    -E –expiresdateアカウントが無効になる日付を指定

    whoコマンド
    ユーザーのログイン状況やログイン履歴を把握することで、不審なログインを見つけ出すことができます。ログイン中のユーザーを調べるには、whoコマンドを使います。

    wコマンド
    wコマンドを使うと、ログイン中のユーザーに加え、システム情報も表示されます

    lastコマンド
    lastコマンドを使うと、最近ログインしたユーザーの一覧を表示します。


    開いているポートを確認するには、netstatコマンドやssコマンド、lsofコマンドを使います。

    netstatソケット、インターフェイスごとのネットワーク統計など表示
    ss「ソケット」についての情報などを表示
    ※従来から移行 netstat → ss
    lsoflsofコマンドは、プロセスが開いているファイルを表示するコマンドですが、
    -iオプションを指定すると、開いているポートを確認できます。実行にはroot権限が必要です。
    nmap攻撃者がネットワーク経由で開いているポートを確認する行為をポートスキャンといいます。nmapコマンドでポートスキャンを行えます
    fuserポートを開いているプロセスを特定するには、fuserコマンドも使えます。


    /bin/false
    /sbin/nologin
    ユーザーのログインシェルを/bin/falseや/sbin/nologinに変更すると、一般ユーザーのログインを禁止することができます。

    ulimitコマンド
    ulimitコマンドを使うと、ユーザーが利用できるリソースを制御できます。

    オプション
    -a制限の設定をずべてひょうじ
    -c サイズコアファイルのサイズを指定
    -f サイズシェルが生成できるファイルの最大サイズを指定
    -n 数同時に開けるファイル数を指定
    -u プロセス数ユーザが利用できる最大のプロセス数を指定
    -v サイズ最大仮想メモリサイズ

    suコマンド
    suコマンドを使うと、一時的に別のユーザーになることができます。

    sudoコマンド
    特定の管理者コマンドのみの実行を許可したい場合は、sudoコマンドが利用できます。sudoコマンドを使えば、任意の管理者コマンドを任意のユーザーに許可することができます。


    inetd
    xinetd
    常駐するデーモンの数が多くなると、待機中のデーモンが消費するシステムリソースもそれだけ大きくなります。
    inetdやxinetdといったスーパーサーバーは、他のサーバープログラムに代わってサービス要求を監視し、接続が確立した時点で本来のサーバープログラムに要求を引き渡します。

    /etc/xinetd.conf
    xinetdの設定は、全体的な設定を行う/etc/xinetd.confファイルと、xinetd.dディレクトリ(通常は/etc/xinetd.d)以下にあるサービスごとの設定ファイルから構成されます。

    /etc/inetd.conf
    inetdの設定ファイルは/etc/inetd.confです。1行につき1つのサービスを設定します。サービスを無効にするには、該当するサービスの行頭に「#」を記述しコメント化します。

    /etc/nologin
    /etc/nologinファイルを作成しておくと、rootアカウントによるログイン以外は禁止されます。

    Netfilter
    Linuxカーネルには、Netfilterというパケットフィルタリング機能が備わっています。

    iptablesコマンド
    iptablesコマンドを使ってパケットフィルタリングのルールを細かく設定することができます。

    firewalld
    CentOS 7以降では、ファイヤウォールサービスとしてfirewalldが搭載されました。

    firewall-cmd –remove-service=dhcpv6-client
    ※ 即座に設定が反映されますが、再起動等の reload 時に設定が戻ってしまいます。
    →設定が戻らないようにするには –permanent を付け加えます。

    firewall-cmd –permanent –remove-service=dhcpv6-client
    ※ 設定は恒久的に残りますが、即座には反映されません
    →reload 等が必要です。

    「–zone=ゾーン」を指定しない場合は、デフォルトのゾーン(初期値はpublic)についての操作になります。

    sshに使われる暗号化アルゴリズム

    アルゴリズム
    RSA広く普及
    DSA広く普及、安全性に懸念あり
    ECDSA小さな鍵長、高速
    ED25519安全性が高い、高速、DSAやDCDSAより安全性が高い

    ssh-keygen
    公開鍵と秘密鍵のペアを作成する


    GnuPG(GNU Privacy Guard)
    ファイルを暗号化したい場合利用

    gpg コマンド
    GnuPG
    を利用するために使います。

    ホスト認証

    1. ホスト公開鍵を登録

    オープンソースの文化

    コピー
    レフト
    GPLフリーソフトウェア財団(FSF)
    AGPLインターネット経由でもソースコードの開示を要求
    LGPLライブラリ用
    MPLMozilla Foundation
    BSD License×カリフォルニア大学のバークレー校
    MIT License×マサチューセッツ工科大学
    Apache License×Apacheソフトウェア財団(ASF)
    いずれのライセンスでも著作権免責事項表記が義務付けられている
    ワイヤーフレーム、デザインカンプとは

    ワイヤーフレーム

    ワイヤーフレームとはWebサイトのレイアウトを決めるものです。

    デザインやコーディングに入る前に、作成し完成イメージを共有します。

    デザインカンプ

    デザインカンプとは「Design Comprehensive Layout」の略です。

    サイト制作では、クライアントにデザインカンプをいくつか提案し、採用されたものを元に製作を進めるのが一般的な流れとなります。

    Sass導入方法、WordPress に SCSS を導入

    Sassとは

    Scssのメリット

    CSSを効率よく書けることや管理、メンテナンスが楽になることがあります。

    • 変数
    • ネスト記法
    • mixin
    • 関数

    Sass導入方法

    SassはCSSと違いHTMLファイルで読み込めないので、CSSファイルにコンパイルする必要があります。

    よく紹介されている、VSCodeの拡張機能Live Sass CompilerはDartSassに非対応です。

    またDartJS Sass Compiler and Sass Watcherという拡張機能もあるのですが、個人的にパスの設定等が難しく感じました。

    そこで今回はVSCodeの拡張機能をしようせず、Sassをコンパイルする方法を紹介します。

    1)パソコンにNode.jsをインストールする

    Node.js公式サイトからダウンロードしインストールします。

    インストールされているか、過去にインストールしていたかの確認はコマンドを打つことで調べれます。

    Macの場合ですと、ターミナルで行います。

    画面上部の虫眼鏡のアイコンで「ターミナル」と検索します。

    一応現在のディレクトリを確認します。

    pwd
    node -v

    node.jsのバージョンが分かります。

    バージョンが表示されていれば、インルトールされていることが分かります。

    2)作業するフォルダ(ディレクトリ)を作成

    作成する内容は以下の通りです。

    • sass-lesson(作業フォルダ)
      • src
        • style.scss
      • index.html(任意)

    2)VSCodeで作業フォルダにてSassをインストール

    ▼ VSCodeでターミナルを開く

    VSCodeのメニューでターミナルを選ぶと現在作業しているディレクトリにいる状態で開いてくれます。

    そのまま作業ディレクトリ上でコマンドを入力します。

    ▼ npmをインストール

    npm init -y

    ※init…(イニシャライズ)初期化の意味

    コマンドを入力するとpackage.jsonが生成されます。

    ▼ Sassパッケージをインストール

    npm install --save-dev sass

    コマンドを入力するとnode_modules、package-lock.jsonが生成されます。

    package.jsonとは手順を共有することができるもので、料理のレシピのようなものですが、

    中身を見るとSassが追加されていることが確認できます。

    3)コンパイルする

    ▼ コンパイルるすためpackage.jsonの内容を書き換えます。

    "scripts": {
        "sass": "sass src/style.scss css/style.css"
    },

    ▼ コンパイルする

    npm run sass

    先ほどpackage.jsonに書いた”sass”を実行したということです。

    正常にCSSが生成されました

    WordPress オリジナルテーマに SCSS を導入

    my-original-theme/
    ├─ functions.php
    ├─ style.css   ← WordPress テーマ識別用 (テーマヘッダーコメント用)
    └─ css/
       ├─ base/
       │   └─ _base.scss
       ├─ mixin/
       │   └─ _mixin.scss
       ├─ modules/
       │   ├─ _c-animation.scss
       │   ├─ _c-footers.scss
       │   ├─ _c-form.scss
       │   ├─ _c-header.scss
       │   ├─ _c-layout.scss
       │   ├─ _c-pagetop.scss
       │   ├─ _c-paging.scss
       │   ├─ _c-parts.scss
       │   └─ _index.scss
       ├─ page/
       │   ├─ _about.scss
       │   ├─ _column.scss
       │   ├─ _contact.scss
       │   ├─ _diagnosis.scss
       │   ├─ _expert.scss
       │   ├─ _home.scss
       │   ├─ _index.scss
       │   ├─ _reviews.scss
       │   ├─ _vendor.scss
       │   └─ _voice.scss
       ├─ plugins/
       │   └─ _index.scss
       ├─ setting/
       │   └─ _setting.scss
       ├─ style.scss         ← SCSS のメインファイル
       └─ style.css          ← コンパイル後の CSS (WordPress で実際に読み込むファイル)
    

    ローカル開発環境でコンパイル

    レンタルサーバー上でNode.jsやDart Sassを動かすのはややハードルが高く、ローカルでのコンパイルが一般的です

    プロジェクト単位でインストール(グローバルでない)

    node -v
    # package.jsonの作成
    npm init -y  # -y フラグで全てデフォルト設定
    # 開発時のみ必要な依存関係(devDependencies)としてパッケージをインストールするオプション
    npm install sass --save-dev

    ソースマップの生成

    SCSSファイルをブラウザの開発者ツールで参照できるようになり、本番環境で問題が発生した際に、圧縮されたコードではなく元のコードで調査可能でデバッグがしやすくなります

      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "sass": "sass style.scss:style.css --watch --no-source-map"
      },
    
    下記に変更
    
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "sass": "sass style.scss:style.css --watch --source-map --embed-sources"
      },
    npm run sass

    注意点:

    • 本番環境ではセキュリティの観点からソースマップを無効にすることが推奨されます
    • ソースマップを有効にすると、ファイルサイズが大きくなることがあります

    実際のSCSSファイルは存在しなくても、ソースマップを通じてブラウザの開発者ツールで元のSCSSの内容を見ることができるようになるため参照できます。

    必要なファイルのみを本番環境に公開

    公開すべきファイル:
    css/
    ├── style.css     (コンパイル済みのCSSファイル)
    └── style.css.map (ソースマップファイル)
    
    開発環境に残すファイル:
    css/
    ├── node_modules/
    ├── package.json
    ├── package-lock.json
    ├── style.scss
    ├── style.min.css      # 使用しない場合は不要
    └── style.min.css.map  # 使用しない場合は不要
    ファイル構成とアップロード要否 /css 必須ファイル: style.css (メインのCSSファイル) style.css.map (ソースコードが埋め込まれたマップ) アップロード不要ファイル: style.scss (ソースマップに内容が含まれる) style.min.css (非圧縮版を使用する場合は不要) style.min.css.map (圧縮版を使用しない場合は不要) ※ –embed-sources オプションにより、.mapファイルにSCSSのソースコードが埋め込まれます ※ 非圧縮版(style.css)を使用する場合、圧縮版(.min)関連ファイルは不要です

      WordPressのfunctions.php で enqueue する

      WordPress でテーマの CSS を読み込む場合、functions.php 内で wp_enqueue_style() を使います。
      例えば css/style.css を読み込むには下記のように記述します。

      <?php
      function mytheme_enqueue_scripts() {
        // テーマディレクトリ (style.css までの絶対パス)
        $theme_css = get_template_directory_uri() . '/css/style.css';
      
        // 第1引数: ハンドル名, 第2引数: CSSファイルのURL, 第3引数: 依存関係, 第4引数: バージョン, 第5引数: メディア
        wp_enqueue_style('mytheme-style', $theme_css, array(), '1.0.0', 'all');
      }
      add_action('wp_enqueue_scripts', 'mytheme_enqueue_scripts');
      

      WordPressSCSSS運用について

      1. キャッシュバスティング
        • CSS を更新したときにキャッシュが残って画面に反映されないことがあるため、wp_enqueue_style() の第4引数にバージョン番号を設定したり、ファイルの更新時刻を付与するなど対策しておく。
      2. SCSS の管理方法
        • 大規模になってくると、フォルダ構造の整理と規約 (例えば BEM など) の導入を検討するとメンテナンスが楽になる。
        • _index.scss は「単一フォルダ内のファイルをまとめるための import 専用」などの目的で使うとスッキリする。
      3. minify
        • 本番環境にデプロイする際は css/style.min.css という形で圧縮ファイルを吐き出すケースも多い。
        • 圧縮版と開発版を分けるかどうかはプロジェクト次第。
      【VSCode】Visual Studio Code ショートカット

      ショートカットキー

      カーソルがある行を複製

      • macOS:Ctrl + Shift + ↑/↓、
      • Windows:Shift + Alt + ↑/↓

      すべて折りたたむ

      Ctrl+K Ctrl+0

      全て折りたたまれており一つずつ展開して使用すると素早く作業できます

      何の閉じタグかを分かりやすくする方法

      タグ名.クラス名|c

      figma

      ショートカットキー

      Fnキー + Fフレームの作成
      shiftキー + Fガイドの表示切り替え
      shiftキー + 矢印10pxずつ移動
      command + Gグループ化
      option + command + Gフレーム化
      command + [再背面へ移動

      コピー&ペーストについて

      command + shift + V貼り付け先のスタイルにあわせてペースト
      command + shift + C → command + V貼り付け元のスタイルのみ貼り付け

      レイアウトグリッド

      レイアウトグリッドのが使いやすいです。

      12列にすると、2、3、4カラムで使えて便利です。

      余白の設定もできるので、max-width: 〇〇pxのコンテナ幅でデザインを作成する場合に便利です。

      コンポーネント機能でフッターメニューを作成

      1)メニュー(top、about、service、faq、contact)からひとつフッターエリアへ移動しテキストの色を変更し、フレーム化します(option + command + G)

      2)オートレイアウト化し、左右の余白を調整

      右側だけ線を付けます

      3)コンポーネント化します。

      4)コンポーネント化したものをまとめる場所に移動させ、複製し元の場所に戻します。

      5)複製し、テキストをコピーします。(command + shift + V …スタイルはコピーしない)

      6)オートレイアウト化します。

      オートレイアウト化することで隙間をそろえて先ほど作成した、コンポーネントを調節することでフッターメニュー全てが一括で変更できます。

      このようにデザインする際コンポーネント化し、それを制作物のフレームと別のフレームで管理すると便利です。

      コンポーネント化解除したいとき

      コンポーネント化したものを編集したい時など、解除したいときはあると思います。

      コンポーネント化を解除することはできないので、一度インスタンス化したものを右クリック→メニューから[インスタンスの切り離し]選択し、フレームに戻します。

      便利プラグイン

      https://note.com/itaru_cgart/n/n76a451cf2619
      CSSサンプルコードまとめ

      display: flex;

      row左から右への横並び
      column上から下
      row-reverserowの逆
      column-reversecolumnの逆
      <flex-directionプロパティ>

      flex-shrink

      flexアイテムの縮小率を指定するプロパティです。親要素のflexコンテナからはみ出た要素を縮小することができます。

      また幅を縮めたくないときは、flex-shrink: 0;を指定します。

      親要素にdisplay: flex;を指定し、子要素にflex-shrinkを指定します。

      flex

      flexとは、flex-growflex-shrinkflex-basisを同時に指定できるプロパティです。

      flex: 1;

      flex-grow: 1;flex-shrink: 1;flex-basis: 0;を同時に指定できるプロパティです。

      flex-grow: 1;親要素の余っているスペースを整数で設定した比率で分配
      flex-shrink: 1;親要素からはみ出たスペースを整数で設定した比率で縮める
      flex-basis: 0;width、heightのように幅を初期値を設定できる
      デフォルト値=autoを0で記載
      https://miyattiblog.com/explanation-of-flex-property/

      gapプロパティー

      gapプロパティーはFlexboxおよびGridで要素間の間隔を設定できます。

      display: grid;

      CSS Gridで中央揃え

      .sample {
      background: #222;
      color: #fff;
      display: grid;
      place-items: center;
      padding: 60px;
      }
      gridで中央寄せ
      https://developer.mozilla.org/ja/docs/Web/CSS/grid-template-columns

      よく使うコード

      https://ntorelabo.com/?p=4671#co-index-68

      リスト 左寄せ揃えかつ中央寄せ

      • リストを
      • 左の書き出し位置は揃えつつ
      • 画面中央位置に寄せたい場合

      ▼ulの親要素、ulに下記のスタイルをあてる

      .list-center {
      text-align: center;
      }
      .list-center ul {
        text-align: left;
        display: inline-block;
      }
      • リストを
      • 左の書き出し位置は揃えつつ
      • 画面中央位置に寄せたい場合

      カラム子要素 下揃え

      各カラムでテキストの量に違いがあったりする場合、カラム下部子要素の高さ位置がバラバラになってしまうことがあると思いますが、CSSで下ぞろえにすることができます!

      各カラムで下部子要素の高さをそろえたいとき、CSSで可能です!

      各カラムでテキストの量に違いがあったりする場合、カラム下部子要素の高さ位置がバラバラになってしまうことがあると思いますが、CSSで下ぞろえにすることができます!

      
      .columns-f .wp-block-column {
      display: flex;
      flex-direction: column;
      }
      .columns-f .wp-block-column div:last-child {
      margin-top: auto!important;
      }

      各カラムでテキストの量に違いがあったりする場合、カラム下部子要素の高さ位置がバラバラになってしまうことがあると思いますが、CSSで下ぞろえにすることができます!

      各カラムで下部子要素の高さをそろえたいとき、CSSで可能です!

      各カラムでテキストの量に違いがあったりする場合、カラム下部子要素の高さ位置がバラバラになってしまうことがあると思いますが、CSSで下ぞろえにすることができます!

      その他

      https://find-a.jp/seotimes/11-flow-designs
      https://jito-site.com/flexbox-bottom-alignment-button/
      【WordPress】カスタムフィールド作成の仕方「ACF」Advanced Custom Fieldsの使用法

      そもそもカスタムフィールドとは

      WordPressの投稿画面にはタイトル、本文、抜粋といった項目がもともとありますが、カスタムフィールド機能はさらに追加で新しい入力項目を設定することができます。

      • WordPressに詳しくない人でも編集がしやすくなります。
      • データ管理しやすくなります。

      例)「求人投稿」というカスタム投稿があった場合

      仕事内容、応募条件などの情報をカスタムフィールドに設定

      →投稿者さんが簡単に編集できるようになります

      カスタムフィールド作成の仕方「ACF」Advanced Custom Fieldsの使用法

      1)「ACF」Advanced Custom Fieldsをダウンロード

      ▽「新規プラグインを追加」より、「Advanced Custom Fields」をダウンロード → 「有効化」

      2)フィールドグループを作成

      〇フィールドグループを新規作成

      ワードプレス管理画面メニュー「ACF」より「フィールドグループ」をクリック

      ▽「新規追加」か「フィールドグループを追加する」をクリック

      〇フィールドグループの各フィールドを入力

      ▽フィールドの各項目を入力

      例)

      • フィールドグループタイトル:工房情報
        • 全般
          • フィールドタイプ:テキスト
          • フィールドラベル:所在地
          • フィールド名:location
          • 初期値:未記入
      フィールドタイプテキスト、画像、ラジオボタン等あります
      フィールドラベル編集ページに表示されます
      フィールド名テンプレートファイルを編集する際に使用
      初期値新規投稿作成時に表示されます

      ▽フィールドグループの各項目を入力

      例)

      • フィールドグループタイトル:工房情報
        • 検証
          • 必須項目:未記入
          • 文字数制限:未記入

      ▽「フィールドを追加」

      同様の手順で下記の通りフィールドを入力しました

      例)

      • 全般
        • フィールドタイプ:画像
        • フィールドラベル:アイコン画像
        • フィールド名:img_icon
      • 戻り値の形式:画像配列
      • ライブラリ:すべて

      〇フィールドグループの設定

      カスタムフィールドを表示するために「ルール」を設定できます

      プラグイン「Custom Post Type UI」で作成したカスタム投稿タイプのときだけ表示することもできます

      3)カスタムフィールドを使用した記事を投稿する

      ▽作成したカスタムフィールドが表示されるので、入力し記事を公開

      4)作成した記事カスタムフィールドの表示

      WordPressテーマ「SWELL」使用している場合、フィルターフックによる方法がオススメです

      ▽functions.phpを編集(ひとまずフィルターフックの出力を確認)

      add_filter('the_content', function() {
      	if (is_singular('workshop')) {
      		$html  = $the_content;
      		$html  .= '出力するコード';
      		return $html ;
      	}
      });

      下記の通り$the_content直下に表示させることができます

      ▽functions.phpを編集(カスタムフィールドの出力)

      add_filter('the_content', function($the_content) {
      	if (is_singular('workshop')) {
      		
      		// ACFで設定した画像を取得 ※関数内で宣言
      		$Landscape = get_field('landscape');
      		$ImgIcon = get_field('img_icon');
      
      		$html  = $the_content;
      		$html .= '<div class="work-shop-landscape" style="background: linear-gradient(rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.4)), url('.$Landscape['url'].');"></div>';
      		$html .= '<img class="work-shop-img-icon" src="'.$ImgIcon['url'].'">';
      		$html .= '<p>'.get_field('location').'</p>';
      		return $html;
      	}
      
      	// トップページで何も表示されなくなるため
      	else {
      		return $the_content;
      	}
      });

      Advanced Custom Fieldsの画像フィールドの使い方と応用方法
      https://usagicode.com/wordpress/how-to-use-acf-image-field/

      【SWELL 】カスタムフィールドの値を詳細記事テンプレート(single.php)に表示するカスタマイズ
      https://note.com/swell_mania/n/n9d7f8ea13eb2

      方法(2)foreach文を入れる場合方法(1)の記述方法がわからないので、アクションフックを使用した出力方法で

      ▽functions.phpを編集

      add_action('the_content', function($html) {
      	if(is_singular('workshop')) {
      		// ACFで設定した画像を取得 ※関数内で宣言
      		$Landscape = get_field('landscape');
      		$Icon = get_field('img_icon');
      		$Loction = get_field('location');
      		?>
      		<div class="work-shop-landscape" style="background: linear-gradient(rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.4)), url(<?php echo esc_attr($Landscape['url']); ?>);"></div>
      		<div class="work-shop-headerInfo">
      			<div class="work-shop-icon-wrapper"><img class="work-shop-icon" src="<?php echo esc_attr($Icon['url']); ?>"></div>
      			<div class="work-shop-icon-desc">
      				<div class="work-shop-tag">
      					<?php 
      						$terms = get_the_terms($post->ID, 'area');
      						if ($terms) {
      							foreach ($terms as $term) {
      								// echo '<a class="tagc-area" tag-id="' . $term->term_id . '" href="' . get_permalink() . '">' . $term->name . '</a>';
      								// aタグのリンクを無効
      								echo '<a class="tagc-area" tag-id="' . $term->term_id . '" href="">' . $term->name . '</a>';
      							}
      						}
      						$terms = get_the_terms($post->ID, 'tag-workshop');
      						if ($terms) {
      							foreach ($terms as $term) {
      								// echo '<a class="tagc-tag-workshop" tag-id="' . $term->term_id . '" href="' . get_permalink() . '">' . $term->name . '</a>';
      								// aタグのリンクを無効
      								echo '<a class="tagc-tag-workshop" tag-id="' . $term->term_id . '" href="">' . $term->name . '</a>';
      							}
      						}
      					?>
      				</div>
      				<!-- /.work-shop-tag -->
      				<div class="work-shop-location"><?php echo esc_attr($Loction); ?></div>
      				<!-- /.work-shop-location -->
      			</div>
      			<!-- /.work-shop-icon-desc -->
      		</div>
      		<!-- /.work-shop-headerInfo -->
      		<?php
      	}
      
      	// トップページで何も表示されなくなるため
      	else {
      		return $html;
      	}
      });

      【WordPress】本文入力欄を非表示にする方法

      参考サイト

      【完全版】Snow Monkeyでカスタム3兄弟を実装する 
      https://ippei-kusakari.com/web/snow-monkey/custom-post

      Advanced Custom Fieldsの画像フィールドの使い方と応用方法
      https://usagicode.com/wordpress/how-to-use-acf-image-field/

      【SWELL 】カスタムフィールドの値を詳細記事テンプレート(single.php)に表示するカスタマイズ
      https://note.com/swell_mania/n/n9d7f8ea13eb2

      【サンプルコード付き】カスタムフィールドの値を一覧ページに表示するカスタマイズ
      https://webrent.xsrv.jp/display-customfield-on-archive-pages

      カスタムフィールドの値でソートをかける方法

      <?php /* 取得する投稿の条件 */ ?>
          <?php
          $args = array(
              'post_type' => 'post', /* 取得したい投稿タイプ */
              'category_name'  => 'job',
              'posts_per_page' => -1, /* 表示したい投稿の数 (すべての取得したい場合は「-1」) */
              'orderby' => 'meta_value', 
              'meta_key' => 'price', //ここにソートの対象となるカスタムフィールドの名前を
              'order' => 'DESC'
          );
          $the_query = new WP_Query($args); /* クエリの作成と発行をし、取得したデータを「$the_query」に格納 */
          ?>

      テーブルのソートはWordPressのプラグインで便利なものがあります。

      table要素のクラス名をtablesorterとすればOK

      headerAheaderBheaderC
      1中央区30万
      2港区20万
      3千代田区25万
      4中央区20万

      【初心者】Excelよく使う関数

      業務の効率化を考える上で関数はすごく便利、とくによく使うものを今回ご紹介します。

      DATE関数

      「年」、「月」、「日」を引数に指定し、日付を作成する関数

      =DATE(年,月,日)

      Word、Excelの小技

      改ページ位置の設定

      見出しとその内容が別のページに分かれてしまう場合があります。

      見出しと内容をまとめて、次のページから開始するようにせっていすることができます。

      ホームタブ → 段落グループ → 段落の設定 → 改ページと改行タブ → 次の段落と分離しないを✓にします

      複数行の文字を前で囲む方法

      1. 囲みたい複数行を選択する
      2. 「Alt」→「A」→「B」
      3. 「線種とページ罫線と編みかけの設定」を表示
      4. 「罫線タブ」で囲む→OK

      Excelのセルの連番入力

      「Ctrl」を押しながら、セルの右下をドラッグ

      行の高さの自動調整

      ホームタブ→セルの書式にて設定

      インフラエンジニアとは

      そもそもインフラとは

      インフラとはインフラストラクチャー(Infrastructure)の略です普段の生活の基盤を意味します。

      例えば公共交通機関、公共施設、電気・ガス・水道など、日々の暮らしにに欠かせない設備です。

      インフラエンジニアとは

      インフラエンジニアはその名の通り、インフラストラクチャーを管理するエンジニアです。 IT環境の下支えをするようなイメージです。

      ネットワーク、サーバーなどを設計・構築・運用・保守を手がける技術者がインフラエンジニアです。

      インフラエンジニアの中でもいくつか分かれますが、分かりやすく2つに大別すると下記の通りです。

      • サーバエンジニア
      • ネットワークエンジニア
      • セキュリティエンジニア

      システムエンジニア(SE)との違いは?

      インフラエンジニアと似た職種に、システムエンジニア(SE)があります。

      インフラエンジニアサーバーやネットワークなどのIT基盤を扱うのに対し、システムエンジニアはソフトウェアやアプリケーションなど主にシステムの開発を行う技術者です。

      インフラエンジニアが構築した基盤の上で動作するシステムをシステムエンジニアが開発・運用するという関係です。

      インフラエンジニアの種類

      先ほども紹介したように、インフラエンジニアは担当する領域や業務内容によって、いくつかの種類に分かれます。主に次のような種類があります。

      個人的にはインフラエンジニアの最初の仕事はサーバエンジニアよりの仕事が多いのかなと思っています。 理由としては、そこまで知識がなくてもなんとなくわかるからです。(一方、ネットワークエンジニアはネットワークに関する知識が必要なので少し専門的ですね。)

      具体的な仕事内容は様々ですが、基本的には下記に分類されるかと思います。(下に行くほど高難度です)

      • 運用保守
      • 構築
      • 設計

      サーバーエンジニア

      サーバーの構築や運用、保守を行います。

      メールサーバーやWebサーバー、DBサーバーなどさまざまなサーバーを設計・構築したり、障害が発生した時の対応を含めた運用・保守を行います。

      また、サーバー機器をラックに設置したり、他の機器とケーブルの配線等、物理的な作業もします。

      ネットワークエンジニア

      コンピューターなどの機器をルーターやLANケーブルでつなぎ、ネットワーク環境を設計・構築・運用します。

      作成した設計書に基づいたネットワーク環境を作り、トラブルや不具合がないようチェックしながら運用・保守を行います。

      セキュリティエンジニア

      情報セキュリティに特化したエンジニアです。

      • セキュリティ機器を導入
      • サイバー攻撃やウイルス感染の防止

      インフラエンジニアの給料や残業

      給料面はインフラエンジニアは全エンジニアの中では平均的かと思います。 (感覚になりますが、平均年収450〜550くらいのレンジかと) が、尖ったスキルがあると給料は青天井です。

      例えば、 「クラウドの中でもAWS(Amazonが出しているサービス)は誰にも負けません」 だったり、 「ネットワークの知識は誰にも負けないので、設計から構築、運用まで任せてください」 などです。

      これは専門職なので当然の流れではありますが、広く浅くよりも狭く深くの方が希少な人材として給与が高くなる傾向があると思います。

      残業や深夜の仕事については、インフラエンジニアは大いにあり得ると考えていただいた方が良いです。 特にサーバを更新、停止する際は長期休暇などを利用することが多いです。

      また、サーバ停止などによって業務がストップした場合は、緊急で呼び出されたりすることもあります。 なので、一般的なインフラエンジニアは「激務だなぁ」と思われることが多いかもしれません。 ただ、これもポジションによって大きく変わります。 イメージとしては、末端の作業をするほど上記のような対応が多いです。 設計フェーズの上流対応であれば、残業はあるかもしれませんが、緊急対応などは少なくなりますね。

      インフラエンジニアに必要なスキル・知識

      ・自己研鑽を続けている

      IT業界は技術革新のスピードがとても速く、日々新しいテクノロジーが生まれています。

      ほかのエンジニア同様インフラエンジニアとして活躍するためには、日ごろから最新の技術をインプットし、自己研鑽を続けることが必要です。

      最近では、クラウド上の設計・構築のニーズが高まっています、そこで実務では経験がない人も、クラウド関連の資格で転職の際にアピール材料とすることも可能です。

      ・マネジメント経験がある

      インフラエンジニアとして一定のキャリアを積んだ人は、さらにチームマネジメントの経験が求められます。

      インフラエンジニアに必要な資格

      ・基本情報技術者試験/応用情報技術者試験

      情報処理に関する国家資格です。

      出題範囲はインフラ、セキュリティだけでなくIT全般となり、あらゆる知識の土台として有効です。

      ・CCNA/CCNP

      ネットワーク機器メーカーのシスコシステムズが提供するベンダー資格です。

      世界的に有名な資格であり、取得すればネットワークエンジニアとしての証明になります。

      ・LPIC/LinuC

      どちらもLinux技術者としての技術力を認定する資格です。

      特にLinuCは日本市場のニーズに合わせて開発された試験です。Linuxシステムの知識だけでなく、さらにクラウドシステムの知識、スキルを有した技術者であることの証明になります。

      ・AWS 認定ソリューションアーキテクト

      Amazonが提供するクラウドの知識を証明する中級レベルの認定資格です。AWSを一年以上使った実務経験者が対象となります。

      https://ntorelabo.com/?p=4144
      WordPressのデバッグログ設定と確認方法

      wp-config.phpの設定

      WordPressのデバッグ機能を有効にするために、wp-config.phpに以下の設定を追加します:

      デバッグモードを有効化
      define('WP_DEBUG', true);
      define('WP_DEBUG_LOG', true);
      define('WP_DEBUG_DISPLAY', false);

      エラーの種類

      1)自動的に出力されるログ

      • データベース接続エラー
      • PHP自体のエラー(Fatal Error, Warning, Notice)
      • WordPressコア、テーマ、プラグインからのエラー
      • データベースクエリエラー

      2)error_log()による明示的なログ

      error_log('カスタムメッセージ: ' . $変数);
      • 開発者が意図的に出力する情報
      • デバッグ目的のカスタムメッセージ
      • 特定の処理の実行確認

      debug.logの権限確認と設定

      SSHでサーバーに接続

      WordPressのwp-content/フォルダで権限確認

      # 現在の位置を確認し、wp-contentディレクトリに移動します
      cd public_html/wp-content/
      
      # wp-contentディレクトリ内のファイル一覧と権限を確認
      ls -la wp-content
      
      # 下記の出力
      
      [xx@svxxx public_html]$ cd wp-content/
      [xx@svxxx wp-content]$ ls -la
      合計 244
      drwxr-xr-x  8 [所有者] members    179  1月  5 20:55 .
      drwx--x--x 18 [所有者] members   4096  1月  5 18:24 ..
      -rw-r--r--  1 [所有者] members 226399  1月  5 21:15 debug.log
      -rw-r--r--  1 [所有者] members     28  1月 26  2022 index.php
      drwxr-xr-x  4 [所有者] members   4096  1月  5 17:42 languages
      drwxr-xr-x 14 [所有者] members   4096  1月  5 20:48 plugins
      drwxr-xr-x  5 [所有者] members    110  1月  5 20:55 themes
      ....

      -rw-r--r-- → 644(読み取り専用)

      この管理者権限の設定で

      • 所有者(6): WordPress(PHP)が書き込み可能
      • 閲覧者(4): 管理者やツールが読み取り可能
      debug.log 644 所有者(6) 閲覧者(4) 書き込み 読み取り

      もし権限がちがっていたら変更

      # debug.logファイルの権限を変更(書き込み可能に)
      chmod 666 wp-content/debug.log

      ログの確認

      tail -f debug.log    # リアルタイムで監視
      # または
      tail -n 50 debug.log # 最後の50行を表示

      権限の見方:

      4. ログファイルの確認方法

      # ログファイルの内容を表示
      cat wp-content/debug.log
      
      # ログをリアルタイムで監視
      tail -f wp-content/debug.log

      debug.logを削除し管理

      debug.logを削除しても、次にデバッグログを出力する必要が生じた時点で、WordPressは自動的に新しいdebug.logファイルを作成します。

      いくつかのおすすめの管理方法をご紹介します:

      1. 定期的なクリーンアップ
      • サイトの状況に応じて、月1回や四半期に1回など、定期的なタイミングで削除
      • 特に問題調査後は、不要なログが残り続けることを防ぐため削除を検討
      1. サイズベースの管理
      • ファイルサイズが一定量(例:10MBなど)を超えたら削除
      • サーバー容量の節約にもなります
      1. ログローテーション より高度な方法として、ログローテーションの仕組みを導入することもできます。これにより:
      • 古いログを自動的にアーカイブ
      • 一定期間経過したログを自動削除
      • ファイルサイズの制限

      デバッグ情報の出力方法

      PHPファイルでログを出力する例:

      // 基本的なログ出力
      error_log('Debug message here');
      
      // 配列やオブジェクトの内容を出力
      error_log(print_r($variable, true));