Atsumaru Engineer's Blog

集客プラットフォーム事業を手がける株式会社あつまるのエンジニアブログです

日付形式設定・時刻形式設定をカスタムブロックから取得する (WordPress Gutenberg)

どうも、あつまるのテックリードの三井です。

 

カスタムブロックで日付や時刻を取り扱うとき、管理画面で設定した日付形式・時刻形式で表示したくなるときがあります。

今回は管理画面から日付形式・時刻形式を取得して表示する方法を紹介します。

@wordpress/data を使う

記事編集画面で wp.data.select( 'core' ).getSite() を実行すると一般設定の登録情報が取れます。日付形式は date_format , 時刻形式は time_format というキーで取れます。

実際には useSelect を使って下記のようにするのがいいでしょう。

export function edit() {
    const { date_format, time_format } = useSelect(
        ( select ) => select( 'core' ).getSite(),
        []
    );

    console.log( date_format );  // => 'Y/n/j'
    console.log( time_format );  // => 'H:i'

    return <div />;
}

 

React Hook の形でまとめると再利用しやすいかも知れません。

export function useDateTimeFormat( 
    default_date_format = 'Y/n/j',
    default_time_format = 'H:i'
): [ string, string ] {
    const { date_format, time_format } = useSelect(
        ( select ) => select( 'core' ).getSite(),
        []
    );

    return [
        date_format ?? default_date_format,
        time_format ?? default_time_format,
    ];
}

使うときはこんな感じ、

export function edit() {
    const [ date_format, time_format ] = useDateTimeFormat( 'Y-m-d', 'H:i:s' );

    console.log( date_format );  // => 'Y/n/j'
    console.log( time_format );  // => 'H:i'

    return <div />;
}

取得できる日付形式・時刻形式が JavaScript で使いづらい問題

取得できる日付形式・時刻形式は PHP の DateTimeInterface::format 形式になっています。そのため JavaScript でメジャーなフォーマット関数 ( Moment.js の format メソッドや date-fns の format 関数 ) でそのまま使うことができません。

PHP 形式の日付形式・時刻形式を JavaScript で使うために @wordpress/date というモジュールが用意されています。
このモジュールに用意されている date() 関数を使うと、うまく日付・時刻をフォーマットして表示してくれます。管理画面で設定したタイムゾーン設定を引用してくれるので便利です。

import { date } from '@wordpress/date';

export function edit() {
    const { date_format, time_format } = useSelect(
        ( select ) => select( 'core' ).getSite(),
        []
    );

    const d = new Date( '2022-01-05 12:30' );

    console.log( date_format );             // => 'Y/n/j'
    console.log( date( d, date_format ) );  // => '2022/1/5'

    console.log( time_format );              // => 'H:i'
    console.info( date( d, time_format ) );  // => '12:30'

    return <div />;
}

 

@wordpress/date モジュールには他にも dateI18n, getDate などの関数が用意されているので必要に応じて使い分けてください。
どれも PHP 形式の設定を JavaScript の処理で使いやすくするために橋渡ししてくれる便利な関数です。

まとめ

Y-m-dyyyy-MM-dd みたいな変換処理をする関数を自作しようかと思ったけど、WordPress が代替案を用意してくれてたので安心しました。

 

私からは以上です。

管理画面 > 一般設定 の登録情報をカスタムブロックから取得する (WordPress Gutenberg)

どうも、あつまるのテックリード、三井です。

 

WordPress は内部的に多種多様な情報を取り扱っています。そしてそれらを取得すための PHP 関数がとても充実しています。一方で Gutenberg のカスタムブロックを開発しているとき、JavaScript 世界からそれらの情報を取得する方法は公式のハンドブックでもなかなか解説されていなかったりします。

 

今回は、WordPress 管理画面の一般設定画面で登録している情報を JavaScript で取得する方法を解説します。一般設定画面とは下記のような ↓↓↓ 画面ですね。

WordPress 一般設定画面

@wordpress/data を使う

カスタムブロックからデータ取得といえば @wordpress/data です。@wordpress/data はGutenberg の Redux ストアにアクセスするための API です。たぶん。

 

試しに固定ページ編集画面で開発者ツールを開いて wp.data.select( 'core' ).getSite() を実行すると何やら情報が取れます。

wp.data.select( 'core' ).getSite() とすると情報が取れる

{
    "title": "デモサイト",
    "description": "Just another WordPress site",
    "url": "https://example.com",
    "email": "admin@example.comp",
    "timezone": "Asia/Tokyo",
    "date_format": "Y年n月j日 (D)",
    "time_format": "H:i",
    "start_of_week": 1,
    "language": "ja",
    "use_smilies": true,
    "default_category": 1,
    "default_post_format": "0",
    "posts_per_page": 10,
    "show_on_front": "page",
    "page_on_front": 13,
    "page_for_posts": 0,
    "default_ping_status": "open",
    "default_comment_status": "open",
    "site_logo": null,
    "site_icon": 0
}

このような情報が取れるみたいです。

カスタムブロックで情報を取るときは useSelect を使う

実際にカスタムブロック開発に使うときのためにもう少し実用的なコードにしましょう。useSelect フックを使います。

export function edit() {
    const data = useSelect(
        ( select ) => select( 'core' ).getSite(),
        []
    );

    console.info( { data } );
    // => { data: {
    //   title: 'デモサイト',
    //   description: 'Just another WordPress site',
    //   url: 'https://example.com',
    //   ...
    // } }

    return <div />
}

useSelect の第二引数は [] でいいでしょう。一般設定の登録情報は頻繁に変わるものでもないので。

 

React Hook の形でまとめると再利用しやすいかも知れませんね。

export function useSite() {
    return useSelect(
        ( select ) => select( 'core' ).getSite(),
        []
    );
}

まとめ

一度やり方が分かってしまえば簡単でした。

 

私からは以上です。

インナーブロックの情報を親ブロックから取得する (WordPress, カスタムブロック)

Gutenberg のカスタムブロックでインナーブロックを配置できるようにしたとき、親ブロックからインナーブロックの情報を取得する方法をまとめます。

 

以下、 @wordpress/create-block を使ってひな形を作成したときのファイル構成を前提に解説します。

インナーブロックを配置できるようにしたときの最小構成

まず、普通に最小構成でブロックを構築するとこんな感じになります。

src/edit.js

import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

export function Edit() {
    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps( blockProps, {} );

    return (
        <div { ...innerBlocksProps  } />
    );
}

やりたいこと

useInnerBlocksProps を利用すると、簡単お手軽にインナーブロックを配置できるブロックが作れます。
save() 関数側でも <InnerBlocks.Content /> と書くだけでインナーブロックの管理はお任せできます。

しかし、 "お任せできる" というのは言い換えると "ブラックボックスになっていて外から中の状態を知り得ない" ということです。それでは困る場面もあるでしょう。
というわけで親ブロックからインナーブロックの情報を取得してみましょう。

useSelect を使ってインナーブロックの情報を取得する

インナーブロックの情報を取得するために useSelect を使います。

src/edit.js

import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';

export function Edit({ clientId }) {
    const innerBlocks = useSelect( select => select( 'core/block-editor' ).getBlocks( clientId ) );
    console.log( { innerBlocks  } );

    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps(blockProps, {});

    return (
        <div { ...innerBlocksProps  } />
    );
}

useSelect を使って useSelect( select => select( 'core/block-editor' ).getBlocks( clientId ) ) のように書くとインナーブロックの情報を取得できます。
getBlocks() メソッドには引数として clientId を渡す必要があります。 Edit() のオブジェクト引数から取得できる clientId をそのまま渡せば大丈夫です。

取得した innerBlocks を実際に見てみると、以下のようなデータになっています。

[
    {
        "clientId": "0c8bc6d7-4b66-46e7-a1aa-5f7284498655",
        "name": "core/heading",
        "isValid": true,
        "attributes": {
            "content": "Foo Bar",
            "level": 1
        },
        "innerBlocks": []
    },
    {
        "clientId": "7e1d6dd0-4152-41a6-98ca-205db0b29a9e",
        "name": "core/paragraph",
        "isValid": true,
        "attributes": {
            "content": "Hoge Fuga",
            "dropCap": false
        },
        "innerBlocks": []
    }
]

attributes プロパティを参照することでインナーブロックのコンテンツに設定されているテキストなどが直接手に入ります。
その他 innerBlocks プロパティを参照すると、「インナーブロックの中のインナーブロック」まで辿っていくこともできます。

withSelect を使ってインナーブロックの情報を取得する

useSelect の代わりに withSelect を使ってもインナーブロックの情報を取得できます。
useSelect を使ったときと理屈は同じです。

src/edit.js

import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import { withSelect } from '@wordpress/data';

export const Edit = withSelect( ( select, { clientId } ) => ({
    innerBlocks: select( 'core/block-editor' ).getBlocks( clientId ),
}))(edit);

function edit({ innerBlocks }) {
  console.log( { innerBlocks  } );

  const blockProps = useBlockProps();
  const innerBlocksProps = useInnerBlocksProps(blockProps, {});

  return (
      <div { ...innerBlocksProps  } />
  );
}

withSelect() の返り値で edit() 関数をデコレートしてあげることで、 edit() 関数のオブジェクト引数に { innerBlocks: [ ... ] } という形でインナーブロックの情報が引き渡されます。

まとめ

@wordpress/data の API 、挙動がマジカルすぎて理解が難しい。

 

私からは以上です。

参考

github.com

シェルスクリプトでデータベースのバックアップ

f:id:Prq8EHGiTndTH3W:20210226153456j:plain

※ 新卒1年目の記事ですので、暖かい目で見てください。

Cron を利用してシェルスクリプトでデータベースの自動バックアップを取ることができると聞いたのでやってみました。( ̄∀ ̄)

// buckup_db.sh

# 何日前までのバックアップファイルを保存するのかを指定
PERIOD=10

# DB バックアップ先のディレクトリを指定
DIRPATH='/home/user/hoge/buckup_db/dbname'

# DB バックアップファイル名を指定
FILENAME=`date +%y%m%d_dbname`

# バックアップする DB 名を指定
DB='dbname'

# DB のバックアップ実行
mysqldump --defaults-extra-file='/home/user/hoge/buckup_db/my.conf' $DB > $DIRPATH/$FILENAME.sql

# バックアップファイルの権限変更
chmod 700 $DIRPATH/$FILENAME.sql

# 旧バックアップファイルの削除
OLDFILE=`date --date "$PERIOD days ago" +%y%m%d_dbname`
rm -f $DIRPATH/$OLDFILE.sql
// my.conf

[client]
user = username
password = mypassword
host = localhost

これでデータベースのバックアップが取れました!シェルスクリプト触ったことなくても割と簡単に書けました!(゜▽゜)

ただこのままだと毎回手動で実行する羽目になるので、次は crontab での定期実行とエラーハンドリング機能の実装、その次は処理を実行した時にメールか何かでメッセージを送る機能を実装していこうと思っています!!

▼ 参考にしようとしているサイト qiita.com blog.amedama.jp

吉報報告アプリをつくってみた!っていう話

コロナ渦の中、皆様いかがお過ごしですか? 少しでも元気になるシステム開発できないかな〜と思いまして、 吉報を全社で喜ぶためのアプリを開発しました。

プログラムの詳細は、書かないですが、どんな構成で作ったかを紹介します! 開発リミットが2日しかなかったので、作り込んではいないです。😣 (そのうちの1日はどんな音楽がテンション上がるかで費やしました。)

吉報を報告するアプリってどんなの?

チャットワークに、メッセージを送るとMacをつないでいるモニターにテンションが上がる音楽とともに吉報が報告されます。


※ミュートを解除すると音楽が流れます。音量をお気をつけください。

アーキテクチャ

この構成はなんとサーバー代もかからず、「完全無料」です!

image.png

①チャットワークの特定のスレッドに報告をする image.png

※あつまるBotに対してToをつけた場合だけ全社への報告になるようにしています🎉

②チャットワークAPIを受け取り、データを加工

③FirebaseのRealtime Databaseを更新

④Electronで作成したMacアプリ側で、データを受け取る

⑤Cloud StorageからBGMをダウンロードして音楽を流し、メッセージを画面に流す ※報告内容によって、ダウンロードする音楽を切り分けています。

どこにつまづいたか

ブラウザに依存させず、Mac本体に制御を加えたかったので、Macアプリ作ろうと思い立ちました。 いろいろ方法はあるものの、久々に"Electron"を触ってみました。

《つまづきポイント①》

Electron側のウィンドウの制御

イメージは下の図のようになっています。 透明な全画面ブラウザを上にマスクさせて、CSSでメッセージが流れる表現をしています。 image.png

Electronの画面の表現には慣れていなかったので、いろいろ苦戦しました。😅

  • mainWindow.setIgnoreMouseEvents(true); ウィンドウをクリックできない状態にする
  • mainWindow.setAlwaysOnTop(true, 'floating'); ウィンドウを最前面表示
ウィンドウ制御周りのコード
  // メインウィンドウを作成します
  let size = screen.getPrimaryDisplay().size; // ディスプレイのサイズを取得する
  mainWindow = new BrowserWindow({
    webPreferences: {
      nodeIntegration: true,
    },
    left: 0,
    top: 0,
    frame: false,       // フレームを非表示にする
    resizable: false,   // ウィンドウリサイズ禁止
    transparent: true,
    width: size.width,
    height: size.height,
    skipTaskbar: true,
    alwaysOnTop: true // 一番手前に表示する
  });

  // 全てのウィンドウに表示(フルスクリーン対応)
  app.dock.hide();
  mainWindow.setAlwaysOnTop(true, 'floating');
  mainWindow.setVisibleOnAllWorkspaces(true);
  mainWindow.setFullScreenable(false);
  app.dock.show();

  // マウスイベント無効化
  mainWindow.setIgnoreMouseEvents(true);

app.dock.hide();して、app.dock.show();する一連の流れについては、謎挙動。。。 しかし、この流れでなければ、最前面&フルスクリーンは実装できませんでした。

《つまづきポイント②》

つまづきポイントを書こうと思ったのですが、つまづきポイント①で書いたところ以外は、 特につまづきませんでした。。。とにかくFirebaseが便利すぎて、助けられました。

作ってみてどうだったか

このアプリを会社に導入してから、1日に8回くらい吉報が流れます。😆 多い時は、15回以上流れることもありました🎉

《社内と気持ちの変化》

  • 喜びを部署超えて、全社に共有できる(他の部署のことを知ったり、話すきっかけにもなる)
  • テンションがあがり、早く吉報を報告したい気分になる

何より、使ってもらえることが作った側からすると一番嬉しいです☺️

今後の展望

吉報を報告した人、内容によって、BGMを分けたり、画面のギミックを変えたりできるともっともっとテンションが上がって、吉報を報告したい気持ちが高まりそう。 あとは、社内だけでなく、他の会社でもこのアプリを使ってもらえると嬉しいなと思います。 ぜひ、興味ある方、声かけてください〜😊