├── .gitignore ├── README.md ├── build ├── index.deps.json └── index.js ├── custom-functions.php ├── index.php ├── package-lock.json ├── package.json └── src ├── editor.css ├── index.js └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | .phpintel 2 | .idea/ 3 | *.log 4 | npm-debug.log 5 | node_modules 6 | .DS_Store 7 | **/.DS_Store 8 | *.map 9 | Thumbs.db 10 | main.deps.json 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | This plugin adds a custom Gutenberg blocks in the Gutenberg editor of your WordPress dashboard. 4 | 5 | ## Installation :wrench: 6 | 7 | 1. Download the zipped plugin. Unzip the plugin. 8 | 2. Navigate to the __Plugins > Add new__ screen in your WordPress administrative dashboard. 9 | 3. Click __Add New__ at the top of the page. 10 | 3. Click __Upload Plugin__ at the top of the page. 11 | 4. Click __Choose File__, then find and __Upload__ the downloaded renamed zip file. 12 | 5. After the plugin finishes installing, click __Activate__. 13 | 14 | or, 15 | Go to your plugin directory from terminal and Clone this repo in wp-content/plugins directory `git clone https://github.com/imranhsayed/custom-blocks` 16 | And then activate it from __Plugins__ screen in your WordPress administrative dashboard. 17 | 6. That's it! 18 | 19 | ## Configuration ( @wordpress/scripts ) 20 | 21 | - This plugin uses [@wordpress/scripts](https://developer.wordpress.org/block-editor/packages/packages-scripts/) which installs and sets up webpack and babel config out of the box 22 | - The `@wordpress/scripts` is installed in the root of the project. This is one single plugin that registers many blocks. 23 | - By default `@wordpress/package` uses `src/index.js` as entry point and `build/index.js` 24 | 25 | ## Directory Structure 26 | 27 | ```ruby 28 | ├── build 29 | │ └── index.js 30 | ├── node_modules 31 | ├── package-lock.json 32 | ├── package.json 33 | └── src 34 | ├── editor.css 35 | ├── index.js 36 | └── style.css 37 | ├── custom-functions.php 38 | ├── index.php 39 | ``` 40 | 41 | ## Scripts 42 | 43 | 1. `npm run start` : will use the `src/index.js` as entry point and output it to `build/index.js` for development 44 | 2. `npm run build` : will use the `src/index.js` as entry point and output it to `build/index.js` for production 45 | 46 | ## What is included in this plugin ? 47 | 48 | - The plugin uses ReactJS & ESNext for creating custom gutenberg block, along with PHP 49 | - It uses Webpack to bundle all of its dependencies into one file index.js 50 | - Has separate stylesheet for front-end & editor. 51 | 52 | ## Useful Blogs: 53 | 54 | 1. [Create Gutenberg Block in 3 Steps](https://medium.com/@imranhsayed/create-gutenberg-block-in-3-steps-924828a2ff83) 55 | 2. [Custom Gutenberg Block with ES6](https://medium.com/@imranhsayed/custom-gutenberg-block-using-es6-webpack-babel-wordpress-scripts-7d6f185d9eb6) 56 | 3. [Attributes & Components](https://medium.com/@imranhsayed/attributes-and-components-in-gutenberg-blocks-richtext-blockcontrols-alignmenttoolbar-230910fcbd4a) 57 | 58 | ## Gutenberg Handbook 59 | 60 | 1. [Gutenberg Handbook](https://developer.wordpress.org/block-editor/) 61 | 62 | ## Gutenberg Tutorials 63 | 64 | 1. [Introduction to Gutenberg](https://youtu.be/U4sfx7vN0Iw) 65 | 2. [Create Gutenberg Block in 3 Steps](https://youtu.be/AQ10IGN2lt8) 66 | 3. [Custom Gutenberg Block using @wordpress/scripts](https://youtu.be/Pfp7mCXnhhw) 67 | 4. [@wordpress/scripts package features](https://youtu.be/wihGO8yR3Q8) 68 | 5. [Attributes and Components | State ](https://youtu.be/aH0u5NBDAeg) 69 | 70 | ## Gutenberg Talks 71 | 72 | 1. [WordCamp Pune: Introduction to Gutenberg](https://wordpress.tv/2019/06/25/imran-sayed-introduction-to-gutenberg/) 73 | 74 | ## How to use ? 75 | 76 | - Go to WordPress Dashboard > Posts/Pages > Add New > Add block ( + icon ) > Common 77 | -------------------------------------------------------------------------------- /build/index.deps.json: -------------------------------------------------------------------------------- 1 | ["wp-element","wp-polyfill"] -------------------------------------------------------------------------------- /build/index.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { 40 | /******/ configurable: false, 41 | /******/ enumerable: true, 42 | /******/ get: getter 43 | /******/ }); 44 | /******/ } 45 | /******/ }; 46 | /******/ 47 | /******/ // define __esModule on exports 48 | /******/ __webpack_require__.r = function(exports) { 49 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 50 | /******/ }; 51 | /******/ 52 | /******/ // getDefaultExport function for compatibility with non-harmony modules 53 | /******/ __webpack_require__.n = function(module) { 54 | /******/ var getter = module && module.__esModule ? 55 | /******/ function getDefault() { return module['default']; } : 56 | /******/ function getModuleExports() { return module; }; 57 | /******/ __webpack_require__.d(getter, 'a', getter); 58 | /******/ return getter; 59 | /******/ }; 60 | /******/ 61 | /******/ // Object.prototype.hasOwnProperty.call 62 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 63 | /******/ 64 | /******/ // __webpack_public_path__ 65 | /******/ __webpack_require__.p = ""; 66 | /******/ 67 | /******/ 68 | /******/ // Load entry module and return exports 69 | /******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); 70 | /******/ }) 71 | /************************************************************************/ 72 | /******/ ({ 73 | 74 | /***/ "./src/index.js": 75 | /*!**********************!*\ 76 | !*** ./src/index.js ***! 77 | \**********************/ 78 | /*! no exports provided */ 79 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 80 | 81 | "use strict"; 82 | __webpack_require__.r(__webpack_exports__); 83 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); 84 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__); 85 | 86 | var __ = wp.i18n.__; 87 | var registerBlockType = wp.blocks.registerBlockType; 88 | var RichText = wp.editor.RichText; 89 | registerBlockType('gtcb-blocks/custom-block', { 90 | title: __('Custom Block', 'custom-blocks'), 91 | icon: 'megaphone', 92 | category: 'common', 93 | attributes: { 94 | fullName: { 95 | type: 'array', 96 | source: 'children', 97 | selector: 'div' 98 | } 99 | }, 100 | edit: function edit(props) { 101 | console.warn('props.attributes.fullName', props.attributes.fullName); 102 | var fullName = props.attributes.fullName, 103 | setAttributes = props.setAttributes, 104 | className = props.className; 105 | return Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])(RichText, { 106 | tagName: "div", 107 | placeholder: __('Full Name', 'custom-blocks'), 108 | value: fullName, 109 | onChange: function onChange(value) { 110 | return setAttributes({ 111 | fullName: value 112 | }); 113 | }, 114 | className: className 115 | }); 116 | }, 117 | save: function save(props) { 118 | console.warn('save', props); 119 | var fullName = props.attributes.fullName, 120 | className = props.className; 121 | return Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])(RichText.Content, { 122 | tagName: "div", 123 | value: fullName, 124 | className: className 125 | }); 126 | } 127 | }); 128 | 129 | /***/ }), 130 | 131 | /***/ "@wordpress/element": 132 | /*!******************************************!*\ 133 | !*** external {"this":["wp","element"]} ***! 134 | \******************************************/ 135 | /*! no static exports found */ 136 | /***/ (function(module, exports) { 137 | 138 | (function() { module.exports = this["wp"]["element"]; }()); 139 | 140 | /***/ }) 141 | 142 | /******/ }); 143 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /custom-functions.php: -------------------------------------------------------------------------------- 1 | 'gtcb-block-front-end-styles', 37 | 'editor_style' => 'gtcb-block-editor-styles', 38 | 'editor_script' => 'gtcb-block-editor-js', 39 | ) 40 | ); 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | { 20 | console.warn( 'props.attributes.fullName', props.attributes.fullName ); 21 | let { attributes: { fullName } , setAttributes, className } = props; 22 | return ( 23 | setAttributes( { fullName: value } ) } 28 | className={ className } 29 | /> 30 | ) 31 | }, 32 | save: ( props ) => { 33 | console.warn( 'save', props ); 34 | let { attributes: { fullName }, className } = props; 35 | return ( 36 | 41 | ) 42 | } 43 | 44 | } ); 45 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imranhsayed/custom-blocks/3a05cff531978a8458e8bf1dccfffce5e672f19c/src/style.css --------------------------------------------------------------------------------