この記事は「Vektor WordPress Solutions Advent Calendar 2021」の12月23日の記事になります。
WordPressでオリジナルのブロックを開発してみたいけど、難しそうだなぁ。ビルドとか超面倒そうだなぁという人、時代に取り残されたレガシーエンジニアがブロック開発のとっかかりをつかめる記事となっております。

みなさん、こんにちは。

今年の3月からベクトルでWordPressのブロック開発を中心にお手伝いさんをしています丸山です。

私はもともとエンジニアですが、ベクトルでWordPress関連の開発に関わらせて頂くまで、2年半「開発」というものから遠ざかっておりました。

WordPressのプラグインなんて、ほら、PHPでちょっとゴリゴリ書けば動くんじゃね。と舐め腐っておりましたら、そりゃとんでもないお話でした。

まず最初に読んでと言われたのこのページです。

ちょっとまて、なんでNodeやらnpmいれて、開発環境なんぞセットアップしにゃならんのだ。なぜそんな壮大な話になっているんだ。

WordPressにおける編集は今やGutenbergというブロックエディタが主流。このGutenbergのオリジナルブロックを開発するには、Reactとやらを使って、あれやこれや駆使しないとあかんらしい。もうなんか浦島太郎状態。

とはいえ仕事ですので、がんばって勉強しました。これ、仕事じゃなくて趣味だったら、秒で放り投げるレベルです。

PHPでプラグインを作るのはできるけど、ブロックはねぇ・・・という人もいると思います。敷居が高いですよね。そこで本日は!

本日のテーマ

開発環境構築やビルド無し子テーマのfunctions.phpと1個のCSSと1個のJavaScriptのコードだけでオリジナルブロックを作りながら、ブロックの基礎の基礎を学んでみましょう。

秀丸(懐)とWordPressの環境があればできるんやで。おー、めっちゃ手軽や。

これは正攻法ではありません。長い目で見たら、ちゃんと開発環境を作った方が効率的です。WordPressのブロックを理解する手助けとなればと思い、この記事を書いています。この記事を一通り読んで、実際にブロックを作ってみてから、上のチュートリアルにもどると「あー、これはこういうことだったのね」と理解も深まることでしょう。

私のように時代に取り残された人でもわかるように、JavaScriptもあえてES5準拠というレガシーな書き方をしています。これでも動くよ的な。全体的に懐かしさがほのかに漂う感じを醸し出しております。

秀丸
秀丸とWordPress夢のコラボ

・・・できれば、モダンなJavaScriptで書けるように学んで頂くことをおすすめします。

さぁ、秀丸とWordPress一式用意してください! WordPressの開発環境をローカルに作りたい人はこちらを御覧ください。

「秀丸」と書いていますが、どうぞお好みのエディタを使ってください。

今回の成果物

実際に手を動かして成果物を作りましょう。選んだお題は「マーキーブロック」です。

ところで「マーキー」って知ってます?

はるか昔、HTMLには<marquee>というHTMLタグがございまして、このタグで囲んだ文字は、新幹線の車内に流れる文字ニュースの如くに文字が流れるという伝説のHTMLタグです。

実際にこれはmarqueeタグをつかった文字列です。

HTML5で非推奨になった・・・はずですが、今でもこっそり使えるようです。じゃあ、マーキーブロックいらねえんじゃね?というツッコミはスルーしつつ、ここでは入力した文字が流れる簡単なマーキーブロックを作ります。仕様は以下の通り。

  • 文字が右から左へ流れる
  • 流す文字はブロックエディタで自由に変更できる。
  • marqueeタグは使わない。

実際動いているところをご覧頂きます。

  • ブロックエディタで「Marquee」ブロックを追加する。
  • 文章を入力して保存。
  • フロント画面で文字が流れている

のがおわかり頂けたと思います。これをつくります。

ここでは、WordPressのテーマをベクトルが提供させて頂いているLightningにしています。よかったらLightningをお持ちでない方は、「Lightning」でテーマを検索してテーマを切り替えてみてくださいね。 (Lightningじゃなくても、もちろん大丈夫です)

STEP1: 子テーマ作成&必要なファイルを作成

まず最初に下準備です。子テーマを作り、必要なファイルを先に作ります。

子テーマ作成

最初に子テーマを準備します。これを読んでいるぐらいの人なら子テーマなんて簡単に作れますよね・・・・あれ?どうやってつくるんだっけ・・・。

そんな時でも大丈夫! ベクトルでは「ベクトレ」というラーニングサイトをご用意しております。ここでベクトル製品を使ったサイトの構築などが学べるようになっております。ここでは、子テーマの作り方がこうして解説されております。

上記ページではLightningの子ページサンプルがダウンロードできますが、今回学ぶにあたって余分なファイルがもれなくついてきますので、ここではシンプル構成で作ります。

  • /wp-contents/themes/lightning-child というディレクトリを作成(テーマがLightningじゃない人はlightning-childのところは別の名前でもOK)
  • その中に style.css を以下の内容で作成
/*
Theme Name: Lightning Child
Template: lightning
Version: 0.5.1
*/
  • 同じく functions.php を作成。内容は空で大丈夫です。
  • ここで、WordPressの管理画面で子テーマを有効化してください。

JS・CSSファイルを配置し、functions.phpでロードする。

空のJSとCSSファイルを先に配置します。

  • 子テーマのフォルダの中に js というサブフォルダを作成し、その中に空の marquee-block.js というファイルを配置してください

ついでにCSSファイルも作ってしまいましょう。先ほどつくったstyle.cssとは別にブロック用のCSSを作ります。

  • 子テーマのフォルダに css というサブフォルダを作成し、その中に空の marquee-block.css というファイルを配置してください。
  • CSS/JSを読み込むコードを functions.php に追加します。以下のコードを貼り付けましょう。すでになんらかのコードが書いてある人は、一番最初か最後あたりに入れてください。
add_action( 'wp_enqueue_scripts', function() {
	wp_enqueue_style( 'my-block-marquee-style', get_stylesheet_directory_uri() . '/css/marquee-block.css' );
});

add_action( 'enqueue_block_editor_assets', function() {
	wp_enqueue_style( 'my-block-marquee-style', get_stylesheet_directory_uri() . '/css/marquee-block.css' );
	wp_enqueue_script( 'my-block-marquee-script', get_stylesheet_directory_uri() . '/js/marquee-block.js', [], false, true );
} );

add_actionはおなじみアクションフックですね。2回呼び出しています。

最初のadd_actionはフロント側でCSSをロードするおなじみの書き方です。先に作った css/marquee-block.cssをロードする処理を書いています。ブロックJSはフロント側では使いません。

2回目のadd_actionは、第1引数に enqueue_block_editor_assets とあるように、ブロックエディタがロードされる時に呼ばれるものです。ここでCSSとJSを両方ロードするようにしています。

これで必要なCSS/JSがロードされるようになりました。

現時点でこのようなファイル構成になっていればOKです。

STEP2: とにかくブロックが動くところまで実装

registerBlockType() を覚える

さて、ここから実装していくのですが、その前にここで重要なポイントです。

重要なポイント

WordPressのブロックはJavaScriptで registerBlockType()関数を呼び出すだけで追加できます

とにかくこの registerBlockType()関数を呼び出せばブロックは追加できる。を覚えてください。いろいろなまやかしに惑わされず、これだけ覚えておいたら、あとは全部応用編です。

registerBlockType() を呼び出す

では registerBlockType() を呼び出しましょう。仕様を本家サイトで見てみます。

なかなか読んでもピンとこない方のために、ざっくり書くと

registerBlockType(blockName, settings)

blockName (string)

ブロックを識別する名前。自分で名付けますが、”namespace/block-name” のような感じで名付けます。

settings (object)

ブロックのプロパティです。ここでブロックの挙動を決めていきます。

ということです。

それに従って、marquee-block.js の中身を書いていきましょう。

(function(wp) {
    wp.blocks.registerBlockType('my-block/marquee', {});
})(wp);

wp.blocks.registerBlockType('my-block/marquee', {});

これが大枠となるブロックの登録関数です。上記の仕様通りです。第2引数が空のオブジェクトになってますが、ここにブロックの挙動を細かく書いていきます。

なお、wp.blocks.registerBlockType とありますが、registerBlockTypewp.blocks というパッケージの中に格納されているので、このように呼び出しています。

余談:最初の(function(wp) {って何?

余談ですが、最初と最後の行で、グローバル変数であるwpをわざわざ無名関数の引数で渡してますが、これはwpを局所化するためです。関数の中は極力ローカル変数であってほしいと私は考えています。

この関数は最後に (wp); がついてますので、即時実行され、引数にグローバル変数のwpが渡されます。それを受け取って局所化しています。他の人がコードを見た時に wp ってどこから来てるんやと思った時にすぐ上に出どころが書いてあるという利点もあります。

さらなる余談ですが、たとえば、jQueryをWordPressで使う場合、$が衝突するのを避けてjQueryっていちいち書く人が多いですが、この書き方なら、最後の行でjQueryを渡して、一番上の引数を $ で受け取ってあげれば、慣れた $ を使うことができます。

(function($) {
    $('.submit').なんちゃら・・・
})(jQuery);

ブロックのプロパティ(title/icon/category)を設定する

先程の marquee-block.js の第2引数にプロパティを追加していきましょう。以下のように書き換えます。

(function(wp) {
    wp.blocks.registerBlockType('my-block/marquee', {
        title: 'Marquee',
        icon: 'text',
        category: 'text'
    });
})(wp);

registerBlockTypeの第2引数で指定されているプロパティを1個ずつ見ていきましょう。

title (string)

ブロックのタイトルを文字列指定します。インサーターと呼ばれるブロックに追加する時に出てくるアレに表示されます。’Marquee’ と指定してありますね。

インサーター
ブロック追加する時に出てくるアレ

icon (string / object)

ブロックのアイコンを指定します。WordPress DashIconという標準のアイコンから好きなものを選んでください。

上記ページで、好きなアイコンを選ぶと、dashicon-text というようにアイコン名が書いてありますので、dashicon- を除いた残りを書きます。ここでは text と指定しています。

上記ページで、好きなアイコンを選びますと、dashicon-text というようにアイコン名が書いてありますので、dashicon- を除いた残りを書きます。ここでは text と指定しています。

右(スマホでお読みの方は下)の図ですと 'admin-links'と指定すればいいのです。

category (string)

WordPressのブロックは検索しやすいように、カテゴリに分類されます。

  • text (テキスト)
  • media (メディア)
  • design (デザイン)
  • widgets (ウィジェット)
  • theme (テーマ)
  • embed (埋め込み)

該当するものを指定します。

edit / save でブロックの挙動を書く

さらにedit save という2つのプロパティを追加します。これらはブロックの挙動を設定するためのもので、editがブロックエディタ側、saveがフロント側です。処理を関数で指定します。実際にmarquee-block.jssaveeditを書き足してみましょう。(2行目の var el = wp.element.createElement; も追加してください)

(function(wp) {
    var el = wp.element.createElement;

    wp.blocks.registerBlockType('my-block/marquee', {
        title: 'Marquee',
        icon: 'text',
        category: 'text',
        edit: function(){
            return el(
                'div',
                {
                    className: "marquee-editor",
                },
                el (
                    'p',
                    {},
                    'マーキーの内容をここに表示するよ。(save)'
                )
            );
        },
        save: function(){
            return el(
                'div',
                {
                    className: "marquee",
                },
                el (
                    'p',
                    {},
                    'マーキーの内容をここに表示するよ。(save)'
                )
                
            );
        }        
    });
})(wp);

marquee-block.cssは一応このようにしておきましょう。

.marquee-editor { 
    background-color: #dfd;
}

.marquee { 
    background-color: #ddf;
}

.marquee-editorはブロックエディタ側、.marqueeはフロント側のCSSです。分かりやすいように色をあえて変えています。

さて、実際にブラウザで編集画面にアクセスし、うまくいけば、インサーターにMarqueeブロックが表示されます。ブロックの挿入はできましたか。

インサーター

フロント側の画面も併せて確認しましょう。

大体こんな感じで表示されていますか? editは編集側で、saveがフロント側。ざっくりご理解頂けたかと思います。

edit で指定した el 関数は、ブロックエディタ内のブロックのViewを返しています。この el 関数は 2行目にあるように wp.element.createElement() という関数を指していますね。

この関数はReactフレームワークから呼び出され、Reactの要素を返しています。第1引数にタグ名、第2引数に属性、第3引数に要素の中身が指定されています。ここでは深く考えず、「なんかdivタグの要素を生成してるのね」ぐらいに捉えておいて、Reactを後でしっかり学んで頂ければ幸いです。コードを見てると <div class="marquee-editor"><p>マーキーの内容をここに表示するよ。(edit)</p></div>と生成してくれそうな予感がしますね。

ここでReactが使われている理由は、ユーザーの入力値に従ってリアルタイムにブロックの形であったり色といったスタイルを変えたいからだと思われます。たとえばブロック設定で背景色に赤を選んだら、エディタの背景色もリアルタイムに赤にしたいですね。素のJavaScriptだけでは、こうした処理を書くは面倒ですが、Reactを使うと比較的簡単に書けてしまいます。

save の方は、フロント側でのブロックのViewを返します。こちらもedit同様ですが、ブロックエディタと異なり、ユーザーの入力に従って動作を変えるということはありませんので、単純に出力するHTMLを吐き出す処理を書きます。

「edit/saveプロパティで指定された無名関数」ですが、この先便宜上 edit関数、save関数と呼ぶことにします。

マーキーの動きをCSSで実装

ここまでまだテキストは動いていません。動かぬなら、動かしましょう。昨今のCSSは進化しており、マーキーの動きはCSSで簡単に表現できる時代です。ここは他社様のブログのお力添えをいただくことにいたしましょう。

上記を参考に marquee-block.css に実装します。CSSを以下のように書き換えてみましょう。

.marquee-editor {
    width: 100%;
    background-color: #dfd;
}
.marquee {
  width: 100%;
  background-color: #ddf;
  padding: 0.5em 0;
  overflow: hidden;
  margin-bottom: 10px;
  position: relative;
}

.marquee p:after {
  content: "";
  white-space: nowrap;
  padding-right: 50px;
}

.marquee p {
  margin: 0;
  padding-left: 100%;
  display: inline-block;
  white-space: nowrap;
  -webkit-animation-name: marquee;
  -webkit-animation-timing-function: linear;
  -webkit-animation-duration: 10s;
  -webkit-animation-iteration-count: infinite;
  -moz-animation-name: marquee;
  -moz-animation-timing-function: linear;
  -moz-animation-duration: 10s;
  -moz-animation-iteration-count: infinite;
  -ms-animation-name: marquee;
  -ms-animation-timing-function: linear;
  -ms-animation-duration: 10s;
  -ms-animation-iteration-count: infinite;
  -o-animation-name: marquee;
  -o-animation-timing-function: linear;
  -o-animation-duration: 10s;
  -o-animation-iteration-count: infinite;
  animation-name: marquee;
  animation-timing-function: linear;
  animation-duration: 10s;
  animation-iteration-count: infinite;
}

@-webkit-keyframes marquee {
  from {
    -webkit-transform: translate(0%);
  }
  99%, to {
    -webkit-transform: translate(-100%);
  }
}

@-moz-keyframes marquee {
  from {
    -moz-transform: translate(0%);
  }
  99%, to {
    -moz-transform: translate(-100%);
  }
}

@-ms-keyframes marquee {
  from {
    -ms-transform: translate(0%);
  }
  99%, to {
    -ms-transform: translate(-100%);
  }
}

@-o-keyframes marquee {
  from {
    -o-transform: translate(0%);
  }
  99%, to {
    -o-transform: translate(-100%);
  }
}

@keyframes marquee {
  from {
    transform: translate(0%);
  }
  99%, to {
    transform: translate(-100%);
  }
}

フロント側を確認してください。文字が流れていますね。エディタ側は動きません。っていうか、動かしません。ユーザーが編集している時に文字が動いたら使いづらいったらありゃしないからです。

テキストの編集機能を実装する

マーキーテキストをブロックエディタで書き換えるように実装します。

一気に完成形のコードを先にご覧頂きましょう。

(function(wp) {
    var registerBlockType  =  wp.blocks.registerBlockType;
    var el = wp.element.createElement;
    var useBlockProps = wp.blockEditor.useBlockProps;
    var RichText = wp.blockEditor.RichText;

    registerBlockType('my-block/marquee', {
            title: 'Marquee',
            icon: 'text',
            category: 'text',
            attributes: {
                content: {
                    type: 'array',
                    source: 'children',
                    selector: 'p',
                }           
            },            
            edit: ( props ) => {
                var blockProps = useBlockProps({className: "marquee-editor"});
                var content = props.attributes.content;
                function onChangeContent( newContent ) {
                    props.setAttributes( { content: newContent } );
                }
                return el(                
                    'div',
                    blockProps,
                    el(
                        RichText,
                        {
                            tagName: 'p',
                            onChange: onChangeContent,
                            value: content,
                            placeholder: 'マーキーのテキストを入力'
                        }
                    )
                );
            },
            save: ( props ) => {
                var blockProps = useBlockProps.save({className: "marquee"});
                return el(                
                    'div',
                    blockProps,
                    el( RichText.Content,
                    {
                        tagName: 'p', 
                        value: props.attributes.content,
                    })
                );
            }
    });
})(wp);

registerBlockType内に attributes というプロパティが追加されています。これはブロックの「属性」です。ユーザーが設定したブロックの「色」や「マージン」「テキスト」といった値をattributesに保存することができます。

ここでは、ユーザーが入力したテキストを content という名前の属性を設定して保存しています。

typesourceselector となにやら指定してますが、詳しい説明は

こちらにおまかせします。ここでは、content という属性を追加したんだな。ここにマーキーのテキストを保存するんだなと理解頂ければ大丈夫です。

editsaveの関数も書きかえてます。

edit

edit は 編集画面でのブロックの挙動を表しています。

var blockProps = useBlockProps({className: "marquee-editor"});useBlockProps() は、4行目 var useBlockProps = wp.blockEditor.useBlockProps; とありますので、wp.blockEditor で提供されている関数です。

ブロックを構成するHTMLの中で、ブロックの一番大外となる<div>などの要素は次のようなHTMLになります。

<div id="block-558620a2-0eb3-4883-811b-ae46c0ffd951" tabindex="0" role="group" aria-label="ブロック: Marquee" data-block="558620a2-0eb3-4883-811b-ae46c0ffd951" data-type="my-block/marquee" data-title="Marquee" class="marquee-editor">

idtabindex など、これらに必要な属性をオブジェクトとして取得できるのが useBlockProps です。引数に{className: "marquee-editor"}を渡していますが、この値がマージされるようになっています。(className と書くのはreact のルールで、HTMLでは class="" の形で出力されます。)

次の行 var content = props.attributes.content; は上記で設定した属性値contentを受け取っています。edit関数の引数として props が渡されていますが、これはブロック情報が格納されたオブジェクトで、props.attributes にあるブロック属性を読み取っています。

その後の onChangeContent 関数は後述しますので、横においておきます。

問題はその次です。

                return el(                
                    'div',
                    blockProps,
                    el(
                        RichText,
                        {
                            tagName: 'p',
                            onChange: onChangeContent,
                            value: content,
                            placeholder: 'マーキーのテキストを入力'
                        }
                    )
                );

return される el の中が変わってますね。 第2引数はさきほど取得したblockPropsを指定することで適切な属性値をdiv属性として出力してくれます。

次の el は 以前の'p' に代わり 第一引数にRichText が指定されています。5行目に
var RichText = wp.blockEditor.RichText; とあるように、WordPressのパッケージに含まれているものです。

これはReactの「コンポーネント」です。ReactではUIを細かく部品に分けることができます。たとえば、入力フォームであれば、ラベルとテキストボックスで一つのコンポーネントを構成するといった具合です。

WordPressでも、数多くのコンポーネントが用意されており、RichTextは高性能なテキストエディタコンポーネントというわけです。以下はWordPress公式サイトで紹介されているコンポーネントリファレンスです(英語です)。

コンポーネントはいくつかの属性値(プロパティ)を持つことができます。それがその下の tagNameonChange にあたります。

tagName は RichTextのラッパーとなるHTMLタグです。ここでは 'p' となっているので、pタグですね。

onChange では、値がユーザーによって変更された時にコールバックする関数を指定します。ここでは先に宣言されていた onChangeContent が指定されます。ここのコールバック関数には、ユーザーの入力値が渡されますので、それを

props.setAttributes( { content: newContent } );

という感じで、先に宣言したブロックの content 属性にセットしているのがわかるかと思います。

ブロックの属性値を書き換えるときは、 props の中にある setAttributes() を使うことになっています。

RichTextについては外部様のコンテンツになりますが、こちらがとても参考になります。

save

save関数の方は、ユーザーの入力がありませんので、ブロック情報から展開するだけです。

最初の var blockProps = useBlockProps.save({className: "marquee"}); では、edit同様ブロックラッパーのHTML属性値を取り出しています。edit ではuseBlockProps() 、save では useBlockProps.save() を使うんですね。

return している el の中身も edit よりシンプルです。

                    el( RichText.Content,
                    {
                        tagName: 'p', 
                        value: props.attributes.content,
                    })

RichText.Content は生成されたHTMLをフロント用に吐き出してくれるものです。大体見れば何をしているかイメージできますでしょうか。

はい! これでひとまず完成です。うまくマーキーブロックは動いていますか?

STEP5: ブロックが動く仕組みを理解する

registerBlockTypeedit 関数とsave 関数を指定しただけで、なぜブロックが動いてしまうのか、いまいちピンときません。

そもそも save という名前はなに? view とか render とかいう名前なら分かりやすいのに saveってなに?って話ですよね。

結論から書くと、ブロックエディタは、フロント側に表示するHTMLを生成し、コンテンツ(post)として保存(save)しているにすぎないのです。フロント側ではReactが動いていません。Reactは編集画面で動いているブロックエディタのための技術です。フロント側はいつもどおりDBに保存したコンテンツ(post)を出力しているだけ、Reactはおろかブロックエディタのことすら知りません。昔からまったく変わっていないのです。

だから save という名前です。フロントに吐き出すHTMLをsaveしているだけです。

実際にブロックエディタで生成されているコードをリアルタイムに見ることができます。編集画面右上の三点リーダー→「コードエディター」を選ぶと・・・。

コードエディターの場所

こんなようなコードが表示されます。

<!-- wp:my-block/marquee -->
<div class="wp-block-my-block-marquee marquee"><p>マーキーのブロックテストだよ。</p></div>
<!-- /wp:my-block/marquee -->

コメントでブロックの開始終了の位置が示され、その中に生成されたHTMLがあります。こうしてHTMLという形でブロックが出力されているにすぎません。ブロックエディターはこのHTMLからブロック情報を取得しているのです。

試しに通常の段落ブロックを加えて、背景色やテキスト色を変えて、ブロックエディターで見てください。

<!-- wp:paragraph {"backgroundColor":"light-green-cyan","textColor":"luminous-vivid-amber"} -->
<p class="has-luminous-vivid-amber-color has-light-green-cyan-background-color has-text-color has-background">こんにちは。</p>
<!-- /wp:paragraph -->

こんな感じになりましたね。今度はコメントの中にJSONっぽい文字列が入っていますが、変更した文字色の情報がこのように保存されているのがわかると思います。

このようにコンテンツについてはHTMLに埋め込み、その他属性値はコメントに埋め込まれることが多いと思います。そのあたりは、attributesの設定で指定しているということになります。

さいごに

こうしてシンプルなブロックをゼロベースから書くと、ブロックがどんな仕組みで動いているか分かりやすくないですか? 今回は子テーマとして作りましたが、プラグインでもやることは同じです。

最初に書いたように、通常、ブロックはビルド型の開発をします。今回ご紹介した方法はブロックについて理解を深めるためのものです。でも、プラグインにちょっとしたブロック機能をオマケ的に追加する程度のものなら、この方法がお手軽かもしれません。

本格的にブロック開発をしたい人は、はい!

これを読みながら、開発環境をつくってビルド型の開発をやってみてください。そう、この記事を読んだ後なら、きっと理解が全然違うはずです。

属性値やスタイル情報をJSONとして別途宣言するといったこともできます。上記でel()をつかって長々と書いたView的な部分はJSXというHTMLに似た構文を使って書くことができます。もっとスタイリッシュにブロックを開発することができるでしょう。

ベクトルが提供している便利なブロックプラグインVK Blocksのように、一つのプラグインに複雑な動きをするブロックがたくさんあるケースでは、ビルド型の開発でなければ、とてもやってられません。

でも、どんなに複雑なブロックになっても

結局は registerBlockTypeの中身を書いているに過ぎない

のです。あとは全部応用です。

さて、余談ですが、PHP側にも register_block_type() という関数が用意されてます。これは、wp_enqueue_script() で呼び出していたJSなどをスマートに読み込むための関数で、JavaScriptのregisterBlockType()とは性質が異なるものです。ここもちょっと混乱ポイントかもしれません。

Vektor WordPress Solutions Advent Calendar 2021」明日の記事は、マンション管理組合目線さんが「素人がG3へのアップグレードで苦労した話」について書いてくれる予定です。どうぞお楽しみに!

Follow me!

この記事を書いた人

丸山泰地
丸山泰地
2021年3月からベクトルのお手伝いをしているレガシーエンジニア。最近const覚えました。

その裏で、BREADFISHというキリスト教会専門のウェブ制作事業を密かに展開しています。

リリース記念キャンペーン!
G3 Pro Unit を買って


Evergreen


無料でダウンロードしよう

Lightningで使えるおしゃれなデザインスキン / コンテンツデータを試せるチャンス!