{"id":25232930,"url":"https://github.com/evermade/wp-block-toolkit","last_synced_at":"2025-10-09T08:21:20.290Z","repository":{"id":57112303,"uuid":"395222114","full_name":"evermade/wp-block-toolkit","owner":"evermade","description":"Toolkit for developing WordPress Gutenberg blocks.","archived":false,"fork":false,"pushed_at":"2024-09-16T06:03:46.000Z","size":2365,"stargazers_count":15,"open_issues_count":6,"forks_count":2,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-01-15T21:41:29.721Z","etag":null,"topics":["gutenberg","wordpress"],"latest_commit_sha":null,"homepage":"https://www.evermade.fi","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evermade.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-08-12T06:44:29.000Z","updated_at":"2025-01-09T05:48:04.000Z","dependencies_parsed_at":"2023-09-27T17:10:15.542Z","dependency_job_id":null,"html_url":"https://github.com/evermade/wp-block-toolkit","commit_stats":{"total_commits":28,"total_committers":2,"mean_commits":14.0,"dds":0.3214285714285714,"last_synced_commit":"c7787ed3f4e9dc4f05085a4da299927303106e1f"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Fwp-block-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Fwp-block-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Fwp-block-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Fwp-block-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evermade","download_url":"https://codeload.github.com/evermade/wp-block-toolkit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238302183,"owners_count":19449558,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gutenberg","wordpress"],"created_at":"2025-02-11T13:37:11.191Z","updated_at":"2025-10-09T08:21:20.259Z","avatar_url":"https://github.com/evermade.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WordPress Block Toolkit\n\nA collection of tools for WordPress Gutenberg block building.\n\n## Styles\n\nTo include the editor styles, add this to the top of your block's `_editor.scss`:\n\n`@import \"~@evermade/wp-block-toolkit/build/index.css\";`\n\n## Components\n\n### FocalPointImage\n\nPurely presentational component, which helps work with the `FocalPointPicker` from `@wordpress/components`.\n\nRenders a standard `\u003cimg /\u003e` element from data received from the MediaUpload flow. See `\u003cImage\u003e` below for all available props.\n\n```javascript\n\u003cFocalPointImage\n  url=\"https://...\"\n  focalPoint={{\n    x: 0.5,\n    y: 0.5,\n  }}\n/\u003e\n```\n\n### Image\n\nSimple presentational component, which renders a standard `\u003cimg /\u003e` element from data format which is received from the MediaUpload flow.\n\nFor example instead of `src` it uses an `url` prop etc.\n\n```javascript\n\u003cImage\n  id={myImageId}\n  url=\"https://...\"\n  alt=\"My alt text\"\n  width={1600}\n  height={900}\n  title=\"My title text\"\n  loading=\"lazy\"\n/\u003e\n```\n\nIf you use an image object saved from the MediaUpload flow, you can simply do:\n\n```javascript\n\u003cImage {...attributes.myImage} /\u003e\n```\n\n### ImageControl\n\nSimple image upload and replacement flow for managing media.\n\nBy setting the `showPreview` prop to `false`, you can build a custom image preview component.\n\n![ImageControl example](assets/ImageControl-screenshot-01.png);\n\n![ImageControl example](assets/ImageControl-screenshot-02.png);\n\n```javascript\n\u003cImageControl\n  id={myImageId}\n  onSelect={(image) =\u003e setAttributes({ myImageId: image.id })}\n  onRemove={() =\u003e setAttributes({ myImageId: undefined })}\n  showPreview={true}\n/\u003e\n```\n\n### InlineNotice\n\nCompliments the base WordPress notice system by allowing you to show either warning or error level notices inside the editor.\n\n![InlineNotice example](assets/InlineNotice-screenshot-01.png)\n\n```javascript\n\u003cInlineNotice status=\"error\"\u003e\n  \u003cstrong\u003eError: \u003c/strong\u003e Lorem ipsum dolor sit amet.\n\u003c/InlineNotice\u003e\n```\n\n### PostControl\n\nCustom ComboboxControl for selecting a single post. Takes an array of post objects and returns and id number on change.\n\n![PostControl example](assets/PostControl-screenshot-01.png)\n\n```javascript\n\u003cPostControl\n  label=\"My Label\"\n  value={mySelectedPostId}\n  posts={myPosts}\n  onChange={(value) =\u003e\n    setAttributes({\n      mySelectedPostId: value,\n    })\n  }\n/\u003e\n```\n\n### PostSearchControl\n\nFor selecting a single post from a large pool of posts. More performant than `PostControl` at the cost of requiring additional user input.\n\nAs a further performance optimization, by default shows only 20 results and a \"View more results\" button. You can configure the number of initial results with the `numOfInitialResults` prop, or disable the optimization completely by setting it to `-1`.\n\n![PostSearchControl example](assets/PostSearchControl-screenshot-01.png)\n\n```javascript\n\u003cPostSearchControl\n  type=\"page\"\n  label=\"Choose a page\"\n  placeholder=\"Search here\"\n  value={mySelectedPageId}\n  onChange={(value) =\u003e\n    setAttributes({\n      mySelectedPageId: value,\n    })\n  }\n  numOfInitialResults={20}\n  filterResults={(results) =\u003e {\n    // You can modify the search results before returning them.\n    return results;\n  }}\n/\u003e\n```\n\n### RequireBlocks\n\nAllows you to only show components if certain blocks are installed and activated in the system. If some of the blocks are missing, displays an error instead using an `InlineNotice`.\n\n![RequireBlocks example](assets/RequireBlocks-screenshot-01.png)\n\n```javascript\n\u003cRequireBlocks blocks={[\"core/paragraph\", \"my-namespace/my-custom-block\"]}\u003e\n  \u003ch2\u003eMy title\u003c/h2\u003e\n  \u003cp\u003eLorem ipsum dolor sit amet, consectetuer adipiscing elit.\u003c/p\u003e\n  \u003cMyComponent /\u003e\n\u003c/RequireBlocks\u003e\n```\n\n### SortablePostsControl\n\nSelect and sort multiple posts, with search filtering. Takes an array of post objects and returns an array of id numbers on change.\n\n![SortablePostsControl example](assets/SortablePostsControl-screenshot-01.png)\n\n```javascript\n\u003cSortablePostsControl\n  label={\"My Label\"}\n  posts={myPosts}\n  value={mySelectedPosts}\n  onChange={(value) =\u003e\n    setAttributes({\n      mySelectedPosts: value,\n    })\n  }\n/\u003e\n```\n\n### SortablePostSearchControl\n\nSelect and sort multiple posts, by searching from a large pool of posts. Takes an array of post ids as value and returns the same on change.\n\n![SortablePostsControl example](assets/SortablePostsControl-screenshot-01.png)\n\n```javascript\n\u003cSortablePostSearchControl\n  type=\"page\"\n  label=\"Choose pages\"\n  placeholder=\"Search here\"\n  value={mySelectedPageIds}\n  onChange={(value) =\u003e\n    setAttributes({\n      mySelectedPageIds: value,\n    })\n  }\n  numOfInitialResults={20}\n  filterResults={(results) =\u003e {\n    // You can modify the search results before returning them.\n    return results;\n  }}\n/\u003e\n```\n\n### TaxonomyControl\n\nSimilar to the default WordPress category selector, shows a filterable list of checkboxes.\n\n![TaxonomyControl example](assets/TaxonomyControl-screenshot-01.png)\n\n```javascript\n\u003cTaxonomyControl\n  slug=\"category\"\n  label=\"My Label\"\n  value={mySelectedTaxonomies}\n  onChange={(value) =\u003e setAttributes({ mySelectedTaxonomies: value })}\n/\u003e\n```\n\n## Hooks\n\n### useAllPosts\n\nQoL wrapper for getting all posts of a certain post type, ordered alphabetically by title.\n\n```javascript\nconst stories = useAllPosts(\"story\");\nconst contacts = useAllPosts(\"contact\");\n```\n\n### useRequiredBlocks\n\nChecks if the listed block names are installed and activated on the site. Also returns the list of missing block names if you wish to list them in an error message for example.\n\n```javascript\nconst { missingBlocks, hasRequiredBlocks } = useRequiredBlocks([\n  \"core/paragraph\",\n  \"core/image\",\n]);\n```\n\n### usePost\n\nQoL wrapper for getting a single post entity using a post type and id.\n\n```javascript\nconst story = usePost(\"story\", 13);\n```\n\n### usePostSearch\n\nSimilar to `useAllPosts`, except uses a search parameter for the query. Much more performant when dealing with large amounts of content.\n\nIt's recommended to debounce the search string, to avoid excessive database queries.\n\n```javascript\nconst loremIpsumStories = usePostSearch({\n  postType: \"story\",\n  search: \"lorem ipsum\",\n});\n```\n\n## Utils\n\nUsage:\n\n```\nimport { utils } from '@evermade/wp-block-toolkit';\n```\n\n### utils.postToControlOption\n\nNormalize a WP post to work as a select type control option.\n\n### utils.labelWithCount\n\nBasic label string with count in parenthesis.\n\n### utils.pickImageProps\n\nPick typical relevant image props from a WordPress MediaUpload object.\n\n## Advanced Examples\n\n### Handling Media Object\n\nIf you need more than just the id, you can use the following flow for managing a media object.\n\nIn your block's `block.json`, add an object type attribute:\n\n```json\n{\n  \"attributes\": {\n    \"myImage\": {\n      \"type\": \"object\"\n    }\n  }\n}\n```\n\nIn your block's edit, you'll need to extract the id when rendering the ImageControl component and pick the relevant properties for storage on save.\n\n```javascript\nimport { ImageControl, utils } from \"@evermade/wp-block-toolkit\";\n\nexport default function Edit({ attributes, setAttributes }) {\n  return (\n    \u003cImageControl\n      id={attributes.myImage.id}\n      onSelect={(image) =\u003e\n        setAttributes({\n          myImage: utils.pickImageProps(image),\n        })\n      }\n      onRemove={() =\u003e\n        setAttributes({\n          myImage: undefined,\n        })\n      }\n    /\u003e\n  );\n}\n```\n\n### Image Control with Focal Point Picker\n\nThis flow describes how to setup image media management with a focal point picker:\n\n![Image Control with Focal Point Picker example](assets/ImageControlWithFocalPointPicker-screenshot-01.png)\n\nFirst, you need two attributes for your block's `block.json`:\n\n```json\n{\n  \"attributes\": {\n    \"myImage\": {\n      \"type\": \"object\"\n    },\n    \"myFocalPoint\": {\n      \"type\": \"object\"\n    }\n  }\n}\n```\n\nIn your block's `edit.js`, use `ImageControl` from this toolkit and `FocalPointPicker` from `@wordpress/components`.\n\nNote how we disable the preview of ImageControl with `showPreview` set to `false`. This allows us to replace it with the focal point picker control after a media item has been selected.\n\nWhenever the media item is removed, we also reset the focal point.\n\nThen use `FocalPointImage` from this toolkit to render the positioned image result.\n\n```javascript\nimport {\n  ImageControl,\n  FocalPointImage,\n  utils,\n} from \"@evermade/wp-block-toolkit\";\n\nimport { FocalPointPicker } from \"@wordpress/components\";\nimport { InspectorControls } from \"@wordpress/block-editor\";\nimport { Fragment } from \"@wordpress/element\";\n\nexport default function Edit({ attributes, setAttributes }) {\n  const { myImage, myFocalPoint } = attributes;\n\n  return (\n    \u003cFragment\u003e\n      \u003cInspectorControls\u003e\n        {myImage \u0026\u0026 (\n          \u003cFocalPointPicker\n            url={myImage?.url}\n            value={myFocalPoint}\n            onChange={(newFocalPoint) =\u003e\n              setAttributes({\n                myFocalPoint: newFocalPoint,\n              })\n            }\n          /\u003e\n        )}\n\n        \u003cImageControl\n          id={myImage?.id}\n          showPreview={false}\n          onSelect={(image) =\u003e\n            setAttributes({\n              myImage: utils.pickImageProps(image),\n            })\n          }\n          onRemove={() =\u003e\n            setAttributes({\n              myImage: undefined,\n              myFocalPoint: undefined,\n            })\n          }\n        /\u003e\n      \u003c/InspectorControls\u003e\n\n      \u003cdiv className=\"my-block\"\u003e\n        {myImage \u0026\u0026 \u003cFocalPointImage {...myImage} focalPoint={myFocalPoint} /\u003e}\n      \u003c/div\u003e\n    \u003c/Fragment\u003e\n  );\n}\n```\n\n## Changelog\n\n### 7.1.0\n\n- Fixed `ImageControl` export to default.\n- Added `Image` and `FocalPointImage` presentational components.\n\n### 7.0.0\n\n- Updated npm dependencies\n- Introduced `ImageControl` component.\n- Exported utils. Added `pickImageProps` util for use with ImageControl component.\n\n### 6.1.0\n\n- Refactored the way textdomain is used and removed config.json.\n- Introduced `SortablePostSearchControl`.\n\n### 6.0.0\n\n- Updated npm dependencies\n\n### 5.0.3\n\n- Fixed a rare issue where `PostSearchControl`'s reset button became full width when used inside a medium size `Placeholder` component.\n\n### 5.0.2\n\n- Add support for post status in `PostSearchControl`.\n\n### 5.0.1\n\n- Fixed an issue where `SortablePostsControl` didn't work properly with `setAttributes` of WordPress. Now always returns a sorted list of ids instead of a callback when sorted.\n\n### 5.0.0\n\n- Breaking change: Changed the way `TaxonomyControl` is used. It now takes just the taxonomy slug instead of an array of terms.\n- Breaking change: Updated dependencies to the latest versions.\n\n### 4.1.0\n\n- Changed `usePostSearch` to use named arguments.\n- Optimized the performance of `PostSearchControl` by limiting the number of initial results.\n- `PostSearchControl` now also has a `numOfInitialResults` prop that can be used to configure the optimization or disable it completely with `-1`.\n\n### 4.0.0\n\n- Breaking change: Updated @wordpress/scripts to [25.4.0](https://github.com/WordPress/gutenberg/blob/trunk/packages/scripts/CHANGELOG.md#2540-2023-02-15), which also introduces React 18.\n- Changed `react-sortable-hoc` which is no longer maintained and compatible with React 18 to `@dnd-kit/core`.\n- Added possibility to filter `PostSearchControl` results via the `filterResults` prop.\n\n### 3.1.1\n\n- Fixed an issue in SortablePostsControl where `undefined` items were being added to SortableList.\n- Added `type` as a prop to the example of PostSearchControl.\n\n### 3.1.0\n\n- Introduced a new component: PostSearchControl. It's better suited for choosing a post from a large number of posts than PostControl.\n- Introduced two new hooks: usePost and usePostSearch.\n- Updated npm dependencies\n\n### 3.0.0\n\n- Breaking change: Updated @wordpress/block-editor to [10.0.0](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/CHANGELOG.md#1000-2022-09-13)\n  - 2 major bumps!\n- Updated npm dependencies\n\n### 2.0.0\n\n- Breaking change: Updated @wordpress/scripts to [24.0.0](https://github.com/WordPress/gutenberg/blob/trunk/packages/scripts/CHANGELOG.md#2400-2022-08-24)\n  - 4 major bumps!\n  - Increased the minimum Node.js version to 14 and npm to 6.14.4\n  - Many major dependency bumps\n- Updated npm dependencies\n- Ran code format\n- Fixed a few code lint errors\n\n### 1.0.6\n\n- Fixed padding and margin issues with PostControl's ComboboxControl when used within the editor\n- Added a CSS targetable parent to PostControl\n\n### 1.0.5\n\n- Fixed a bug with special characters in TaxonomyControl\n- Fixed a bug where TaxonomyControl would crash on a null value\n\n### 1.0.4\n\n- Fixed a class bug in SortablePostsControl component\n\n### 1.0.3\n\n- Updated npm packages\n- Fixed incorrect InlineNotice prop in RequireBlocks component\n\n### 1.0.2\n\n- Use raw instead of rendered title to avoid issues with special characters in post control option\n\n### 1.0.1\n\n- Make InlineNotice paddings a bit nicer.\n\n### 1.0.0\n\n- Breaking changes\n- Changed InlineNotice `level` prop to `status` to be in line with core Notice component\n- In order to support using InlineNotice on server side rendering, moved InlineNotice styles to Sass\n- Added size option to InlineNotice\n\n### 0.4.0\n\n- Updated npm packages\n- Changed named imports from config.json to default imports, as warned by webpack\n\n### 0.3.0\n\n- Added a safety check around SortablePostsControl's setOptions\n\n### 0.2.0\n\n- Added an safety check around PostControl's setOptions\n\n### 0.1.0\n\n- Initial release\n\n## Development\n\n- Update version in `package.json`\n- Commit to master\n- Set tag with version number to git\n- Create new release in GitHub\n- NPM package is automatically published from GitHub\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevermade%2Fwp-block-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevermade%2Fwp-block-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevermade%2Fwp-block-toolkit/lists"}