始める前に

この記事では、前の記事で始めたプロジェクトを基に、前回の続きから進めていきます。

この記事の出発点となるプロジェクトを取得するには、次の手順を実行できます:

  1. git clone git@github.com:wptrainingteam/devblog-dataviews-plugin.git
  2. git checkout part1

この記事で説明されているプロジェクトの最終コードは、GitHubで入手可能です

記事全体を通して、説明されている変更に対応する特定のコミットへのリンクが見つかります。これにより、プロジェクトの進捗を追跡するのに役立ちます。

メディアライブラリに画像を追加するアクション

現在の状態では、プロジェクトは画像をフルサイズで表示するアクションのみを持っています。次に、メディアライブラリに画像をアップロードする新しいアクションを作成しましょう。

次のコードactions配列に追加し、actionsプロパティに渡します。Dataviewsコンポーネント:

  1. src/App.jsconst actions = [
  2. {
  3. id: 'upload-media',
  4. label: __( 'Upload Media' ),
  5. isPrimary: true,
  6. icon: 'upload',
  7. supportsBulk: true,
  8. callback: ( images ) => {
  9. images.forEach( ( image ) => {
  10. console.log( `Image to upload: ${ image.slug }` );
  11. });
  12. },
  13. },
  14. ...
  15. ]

この新しいアクションは、データビューUIでのマルチ選択を可能にします。現時点では、トリガーされると、選択された各画像に対してコンソールにメッセージを記録します。

ファイルが変更されたときにプロジェクトのビルドバージョンを自動的に生成するために、npm startnpm run startのエイリアス)が実行されていることを確認してください。

‘see-original’アクションは、idlabelcallbackプロパティを使用して定義されました。上記のように、この新しい‘upload-media’アクションの定義では、次のような追加のプロパティが使用されています:

  • isPrimary – このプロパティをtrueに設定することで、このアクションは各アイテムのデフォルトアクションになります。
  • supportsBulk – このプロパティをtrueに設定することで、アイテムのマルチ選択を有効にできます。この設定を有効にすると、複数のアイテムに対して同時にアクションを実行できます。
  • icon – プライマリアクション用のアイコン。

このアクションのコールバック関数が、現在1つ以上のアイテムの配列を受け取っていることに注意してください。forEachを使用することで、選択された各アイテムに対していくつかのロジックを実行できます。

データビューアイテムのアクションを定義するために使用できるプロパティの完全なリストは、こちらで確認してください。

‘upload-media’アクションが作成されたので、URLを指定してメディアライブラリに画像をアップロードするために必要な手順を考えてみましょう:

  • 1. 提供されたURLから画像をダウンロードし、blobに変換します。
  • 2. 画像blobを含むFormDataオブジェクトを作成し、POSTリクエストのボディとして送信します。
  • 3. apiFetchを使用して、WordPress REST APIの適切なエンドポイントに画像をメディアライブラリに追加するためのPOSTリクエストを送信します。

基本的に、特定のREST API URLにPOSTリクエストを行い、バイナリ形式の画像データを含める必要があります。これを行うには、REST APIリクエストのデータを準備するためにいくつかの前提条件が必要です。

これらの手順をコメントとして追加し、各ステップのロジックを追加する際の参照として使用します:

  1. src/App.jsconst actions = [
  2. {
  3. id: 'upload-media',
  4. ...
  5. callback: ( images ) => {
  6. images.forEach( ( image ) => {
  7. // 1- Download the image and convert it to a blob
  8. // 2- Create FormData with the image blob
  9. // 3- Send the request to the WP REST API
  10. });
  11. },
  12. },
  13. ...
  14. ]

画像をダウンロードしてblobに変換する

各アイテムの画像URLはimage.urls.rawで利用可能ですので、ブラウザのネイティブfetchメソッドを使用して各画像をダウンロードし、レスポンスをblobに変換できます。

POSTリクエストで画像を送信するには、ネットワークを介して送信できる形式に変換する必要があります。一般的な形式はバイナリ大オブジェクト(Blob)です。

このコードを追加して、forEachのコールバック関数に:

  1. src/App.jsimages.forEach( async ( image ) => {
  2. // 1- Download the image and convert it to a blob
  3. const responseRequestImage = await fetch( image.urls.raw );
  4. const blobImage = await responseRequestImage.blob();
  5. ...
  6. })
  1. `````fetch`````からの成功したレスポンスは、[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)インスタンスにカプセル化されており、[`````blob()`````メソッド](https://developer.mozilla.org/en-US/docs/Web/API/Response/blob)が含まれています。このメソッドを使用すると、レスポンスから直接blobを生成できます。
  2. <a name="create-formdata-with-the-image-blob"></a>
  3. ### 画像blobでFormDataを作成する
  4. 画像がblob形式になったら、次のステップはREST APIへのHTTPリクエストで送信するデータを準備することです。POSTリクエストでデータを送信する方法の1つは、[`````FormData`````オブジェクト](https://developer.mozilla.org/en-US/docs/Web/API/FormData)をリクエストボディとして使用することです。
  5. `````fetch`````(またはWordPress`````apiFetch`````)のようなメソッドは、リクエストのボディとして`````FormData`````オブジェクトを使用できます。このデータは、`````Content-Type``````````multipart/form-data`````に設定されてエンコードされ、送信されます。
  6. [このコードを追加](https://github.com/wptrainingteam/devblog-dataviews-plugin/commit/273658720dbf832eddcf4a0db8a4542e4a315767)して、`````forEach`````のコールバック関数に:
  7. ``````bash
  8. src/App.jsimages.forEach( async ( image ) => {
  9. ...
  10. // 2- Create FormData with the image blob
  11. const formDataWithImage = new FormData();
  12. formDataWithImage.append(
  13. 'file',
  14. blobImage,
  15. );
  16. ...
  17. })
  18. `

上記のコードは、新しいFormDataオブジェクトを作成し、blob形式の画像を含むfileフィールドを追加します。

  1. <a name="send-the-request-to-the-wp-rest-api"></a>
  2. ### WP REST APIにリクエストを送信する
  3. この時点で、すべてが`````apiFetch`````メソッドを使用してREST APIリクエストを行う準備が整いました。
  4. `````apiFetch`````は、`````window.fetch`````のラッパーであり、WP REST APIへのリクエストを行う際に、REST APIエンドポイントのベースURLを自動的に補完し、[`````nonce`````をリクエストヘッダーに含める](/read/wordpress/c78da111cf4e6cb4.md)など、いくつかの利点を提供します。
  5. `````App.js`````の先頭に移動し、`````apiFetch`````メソッドを`````@wordpress/api-fetch`````からインポートします:
  6. ``````bash
  7. src/App.jsimport apiFetch from "@wordpress/api-fetch";
  8. `

次に、このコードを追加して、forEachのコールバック関数に:

  1. src/App.jsimages.forEach( async ( image ) => {
  2. ...
  3. // 3- Send the request to the WP REST API with apiFetch
  4. await apiFetch({
  5. path: "/wp/v2/media",
  6. method: "POST",
  7. body: formDataWithImage,
  8. })
  9. .then( console.log )
  10. ...
  11. })

上記のコードは、apiFetchを使用してwp/v2/mediaエンドポイントに(POST)リクエストを行います。REST APIハンドブックに記載されているように、/wp/v2/mediaエンドポイントへのPOSTリクエストを介して、WordPressインストールにメディアアイテムを作成できます

パブリックREST APIは、WP 4.7以降コアの一部です。

あなたのデータビューには、表示された写真をメディアライブラリに直接アップロードする新しい機能が含まれています。個別に画像をアップロードすることも、複数の画像を選択して一括アップロードすることもできます。

データビューからのアクション:メディアライブラリに画像を追加(Actions from Data Views: Adding images to the Media Library) - img1

ただし、ユーザーがアップロードプロセスについて受け取るフィードバックはあまり良くなく、コンソールにメッセージが表示されるだけです。このユーザーエクスペリエンスを改善するために取り組みましょう。

アップロードプロセスの結果を通知するボックス

WordPressは、通知システムを提供しており、通知ストアを介して管理できます。通知UIと対話する良いアプローチは、withNoticesハイアオーダーコンポーネントでReactコンポーネントをラップすることです。

  1. - `````noticeOperations`````は、特定の通知ボックスを生成するために使用できる[`````createNotice`````](a594ec44f1731fc8.md#createnotice)メソッド(他のメソッドも含む)を含むオブジェクトです。
  2. - `````noticeUI`````は、通知ボックスが作成されたときに表示される通知Reactコンポーネントです。
  3. `````App.js`````の先頭に移動し、[`````withNotices`````メソッドを`````"@wordpress/components"`````からインポート](https://github.com/wptrainingteam/devblog-dataviews-plugin/commit/0e0059f6dbe5361d383a7adfa6243426fd8dabe1#diff-3d74dddefb6e35fbffe3c76ec0712d5c416352d9449e2fcc8210a9dee57dff67R4)します:
  4. ``````bash
  5. src/App.jsimport { withNotices } from "@wordpress/components";
  6. `
  1. ``````bash
  2. src/App.jsconst App = withNotices(({ noticeOperations, noticeUI }) => {
  3. const { createNotice } = noticeOperations;
  4. ...
  5. });
  6. `

createNoticeメソッドをnoticeOperationsから分解して使用して、Reactアプリの画面上にnoticeUIコンポーネントを配置する場所に通知ボックスを作成できます。これらの通知ボックスは、メディアライブラリにアップロードされた画像の成功または失敗についてユーザーに情報を提供するために使用できます。

次のthenおよびcatchメソッドをapiFetch呼び出しにチェーンして、APIリクエストの成功またはエラーを処理します。まだ定義されていないonSuccessMediaUploadおよびonErrorMediaUpload関数を使用します:

  1. src/App.js// 3- Send the request to the WP REST API with apiFetch
  2. await apiFetch({
  3. path: "/wp/v2/media",
  4. method: "POST",
  5. body: formDataWithImage,
  6. })
  7. .then(onSuccessMediaUpload)
  8. .catch(onErrorMediaUpload);

次に、次のコードをAppコンポーネントに追加します(これらの関数の呼び出しの前に)onSuccessMediaUploadおよびonErrorMediaUpload関数の定義を含めます:

  1. src/App.jsconst onSuccessMediaUpload = (oImageUploaded) => {
  2. const title = oImageUploaded.title.rendered;
  3. createNotice({
  4. status: "success",
  5. content: __(`${title}.jpg successfully uploaded to Media Library!`),
  6. isDismissible: true,
  7. });
  8. };
  9. const onErrorMediaUpload = (error) => {
  10. console.log(error);
  11. createNotice({
  12. status: "error",
  13. content: __("An error occurred!"),
  14. isDismissible: true,
  15. });
  16. };
  1. アップロード操作が失敗した場合、`````onErrorMediaUpload`````は、アップロード操作の失敗を引き起こした特定のエラーを受け取ります。この関数内でも、何かがうまくいかなかったことをユーザーに通知するために`````error`````ボックスを呼び出すことができます。
  2. `````createNotice`````メソッドによってトリガーされた通知ボックスを表示するには、[`````noticeUI`````](https://github.com/wptrainingteam/devblog-dataviews-plugin/commit/0e0059f6dbe5361d383a7adfa6243426fd8dabe1#diff-3d74dddefb6e35fbffe3c76ec0712d5c416352d9449e2fcc8210a9dee57dff67R186)コンポーネントを`````App`````コンポーネントのreturnに追加します:
  3. ``````bash
  4. src/App,jsreturn (
  5. <>
  6. {noticeUI}
  7. <DataViews
  8. ...
  9. />
  10. </>
  11. );
  12. `

Reactコンポーネントは1つの親要素しか返せないため、Fragmentコンポーネントを使用して要素をグループ化できます。

通知ボックスは画面の上部に表示されるため、次のコードを追加して、‘upload-media’コールバックの開始時に毎回このアクションがトリガーされるたびにスクロールして、ユーザーが通知を見逃さないようにします:

  1. src/App.jswindow.scrollTo( 0, 0 );

アップロードプロセスの進行状況を示すスピナー

追加できる良いUI要素は、アップロードプロセスの進行状況を示すインジケーターです。WordPressコンポーネントのSpinnerコンポーネントは、これに最適です。

ただし、Spinnerコンポーネントを使用する前に、アップロードプロセスが実行されている間のみ表示されるようにするためのロジックを追加する必要があります。進行中のアップロードプロセスを監視するには、進行中のすべてのアップロードの配列を保持する状態変数を使用できます。

状態変数を使用してアップロードプロセスを追跡する

Appコンポーネントの先頭に次のコードを追加して、useStateを使用して状態変数を追加します:

  1. src/App.jsconst [isUploadingItems, setIsUploadingItems] = useState([]);
  1. 状態変数が更新されるたびに、Reactコンポーネントが再レンダリングされます。
  2. [次のコード](https://github.com/wptrainingteam/devblog-dataviews-plugin/commit/c046c5808e704409f9d717311abed4cac8f0af0b#diff-3d74dddefb6e35fbffe3c76ec0712d5c416352d9449e2fcc8210a9dee57dff67R161)を`````forEach`````コールバックの最初に追加します(‘upload-media’アクションのコールバック内):
  3. ``````bash
  4. src/App.jssetIsUploadingItems((prevIsUploadingItems) => [
  5. ...prevIsUploadingItems,
  6. image.slug,
  7. ]);
  8. `

上記のコードは、アップロードのために選択されている各画像のスラグをisUploadingItems状態変数配列に追加します。

画像が正常にアップロードされたときにisUploadingItems状態変数配列から画像のスラグを削除するか、エラーが発生したときに完全に空にするには、https://github.com/wptrainingteam/devblog-dataviews-plugin/commit/c046c5808e704409f9d717311abed4cac8f0af0b#diff-3d74dddefb6e35fbffe3c76ec0712d5c416352d9449e2fcc8210a9dee57dff67R124onSuccessMediaUploadおよびonErrorMediaUpload関数に追加します。

  1. src/App.jsconst onSuccessMediaUpload = (oImageUploaded) => {
  2. ...
  3. setIsUploadingItems((prevIsUploadingItems) =>
  4. prevIsUploadingItems.filter((slugLoading) => slugLoading !== title)
  5. );
  6. ...
  7. };
  8. const onErrorMediaUpload = (error) => {
  9. setIsUploadingItems([]);
  10. ...
  11. };

スピナーコンポーネントの表示

  1. App.jsの先頭に移動し、[`````Spinner`````コンポーネント](https://github.com/wptrainingteam/devblog-dataviews-plugin/commit/c046c5808e704409f9d717311abed4cac8f0af0b#diff-3d74dddefb6e35fbffe3c76ec0712d5c416352d9449e2fcc8210a9dee57dff67R4)を`````"@wordpress/components"`````からインポートします:
  2. ``````bash
  3. src/App.jsimport { Spinner } from "@wordpress/components";
  4. `

最後に、画像のアップロードがまだ進行中である間にスピナーコンポーネントを条件付きで表示するために、次のコードをAppコンポーネントのreturn文に追加します:

  1. src/Ap.jsreturn (
  2. <>
  3. {!!isUploadingItems.length && <Spinner />}
  4. ...
  5. <DataViews
  6. ...
  7. />
  8. </>
  9. );

モーダルウィンドウを使用したアクション

前回の記事で作成したアクションを思い出してください。画像をフルサイズで表示するためのものです。このアクションを改善して、ユーザーが新しいウィンドウで開く画像のサイズを選択できるようにモーダルを表示することはどうでしょうか?

データビューアクションは、トリガーされたときにモーダルウィンドウを表示するメカニズムを提供します。RenderModalプロパティを介して、アクション呼び出し時にモーダルウィンドウとして表示されるReactコンポーネントを定義できます。RenderModalプロパティが提供されると、callbackプロパティは無視されます。

  1. see-original’アクションの定義を次のコードに置き換えることができます:
  2. ``````bash
  3. src/App.js{
  4. id: 'see-original',
  5. label: __( 'See Original' ),
  6. modalHeader: __( 'See Original Image', 'action label' ),
  7. RenderModal: ( { items: [ item ], closeModal } ) => {
  8. return (
  9. <div>
  10. <button
  11. onClick={ () => {
  12. closeModal();
  13. window.open( item.urls.raw, '_blank' );
  14. } }
  15. >
  16. Open original image in new window
  17. </button>
  18. </div>
  19. );
  20. },
  21. }
  22. `

上記のコードは、アクションが画像に対してトリガーされるとモーダルを開き、元の画像を新しいウィンドウで開くボタンを提供します。これは、callbackを介して前のバージョンで定義されたのと同じ動作ですが、その間にモーダルウィンドウがあります。

このモーダルウィンドウをより魅力的にするために、ユーザーが新しいウィンドウで開く画像のサイズを選択できるようにドロップダウンを提供しましょう。

まず、モーダルウィンドウで使用するいくつかのコンポーネントをインポートします:

  1. src/App.jsimport {
  2. SelectControl,
  3. Button,
  4. __experimentalText as Text,
  5. __experimentalHStack as HStack,
  6. __experimentalVStack as VStack,
  7. ...
  8. } from '@wordpress/components';

SelectControlButtonTextHStack、およびVStackは、Reactを使用したWordPress開発のために利用可能なWordPressコンポーネントです。これらのコンポーネントや他のコンポーネントのライブ例は、Gutenberg Storybookで見つけることができます。

次に、次のコードを使用して‘see-original’アクションを定義します:

  1. src/App.js{
  2. id: 'see-original',
  3. label: __( 'See Original' ),
  4. modalHeader: __( 'See Original Image', 'action label' ),
  5. RenderModal: ( { items: [ item ], closeModal } ) => {
  6. const [ size, setSize ] = useState( 'raw' );
  7. return (
  8. <VStack spacing="5">
  9. <Text>
  10. { `Select the size you want to open for "${ item.slug }"` }
  11. </Text>
  12. <HStack justify="left">
  13. <SelectControl
  14. __nextHasNoMarginBottom
  15. label="Size"
  16. value={ size }
  17. options={ Object.keys( item.urls )
  18. .filter( ( url ) => url !== 'small_s3' )
  19. .map( ( url ) => ( {
  20. label: url,
  21. value: url,
  22. } ) ) }
  23. onChange={ setSize }
  24. />
  25. </HStack>
  26. <HStack justify="right">
  27. <Button
  28. __next40pxDefaultSize
  29. variant="primary"
  30. onClick={ () => {
  31. closeModal();
  32. window.open( item.urls[ size ], '_blank' );
  33. } }
  34. >
  35. Open image from original location
  36. </Button>
  37. </HStack>
  38. </VStack>
  39. );
  40. },
  41. },

上記のコードは、SelectControlコンポーネントを使用して、各画像の情報を含むオブジェクトから利用可能なサイズを表示します。選択された画像サイズは、size状態変数にsetSize関数を介して保存されます。

ButtonコンポーネントのonClickは、closeModal(props経由で利用可能)を呼び出し、次に選択された画像(選択されたsize)を新しいウィンドウで開きます。

これで、画像の‘see-original’アクションをクリックすると、次のようなモーダルウィンドウが表示されるはずです:

データビューからのアクション:メディアライブラリに画像を追加(Actions from Data Views: Adding images to the Media Library) - img2

完全な実装と出力

この時点で、プロジェクトの最終src/App.jsファイルはこのように見えるはずです

  1. src/App.jsimport { DataViews, filterSortAndPaginate } from '@wordpress/dataviews';
  2. import { getTopicsElementsFormat } from './utils';
  3. import { useState, useMemo } from '@wordpress/element';
  4. import {
  5. SelectControl,
  6. Button,
  7. __experimentalText as Text,
  8. __experimentalHStack as HStack,
  9. __experimentalVStack as VStack,
  10. Spinner,
  11. withNotices,
  12. } from '@wordpress/components';
  13. import { __ } from '@wordpress/i18n';
  14. import apiFetch from '@wordpress/api-fetch';
  15. import './style.scss';
  16. // source "data" definition
  17. import { dataPhotos } from './data';
  18. // "defaultLayouts" definition
  19. const primaryField = 'id';
  20. const mediaField = 'img_src';
  21. const defaultLayouts = {
  22. table: {
  23. layout: {
  24. primaryField,
  25. },
  26. },
  27. grid: {
  28. layout: {
  29. primaryField,
  30. mediaField,
  31. },
  32. },
  33. };
  34. // "fields" definition
  35. const fields = [
  36. {
  37. id: 'img_src',
  38. label: __( 'Image' ),
  39. render: ( { item } ) => (
  40. <img alt={ item.alt_description } src={ item.urls.thumb } />
  41. ),
  42. enableSorting: false,
  43. },
  44. {
  45. id: 'id',
  46. label: __( 'ID' ),
  47. enableGlobalSearch: true,
  48. },
  49. {
  50. id: 'author',
  51. label: __( 'Author' ),
  52. getValue: ( { item } ) =>
  53. render: ( { item } ) => (
  54. <a target="_blank" href={ item.user.url } rel="noreferrer">
  55. { item.user.first_name } { item.user.last_name }
  56. </a>
  57. ),
  58. enableGlobalSearch: true,
  59. },
  60. {
  61. id: 'alt_description',
  62. label: __( 'Description' ),
  63. enableGlobalSearch: true,
  64. },
  65. {
  66. id: 'topics',
  67. label: __( 'Topics' ),
  68. elements: getTopicsElementsFormat( dataPhotos ),
  69. render: ( { item } ) => {
  70. return (
  71. <div className="topic_photos">
  72. { item.topics.map( ( topic ) => (
  73. <span key={ topic } className="topic_photo_item">
  74. { topic.toUpperCase() }
  75. </span>
  76. ) ) }
  77. </div>
  78. );
  79. },
  80. filterBy: {
  81. operators: [ 'isAny', 'isNone', 'isAll', 'isNotAll' ],
  82. },
  83. enableSorting: false,
  84. },
  85. {
  86. id: 'width',
  87. label: __( 'Width' ),
  88. getValue: ( { item } ) => parseInt( item.width ),
  89. enableSorting: true,
  90. },
  91. {
  92. id: 'height',
  93. label: __( 'Height' ),
  94. getValue: ( { item } ) => parseInt( item.height ),
  95. enableSorting: true,
  96. },
  97. ];
  98. const App = withNotices( ( { noticeOperations, noticeUI } ) => {
  99. const { createNotice } = noticeOperations;
  100. const [ isUploadingItems, setIsUploadingItems ] = useState( [] );
  101. // "view" and "setView" definition
  102. const [ view, setView ] = useState( {
  103. type: 'table',
  104. perPage: 10,
  105. layout: defaultLayouts.table.layout,
  106. fields: [
  107. 'img_src',
  108. 'id',
  109. 'alt_description',
  110. 'author',
  111. 'topics',
  112. 'width',
  113. 'height',
  114. ],
  115. } );
  116. // "processedData" and "paginationInfo" definition
  117. const { data: processedData, paginationInfo } = useMemo( () => {
  118. return filterSortAndPaginate( dataPhotos, view, fields );
  119. }, [ view ] );
  120. const onSuccessMediaUpload = ( oImageUploaded ) => {
  121. const title = oImageUploaded.title.rendered;
  122. setIsUploadingItems( ( prevIsUploadingItems ) =>
  123. prevIsUploadingItems.filter(
  124. ( slugLoading ) => slugLoading !== title
  125. )
  126. );
  127. createNotice( {
  128. status: 'success',
  129. // translators: %s is the image title
  130. content:
  131. __( 'successfully uploaded to Media Library' ),
  132. isDismissible: true,
  133. } );
  134. };
  135. const onErrorMediaUpload = ( error ) => {
  136. setIsUploadingItems( [] );
  137. console.log( error );
  138. createNotice( {
  139. status: 'error',
  140. content: __( 'An error occurred!' ),
  141. isDismissible: true,
  142. } );
  143. };
  144. // "actions" definition
  145. const actions = [
  146. {
  147. id: 'upload-media',
  148. label: __( 'Upload Media' ),
  149. isPrimary: true,
  150. icon: 'upload',
  151. supportsBulk: true,
  152. callback: ( images ) => {
  153. images.forEach( async ( image ) => {
  154. // 1- Download the image and convert it to a blob
  155. const responseRequestImage = await fetch( image.urls.raw );
  156. const blobImage = await responseRequestImage.blob();
  157. // 2- Create FormData with the image blob
  158. const formDataWithImage = new FormData();
  159. formDataWithImage.append(
  160. 'file',
  161. blobImage,
  162. );
  163. // 3- Send the request to the WP REST API with apiFetch
  164. await apiFetch( {
  165. path: '/wp/v2/media',
  166. method: 'POST',
  167. body: formDataWithImage,
  168. } ).then( console.log );
  169. } );
  170. },
  171. },
  172. {
  173. id: 'see-original',
  174. label: __( 'See Original' ),
  175. modalHeader: __( 'See Original Image', 'action label' ),
  176. RenderModal: ( { items: [ item ], closeModal } ) => {
  177. const [ size, setSize ] = useState( 'raw' );
  178. return (
  179. <VStack spacing="5">
  180. <Text>
  181. { `Select the size you want to open for "${ item.slug }"` }
  182. </Text>
  183. <HStack justify="left">
  184. <SelectControl
  185. __nextHasNoMarginBottom
  186. label="Size"
  187. value={ size }
  188. options={ Object.keys( item.urls )
  189. .filter( ( url ) => url !== 'small_s3' )
  190. .map( ( url ) => ( {
  191. label: url,
  192. value: url,
  193. } ) ) }
  194. onChange={ setSize }
  195. />
  196. </HStack>
  197. <HStack justify="right">
  198. <Button
  199. __next40pxDefaultSize
  200. variant="primary"
  201. onClick={ () => {
  202. closeModal();
  203. window.open( item.urls[ size ], '_blank' );
  204. } }
  205. >
  206. Open image from original location
  207. </Button>
  208. </HStack>
  209. </VStack>
  210. );
  211. },
  212. },
  213. ];
  214. return (
  215. <>
  216. { !! isUploadingItems.length && <Spinner /> }
  217. { noticeUI }
  218. <DataViews
  219. data={ processedData }
  220. fields={ fields }
  221. view={ view }
  222. onChangeView={ setView }
  223. defaultLayouts={ defaultLayouts }
  224. actions={ actions }
  225. paginationInfo={ paginationInfo }
  226. />
  227. </>
  228. );
  229. } );
  230. export default App;

データビューのプロジェクトはこれで完了です!

管理パネルに移動し、‘メディアからサードパーティサービスを追加’サブページを‘メディア’設定の下に開きます。次の動作が観察されるはずです:

  • テーブルモードでは、各画像にプライマリの‘Upload Media’アクションがあり、ホバー時にアイコンとして表示されます。
  • 画像の三点ボタンをクリックすると、‘Upload Media’と‘See Original’の2つのアクションが表示されます。
  • 複数の画像を選択し、すべてに対して‘Upload Media’アクションを同時に実行できます。
  • 画像のアップロードプロセスが完了すると、通知ボックスが表示されます。
  • 画像がアップロードされている間、スピナーアイコンが表示されます。
  • “See Original”アクションは、ユーザーが新しいウィンドウで開く画像のサイズを選択できるモーダルウィンドウを表示します。

このプロジェクトの完全なコードは、https://github.com/wptrainingteam/devblog-dataviews-pluginで入手可能です。

プロジェクトのライブデモも、Playgroundによって提供されています。

まとめ

この記事は、データビューコンポーネントの可能性を探る2部構成のシリーズを締めくくります:

この機能の進捗を追跡したい場合は、gutenbergリポジトリの「[Feature] Data Views」ラベルの問題を確認できます。このコンポーネントには、隔週の更新もあり、https://make.wordpress.org/design/tag/dataviews/で共有されています。

@wordpress/dataviewsパッケージは、プラグイン開発者に新しい可能性を開くツールであり、この機能に取り組んでいるWordPressコア開発者は、あなたの意見を聞きたいと思っています。これを使用して興味深いと感じましたか?それとも、何かできなかったことに遭遇しましたか?コメントやGutenbergリポジトリの問題としてあなたの考えを共有してください。

@bph@greenshady@oandregal@milana_capに感謝します。フィードバックとこの投稿のレビューを提供してくれました。