├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── README.md
├── assets
└── js
│ ├── extend-block-example.js
│ └── spacing-control.js
├── dist
├── extend-block-example.js
└── extend-block-example.js.map
├── extend-block-example.php
├── package-lock.json
└── package.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["transform-react-jsx"]
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 |
4 | # WordPress Coding Standards
5 | # https://make.wordpress.org/core/handbook/coding-standards/
6 |
7 | root = true
8 |
9 | [*]
10 | charset = utf-8
11 | end_of_line = lf
12 | insert_final_newline = true
13 | trim_trailing_whitespace = true
14 | indent_style = tab
15 | indent_size = 4
16 |
17 | [*.{yml,json}]
18 | indent_style = space
19 | indent_size = 2
20 |
21 | [*.md]
22 | indent_style = space
23 | trim_trailing_whitespace = false
24 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*.min.js
2 | **/*.build.js
3 | **/node_modules/**
4 | **/vendor/**
5 | build
6 | coverage
7 | cypress
8 | node_modules
9 | vendor
10 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "babel-eslint",
4 | "extends": [
5 | "wordpress",
6 | "plugin:react/recommended",
7 | "plugin:jsx-a11y/recommended",
8 | "plugin:jest/recommended"
9 | ],
10 | "env": {
11 | "browser": false,
12 | "es6": true,
13 | "node": true,
14 | "mocha": true,
15 | "jest/globals": true
16 | },
17 | "parserOptions": {
18 | "sourceType": "module",
19 | "ecmaFeatures": {
20 | "jsx": true
21 | }
22 | },
23 | "globals": {
24 | "wp": true,
25 | "wpApiSettings": true,
26 | "window": true,
27 | "document": true
28 | },
29 | "plugins": ["react", "jsx-a11y", "jest"],
30 | "settings": {
31 | "react": {
32 | "pragma": "wp"
33 | }
34 | },
35 | "rules": {
36 | "array-bracket-spacing": ["error", "always"],
37 | "brace-style": ["error", "1tbs"],
38 | "camelcase": ["error", { "properties": "never" }],
39 | "comma-dangle": ["error", "always-multiline"],
40 | "comma-spacing": "error",
41 | "comma-style": "error",
42 | "computed-property-spacing": ["error", "always"],
43 | "constructor-super": "error",
44 | "dot-notation": "error",
45 | "eol-last": "error",
46 | "eqeqeq": "error",
47 | "func-call-spacing": "error",
48 | "indent": ["error", "tab", { "SwitchCase": 1 }],
49 | "jsx-a11y/label-has-for": [
50 | "error",
51 | {
52 | "required": "id"
53 | }
54 | ],
55 | "jsx-a11y/media-has-caption": "off",
56 | "jsx-a11y/no-noninteractive-tabindex": "off",
57 | "jsx-a11y/role-has-required-aria-props": "off",
58 | "jsx-quotes": "error",
59 | "key-spacing": "error",
60 | "keyword-spacing": "error",
61 | "lines-around-comment": "off",
62 | "no-alert": "error",
63 | "no-bitwise": "error",
64 | "no-caller": "error",
65 | "no-console": "error",
66 | "no-const-assign": "error",
67 | "no-debugger": "error",
68 | "no-dupe-args": "error",
69 | "no-dupe-class-members": "error",
70 | "no-dupe-keys": "error",
71 | "no-duplicate-case": "error",
72 | "no-duplicate-imports": "error",
73 | "no-else-return": "error",
74 | "no-eval": "error",
75 | "no-extra-semi": "error",
76 | "no-fallthrough": "error",
77 | "no-lonely-if": "error",
78 | "no-mixed-operators": "error",
79 | "no-mixed-spaces-and-tabs": "error",
80 | "no-multiple-empty-lines": ["error", { "max": 1 }],
81 | "no-multi-spaces": "error",
82 | "no-multi-str": "off",
83 | "no-negated-in-lhs": "error",
84 | "no-nested-ternary": "error",
85 | "no-redeclare": "error",
86 | "no-restricted-syntax": [
87 | "error",
88 | {
89 | "selector":
90 | "ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]",
91 | "message": "Path access on WordPress dependencies is not allowed."
92 | },
93 | {
94 | "selector": "ImportDeclaration[source.value=/^blocks$/]",
95 | "message": "Use @wordpress/blocks as import path instead."
96 | },
97 | {
98 | "selector": "ImportDeclaration[source.value=/^components$/]",
99 | "message": "Use @wordpress/components as import path instead."
100 | },
101 | {
102 | "selector": "ImportDeclaration[source.value=/^date$/]",
103 | "message": "Use @wordpress/date as import path instead."
104 | },
105 | {
106 | "selector": "ImportDeclaration[source.value=/^editor$/]",
107 | "message": "Use @wordpress/editor as import path instead."
108 | },
109 | {
110 | "selector": "ImportDeclaration[source.value=/^element$/]",
111 | "message": "Use @wordpress/element as import path instead."
112 | },
113 | {
114 | "selector": "ImportDeclaration[source.value=/^i18n$/]",
115 | "message": "Use @wordpress/i18n as import path instead."
116 | },
117 | {
118 | "selector": "ImportDeclaration[source.value=/^data$/]",
119 | "message": "Use @wordpress/data as import path instead."
120 | },
121 | {
122 | "selector": "ImportDeclaration[source.value=/^utils$/]",
123 | "message": "Use @wordpress/utils as import path instead."
124 | },
125 | {
126 | "selector":
127 | "CallExpression[callee.name=/^__|_n|_x$/]:not([arguments.0.type=/^Literal|BinaryExpression$/])",
128 | "message": "Translate function arguments must be string literals."
129 | },
130 | {
131 | "selector":
132 | "CallExpression[callee.name=/^_n|_x$/]:not([arguments.1.type=/^Literal|BinaryExpression$/])",
133 | "message": "Translate function arguments must be string literals."
134 | },
135 | {
136 | "selector":
137 | "CallExpression[callee.name=_nx]:not([arguments.2.type=/^Literal|BinaryExpression$/])",
138 | "message": "Translate function arguments must be string literals."
139 | }
140 | ],
141 | "no-shadow": "error",
142 | "no-undef": "error",
143 | "no-undef-init": "error",
144 | "no-unreachable": "error",
145 | "no-unsafe-negation": "error",
146 | "no-unused-expressions": "error",
147 | "no-unused-vars": "error",
148 | "no-useless-computed-key": "error",
149 | "no-useless-constructor": "error",
150 | "no-useless-return": "error",
151 | "no-var": "error",
152 | "no-whitespace-before-property": "error",
153 | "object-curly-spacing": ["error", "always"],
154 | "padded-blocks": ["error", "never"],
155 | "prefer-const": "error",
156 | "quote-props": ["error", "as-needed"],
157 | "react/display-name": "off",
158 | "react/jsx-curly-spacing": [
159 | "error",
160 | {
161 | "when": "always",
162 | "children": true
163 | }
164 | ],
165 | "react/jsx-equals-spacing": "error",
166 | "react/jsx-indent": ["error", "tab"],
167 | "react/jsx-indent-props": ["error", "tab"],
168 | "react/jsx-key": "error",
169 | "react/jsx-tag-spacing": "error",
170 | "react/no-children-prop": "off",
171 | "react/no-find-dom-node": "warn",
172 | "react/prop-types": "off",
173 | "semi": "error",
174 | "semi-spacing": "error",
175 | "space-before-blocks": ["error", "always"],
176 | "space-before-function-paren": ["error", "never"],
177 | "space-in-parens": ["error", "always"],
178 | "space-infix-ops": ["error", { "int32Hint": false }],
179 | "space-unary-ops": [
180 | "error",
181 | {
182 | "overrides": {
183 | "!": true
184 | }
185 | }
186 | ],
187 | "template-curly-spacing": ["error", "always"],
188 | "valid-jsdoc": ["error", { "requireReturn": false }],
189 | "valid-typeof": "error",
190 | "yoda": "off"
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | vendor
3 | .cache/
4 | composer.phar
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Example how to extend an existing Gutenberg block in WordPress
2 |
3 | This is a WordPress plugin which shows how to extend an existing Gutenberg block.
4 | This blog post explains how it works: https://www.liip.ch/en/blog/how-to-extend-existing-gutenberg-blocks-in-wordpress.
5 | Feel free to use this plugin as a starting point to extend Gutenberg blocks in your WordPress site.
6 |
7 | ## Developer information
8 |
9 | ### Installation
10 |
11 | 1. Clone this repository
12 |
13 | 1. Install Node dependencies
14 |
15 | ```
16 | $ npm install
17 | ```
18 |
19 | ### Code style
20 |
21 | Run eslint with the following command:
22 |
23 | ```
24 | $ npm run lint
25 | ```
26 |
27 | ### Compile assets
28 |
29 | #### `npm start`
30 | - Use to compile and run the block in development mode.
31 | - Watches for any changes and reports back any errors in your code.
32 |
33 | #### `npm run build`
34 | - Use to build production code for your block inside `dist` folder.
35 | - Runs once and reports back the gzip file sizes of the produced code.
36 |
--------------------------------------------------------------------------------
/assets/js/extend-block-example.js:
--------------------------------------------------------------------------------
1 | import './spacing-control';
2 |
--------------------------------------------------------------------------------
/assets/js/spacing-control.js:
--------------------------------------------------------------------------------
1 | import assign from 'lodash.assign';
2 |
3 | const { createHigherOrderComponent } = wp.compose;
4 | const { Fragment } = wp.element;
5 | const { InspectorControls } = wp.editor;
6 | const { PanelBody, SelectControl } = wp.components;
7 | const { addFilter } = wp.hooks;
8 | const { __ } = wp.i18n;
9 |
10 | // Enable spacing control on the following blocks
11 | const enableSpacingControlOnBlocks = [
12 | 'core/image',
13 | ];
14 |
15 | // Available spacing control options
16 | const spacingControlOptions = [
17 | {
18 | label: __( 'None' ),
19 | value: '',
20 | },
21 | {
22 | label: __( 'Small' ),
23 | value: 'small',
24 | },
25 | {
26 | label: __( 'Medium' ),
27 | value: 'medium',
28 | },
29 | {
30 | label: __( 'Large' ),
31 | value: 'large',
32 | },
33 | ];
34 |
35 | /**
36 | * Add spacing control attribute to block.
37 | *
38 | * @param {object} settings Current block settings.
39 | * @param {string} name Name of block.
40 | *
41 | * @returns {object} Modified block settings.
42 | */
43 | const addSpacingControlAttribute = ( settings, name ) => {
44 | // Do nothing if it's another block than our defined ones.
45 | if ( ! enableSpacingControlOnBlocks.includes( name ) ) {
46 | return settings;
47 | }
48 |
49 | // Use Lodash's assign to gracefully handle if attributes are undefined
50 | settings.attributes = assign( settings.attributes, {
51 | spacing: {
52 | type: 'string',
53 | default: spacingControlOptions[ 0 ].value,
54 | },
55 | } );
56 |
57 | return settings;
58 | };
59 |
60 | addFilter( 'blocks.registerBlockType', 'extend-block-example/attribute/spacing', addSpacingControlAttribute );
61 |
62 | /**
63 | * Create HOC to add spacing control to inspector controls of block.
64 | */
65 | const withSpacingControl = createHigherOrderComponent( ( BlockEdit ) => {
66 | return ( props ) => {
67 | // Do nothing if it's another block than our defined ones.
68 | if ( ! enableSpacingControlOnBlocks.includes( props.name ) ) {
69 | return (
70 |
71 | );
72 | }
73 |
74 | const { spacing } = props.attributes;
75 |
76 | // add has-spacing-xy class to block
77 | if ( spacing ) {
78 | props.attributes.className = `has-spacing-${ spacing }`;
79 | }
80 |
81 | return (
82 |
83 |
84 |
85 |
89 | {
94 | props.setAttributes( {
95 | spacing: selectedSpacingOption,
96 | } );
97 | } }
98 | />
99 |
100 |
101 |
102 | );
103 | };
104 | }, 'withSpacingControl' );
105 |
106 | addFilter( 'editor.BlockEdit', 'extend-block-example/with-spacing-control', withSpacingControl );
107 |
108 | /**
109 | * Add margin style attribute to save element of block.
110 | *
111 | * @param {object} saveElementProps Props of save element.
112 | * @param {Object} blockType Block type information.
113 | * @param {Object} attributes Attributes of block.
114 | *
115 | * @returns {object} Modified props of save element.
116 | */
117 | const addSpacingExtraProps = ( saveElementProps, blockType, attributes ) => {
118 | // Do nothing if it's another block than our defined ones.
119 | if ( ! enableSpacingControlOnBlocks.includes( blockType.name ) ) {
120 | return saveElementProps;
121 | }
122 |
123 | const margins = {
124 | small: '5px',
125 | medium: '15px',
126 | large: '30px',
127 | };
128 |
129 | if ( attributes.spacing in margins ) {
130 | // Use Lodash's assign to gracefully handle if attributes are undefined
131 | assign( saveElementProps, { style: { 'margin-bottom': margins[ attributes.spacing ] } } );
132 | }
133 |
134 | return saveElementProps;
135 | };
136 |
137 | addFilter( 'blocks.getSaveContent.extraProps', 'extend-block-example/get-save-content/extra-props', addSpacingExtraProps );
138 |
--------------------------------------------------------------------------------
/dist/extend-block-example.js:
--------------------------------------------------------------------------------
1 | parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c1?t[u-1]:void 0,c=u>2?t[2]:void 0;for(o=n.length>3&&"function"==typeof o?(u--,o):void 0,c&&A(t[0],t[1],c)&&(o=u<3?void 0:o,u=1),r=Object(r);++e-1&&r%1==0&&r-1&&r%1==0&&r<=n}function M(n){var r=typeof n;return!!n&&("object"==r||"function"==r)}function P(n){return!!n&&"object"==typeof n}var $=O(function(n,r){if(y||w(r)||k(r))j(r,q(r),n);else for(var t in r)l.call(r,t)&&g(n,t,r[t])});function q(n){return k(n)?h(n):b(n)}module.exports=$;
3 | },{}],"0/j4":[function(require,module,exports) {
4 | "use strict";var e=t(require("lodash.assign"));function t(e){return e&&e.__esModule?e:{default:e}}var a=wp.compose.createHigherOrderComponent,n=wp.element.Fragment,l=wp.editor.InspectorControls,r=wp.components,i=r.PanelBody,c=r.SelectControl,o=wp.hooks.addFilter,s=wp.i18n.__,u=["core/image"],p=[{label:s("None"),value:""},{label:s("Small"),value:"small"},{label:s("Medium"),value:"medium"},{label:s("Large"),value:"large"}],m=function(t,a){return u.includes(a)?(t.attributes=(0,e.default)(t.attributes,{spacing:{type:"string",default:p[0].value}}),t):t};o("blocks.registerBlockType","extend-block-example/attribute/spacing",m);var g=a(function(e){return function(t){if(!u.includes(t.name))return React.createElement(e,t);var a=t.attributes.spacing;return a&&(t.attributes.className="has-spacing-".concat(a)),React.createElement(n,null,React.createElement(e,t),React.createElement(l,null,React.createElement(i,{title:s("My Spacing Control"),initialOpen:!0},React.createElement(c,{label:s("Spacing"),value:a,options:p,onChange:function(e){t.setAttributes({spacing:e})}}))))}},"withSpacingControl");o("editor.BlockEdit","extend-block-example/with-spacing-control",g);var d=function(t,a,n){if(!u.includes(a.name))return t;var l={small:"5px",medium:"15px",large:"30px"};return n.spacing in l&&(0,e.default)(t,{style:{"margin-bottom":l[n.spacing]}}),t};o("blocks.getSaveContent.extraProps","extend-block-example/get-save-content/extra-props",d);
5 | },{"lodash.assign":"9bLa"}],"KQUp":[function(require,module,exports) {
6 | "use strict";require("./spacing-control");
7 | },{"./spacing-control":"0/j4"}]},{},["KQUp"], null)
8 | //# sourceMappingURL=/extend-block-example.js.map
--------------------------------------------------------------------------------
/dist/extend-block-example.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../../node_modules/lodash.assign/index.js","spacing-control.js","extend-block-example.js"],"names":["createHigherOrderComponent","wp","compose","Fragment","element","InspectorControls","editor","components","PanelBody","SelectControl","addFilter","hooks","__","i18n","enableSpacingControlOnBlocks","spacingControlOptions","label","value","addSpacingControlAttribute","settings","name","includes","attributes","spacing","type","default","withSpacingControl","BlockEdit","props","className","selectedSpacingOption","setAttributes","addSpacingExtraProps","saveElementProps","blockType","margins","small","medium","large","style"],"mappings":"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","file":"extend-block-example.js","sourceRoot":"../assets/js","sourcesContent":["/**\n * lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]';\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object),\n nativeMax = Math.max;\n\n/** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */\nvar nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf');\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n // Safari 9 makes `arguments.length` enumerable in strict mode.\n var result = (isArray(value) || isArguments(value))\n ? baseTimes(value.length, String)\n : [];\n\n var length = result.length,\n skipIndexes = !!length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (key == 'length' || isIndex(key, length)))) {\n result.push(key);\n }\n }\n return result;\n}\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n object[key] = value;\n }\n}\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\n/**\n * The base implementation of `_.rest` which doesn't validate or coerce arguments.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @returns {Function} Returns the new function.\n */\nfunction baseRest(func, start) {\n start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n return function() {\n var args = arguments,\n index = -1,\n length = nativeMax(args.length - start, 0),\n array = Array(length);\n\n while (++index < length) {\n array[index] = args[start + index];\n }\n index = -1;\n var otherArgs = Array(start + 1);\n while (++index < start) {\n otherArgs[index] = args[index];\n }\n otherArgs[start] = array;\n return apply(func, this, otherArgs);\n };\n}\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n object || (object = {});\n\n var index = -1,\n length = props.length;\n\n while (++index < length) {\n var key = props[index];\n\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n\n assignValue(object, key, newValue === undefined ? source[key] : newValue);\n }\n return object;\n}\n\n/**\n * Creates a function like `_.assign`.\n *\n * @private\n * @param {Function} assigner The function to assign values.\n * @returns {Function} Returns the new assigner function.\n */\nfunction createAssigner(assigner) {\n return baseRest(function(object, sources) {\n var index = -1,\n length = sources.length,\n customizer = length > 1 ? sources[length - 1] : undefined,\n guard = length > 2 ? sources[2] : undefined;\n\n customizer = (assigner.length > 3 && typeof customizer == 'function')\n ? (length--, customizer)\n : undefined;\n\n if (guard && isIterateeCall(sources[0], sources[1], guard)) {\n customizer = length < 3 ? undefined : customizer;\n length = 1;\n }\n object = Object(object);\n while (++index < length) {\n var source = sources[index];\n if (source) {\n assigner(object, source, index, customizer);\n }\n }\n return object;\n });\n}\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n length = length == null ? MAX_SAFE_INTEGER : length;\n return !!length &&\n (typeof value == 'number' || reIsUint.test(value)) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\n/**\n * Checks if the given arguments are from an iteratee call.\n *\n * @private\n * @param {*} value The potential iteratee value argument.\n * @param {*} index The potential iteratee index or key argument.\n * @param {*} object The potential iteratee object argument.\n * @returns {boolean} Returns `true` if the arguments are from an iteratee call,\n * else `false`.\n */\nfunction isIterateeCall(value, index, object) {\n if (!isObject(object)) {\n return false;\n }\n var type = typeof index;\n if (type == 'number'\n ? (isArrayLike(object) && isIndex(index, object.length))\n : (type == 'string' && index in object)\n ) {\n return eq(object[index], value);\n }\n return false;\n}\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nfunction isArguments(value) {\n // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&\n (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);\n}\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n * else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n return isObjectLike(value) && isArrayLike(value);\n}\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 8-9 which returns 'object' for typed array and other constructors.\n var tag = isObject(value) ? objectToString.call(value) : '';\n return tag == funcTag || tag == genTag;\n}\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n\n/**\n * Assigns own enumerable string keyed properties of source objects to the\n * destination object. Source objects are applied from left to right.\n * Subsequent sources overwrite property assignments of previous sources.\n *\n * **Note:** This method mutates `object` and is loosely based on\n * [`Object.assign`](https://mdn.io/Object/assign).\n *\n * @static\n * @memberOf _\n * @since 0.10.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.assignIn\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * function Bar() {\n * this.c = 3;\n * }\n *\n * Foo.prototype.b = 2;\n * Bar.prototype.d = 4;\n *\n * _.assign({ 'a': 0 }, new Foo, new Bar);\n * // => { 'a': 1, 'c': 3 }\n */\nvar assign = createAssigner(function(object, source) {\n if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {\n copyObject(source, keys(source), object);\n return;\n }\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n assignValue(object, key, source[key]);\n }\n }\n});\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nmodule.exports = assign;\n","import assign from 'lodash.assign';\n\nconst { createHigherOrderComponent } = wp.compose;\nconst { Fragment } = wp.element;\nconst { InspectorControls } = wp.editor;\nconst { PanelBody, SelectControl } = wp.components;\nconst { addFilter } = wp.hooks;\nconst { __ } = wp.i18n;\n\n// Enable spacing control on the following blocks\nconst enableSpacingControlOnBlocks = [\n\t'core/image',\n];\n\n// Available spacing control options\nconst spacingControlOptions = [\n\t{\n\t\tlabel: __( 'None' ),\n\t\tvalue: '',\n\t},\n\t{\n\t\tlabel: __( 'Small' ),\n\t\tvalue: 'small',\n\t},\n\t{\n\t\tlabel: __( 'Medium' ),\n\t\tvalue: 'medium',\n\t},\n\t{\n\t\tlabel: __( 'Large' ),\n\t\tvalue: 'large',\n\t},\n];\n\n/**\n * Add spacing control attribute to block.\n *\n * @param {object} settings Current block settings.\n * @param {string} name Name of block.\n *\n * @returns {object} Modified block settings.\n */\nconst addSpacingControlAttribute = ( settings, name ) => {\n\t// Do nothing if it's another block than our defined ones.\n\tif ( ! enableSpacingControlOnBlocks.includes( name ) ) {\n\t\treturn settings;\n\t}\n\n\t// Use Lodash's assign to gracefully handle if attributes are undefined\n\tsettings.attributes = assign( settings.attributes, {\n\t\tspacing: {\n\t\t\ttype: 'string',\n\t\t\tdefault: spacingControlOptions[ 0 ].value,\n\t\t},\n\t} );\n\n\treturn settings;\n};\n\naddFilter( 'blocks.registerBlockType', 'extend-block-example/attribute/spacing', addSpacingControlAttribute );\n\n/**\n * Create HOC to add spacing control to inspector controls of block.\n */\nconst withSpacingControl = createHigherOrderComponent( ( BlockEdit ) => {\n\treturn ( props ) => {\n\t\t// Do nothing if it's another block than our defined ones.\n\t\tif ( ! enableSpacingControlOnBlocks.includes( props.name ) ) {\n\t\t\treturn (\n\t\t\t\t\n\t\t\t);\n\t\t}\n\n\t\tconst { spacing } = props.attributes;\n\n\t\t// add has-spacing-xy class to block\n\t\tif ( spacing ) {\n\t\t\tprops.attributes.className = `has-spacing-${ spacing }`;\n\t\t}\n\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tprops.setAttributes( {\n\t\t\t\t\t\t\t\t\tspacing: selectedSpacingOption,\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t/>\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t);\n\t};\n}, 'withSpacingControl' );\n\naddFilter( 'editor.BlockEdit', 'extend-block-example/with-spacing-control', withSpacingControl );\n\n/**\n * Add margin style attribute to save element of block.\n *\n * @param {object} saveElementProps Props of save element.\n * @param {Object} blockType Block type information.\n * @param {Object} attributes Attributes of block.\n *\n * @returns {object} Modified props of save element.\n */\nconst addSpacingExtraProps = ( saveElementProps, blockType, attributes ) => {\n\t// Do nothing if it's another block than our defined ones.\n\tif ( ! enableSpacingControlOnBlocks.includes( blockType.name ) ) {\n\t\treturn saveElementProps;\n\t}\n\n\tconst margins = {\n\t\tsmall: '5px',\n\t\tmedium: '15px',\n\t\tlarge: '30px',\n\t};\n\n\tif ( attributes.spacing in margins ) {\n\t\t// Use Lodash's assign to gracefully handle if attributes are undefined\n\t\tassign( saveElementProps, { style: { 'margin-bottom': margins[ attributes.spacing ] } } );\n\t}\n\n\treturn saveElementProps;\n};\n\naddFilter( 'blocks.getSaveContent.extraProps', 'extend-block-example/get-save-content/extra-props', addSpacingExtraProps );\n","import './spacing-control';\n"]}
--------------------------------------------------------------------------------
/extend-block-example.php:
--------------------------------------------------------------------------------
1 |