Skip to content

Instantly share code, notes, and snippets.

@zutigrm
Last active September 1, 2019 14:46
Show Gist options
  • Save zutigrm/5264810d3f0be8789e5efaf16ab26891 to your computer and use it in GitHub Desktop.
Save zutigrm/5264810d3f0be8789e5efaf16ab26891 to your computer and use it in GitHub Desktop.
<?php
/*
Plugin Name: User Info Box
Plugin URI: https://messyarray.com
Description: Very cool plugin for displaying user information using Gutemberg block.
Version: 1.0.0
Author: Aleksej Vukomanovic
Author URI: https://messyarray.com
License: GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: messyarray
Domain Path: /languages
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Save function will handle the client side rendering
* This is the code (HTML markup) which will be saved into the_content
* once post is saved
*/
save: props => {
const {attributes} = props;
if ( typeof attributes.id === 'string' && attributes.id.search('user-') !== -1 ) {
// if we have prefixed id it means we already have saved user
// and this is new block insert, we need to filter id
attributes.id = attributes.id.replace('user-', '');
}
return(
<UserBox data={attributes} />
)
}
<p>{__('User Box Background Color')}</p>
<ColorPicker
color={ color }
width={ 100 }
onChangeComplete={ ( value ) => {
setState( {color: value.rgb } );
// since we will use rgba mode, format the color
// you can use hex if you want. Just use value.hex, no formating needed
const rgb = value.rgb
const result = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`;
// pass selected color to the callback function
setAttributes( {boxBg: result} );
}}
/>
<?php
/*
Plugin Name: User Info Box
Plugin URI: https://no-domain-yet.com
Description: Very cool plugin for displaying user information using Gutemberg block.
Version: 1.0.0
Author: Aleksej Vukomanovic
Author URI: https://messyarray.com
License: GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: messyarray
Domain Path: /languages
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// define path to our build folder
define( 'UIB_BLOCK_BUILD', plugin_dir_url(__FILE__) . 'build/' );
// define path to our src folder where we will keep styles
define( 'UIB_BLOCK', plugin_dir_url(__FILE__) . 'src/' );
// Enqueue Gutenberg block assets for both frontend + backend.
add_action( 'enqueue_block_assets', 'uib_block_assets' );
/**
* callback function for registeing our block style
* in both Gutemberg editor and frontend
*
* @return void
*/
function uib_block_assets() {
// include css style which will be used on both block preview
// inside Gutemberg block Editor and on the frontend
// we will create this file later in src/style.css
wp_enqueue_style( 'uib-style-css', UIB_BLOCK . 'style.css', array(), '1.0.0' );
}
// Enqueue Gutenberg block assets for backend editor.
add_action( 'enqueue_block_editor_assets', 'uib_editor_assets' );
/**
* Callback function for registering our block with Gutemberg
*
* @return void
*/
function uib_editor_assets() {
// Scripts.
wp_enqueue_script(
'uib-block-js',
UIB_BLOCK_BUILD . 'index.js',
array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ),
'1.0.0',
true
);
}
import React from 'react'; // import react object
const __ = wp.i18n.__; // The __() for internationalization.
const registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
/**
* Register: a Gutenberg Block.
*
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made editor as an option to any
* editor interface where blocks are implemented.
*
* @link https://wordpress.org/gutenberg/handbook/block-api/
* @param {string} name Block name.
* @param {Object} settings Block settings.
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
registerBlockType("uib/user-info-block", {
title: __("User Info Box"), // Our block title
icon: "businessman",
category: "common", // pick a category from core provided ones or create a custom one
keywords: [__("User"), __("User Info")],
attributes: {
// we will go over attributes later
},
/**
* Edit function will render our block code
* inside the Gutemberg editor once inserted
*/
edit: props => {
},
/**
* Save function will handle the client side rendering
* This is the code (html markup) which will be saved into the_content
* once post is saved
*/
save: props => {
}
});
import React from 'react'; // import react object
const __ = wp.i18n.__; // The __() for internationalization.
const registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
/**
* Register: a Gutenberg Block.
*
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made editor as an option to any
* editor interface where blocks are implemented.
*
* @link https://wordpress.org/gutenberg/handbook/block-api/
* @param {string} name Block name.
* @param {Object} settings Block settings.
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
registerBlockType("uib/user-info-block", {
title: __("User Info Box"), // Our block title
icon: "businessman",
category: "common", // pick a category from core provided ones or create a custom one
keywords: [__("User"), __("User Info")],
// attributes start here
attributes: {
id: {
source: "attribute",
selector: ".uib-wrapper",
attribute: "id"
},
avatar: {
source: "attribute",
selector: "img",
attribute: "src"
},
name: {
source: "text",
selector: ".uib-user-name",
},
desc: {
source: "text",
selector: ".uib-desc",
},
},
// attributes end here
/**
* Edit function will render our block code
* inside the Gutemberg editor once inserted
*/
edit: props => {
},
/**
* Save function will handle the client side rendering
* This is the code (html markup) which will be saved into the_content
* once post is saved
*/
save: props => {
}
});
import React from 'react';
import { SelectControl } from '@wordpress/components';
import { withState } from '@wordpress/compose';
// Fragment will be used as wrapper if we do not want to include markup, like div, etc
const {Fragment} = wp.element;
// InspectorControls will be used to wrap Panel body component
// we need this two wrapper component if we want to display our settings
// in the right panel (where we have document and block tabs, next to the content)
const { InspectorControls } = wp.editor;
const { PanelBody } = wp.components;
const Users = ( {userId, existingUser, data, userSelect, setState } ) => {
const __ = wp.i18n.__; // The __() for internationalization.
// if we already have block saved, use the saved userId
if ( existingUser ) userId = existingUser;
// loop through users and assign label and value
// for options. If users are not loaded yet show
// Loading users message
const options = data.length ? data.map(user => {
return {
label: user.name,
value: user.id
}
}) : [{label: __('Loading users'), value: ''}];
return(
<Fragment>
<InspectorControls>
<PanelBody title={ __( 'User' ) }>
<SelectControl
label={__('Select User')}
value={userId}
// add first empty option and pass the options array using spread operator
options={[{label: '', value: ''}, ...options]}
onChange={( userId ) => {
// pass user id to parent component (edit function)
userSelect(userId);
// set state - change the value for select box
setState({userId: userId}); // wp-script do not include property shorthand (userId)
}}
/>
</PanelBody>
</InspectorControls>
</Fragment>
);
}
// wrap the component with withState so we can manipulate the state
// by using natively supported WordPress functions
export default withState( {
userId: ''
} )(Users);
import React from 'react';
const __ = wp.i18n.__; // The __() for internationalization.
const UserBox = ({data}) => {
// extract the properties we will use from user data
const {id, name, avatar, desc} = data;
// if we do not have user selected, show the message and prevent
// code from further rendering
if ( !id ) return __('No user selected');
return(
<div className="uib-wrapper" id={'user-' + id}>
<figure>
<img
src={avatar}
width={96}
height={96}
alt={name + ' avatar'} />
</figure>
<div className="uib-content">
<h4 className="uib-name">{name}</h4>
<p className="uib-desc">{desc}</p>
</div>
</div>
);
}
export default UserBox;
import React from 'react';
import { withState } from '@wordpress/compose';
import apiFetch from '@wordpress/api-fetch';
// import our Users component which handles the users dropdown
import Users from './users';
import UserBox from './user-box';
const __ = wp.i18n.__; // The __() for internationalization.
const registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
const {Fragment} = wp.element; // Wrapper we can use instead of adding markup, like div, etc
/**
* Register: a Gutenberg Block.
*
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made editor as an option to any
* editor interface where blocks are implemented.
*
* @link https://wordpress.org/gutenberg/handbook/block-api/
* @param {string} name Block name.
* @param {Object} settings Block settings.
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
registerBlockType("uib/user-info-block", {
title: __("User Info Box"), // Our block title
icon: "businessman",
category: "common", // pick a category from core provided ones or create a custom one
keywords: [__("User"), __("User Info")],
// attributes start here
attributes: {
id: {
source: "attribute",
selector: ".uib-wrapper",
attribute: "id"
},
avatar: {
source: "attribute",
selector: "img",
attribute: "src"
},
name: {
source: "text",
selector: ".uib-name",
},
desc: {
source: "text",
selector: ".uib-desc",
},
},
// attributes end here
/**
* Edit function will render our block code
* inside the Gutemberg editor once inserted
*/
edit: withState( {users: []} )( ( {users, setState, attributes, setAttributes} ) => {
// make sure to check if users are still empty before calling
// fetch and updating state. If we do not include this
// conditional our state will be updated over and over again.
if ( ! users.length ) {
// users data fetched from WP Rest Api
// resposne will be passed to a setState hook
// which will update state of users constant
// use apiFetch to get user data from WP Rest api
apiFetch( { path: '/wp/v2/users' } )
.then( response => {
// setState is pre defined is available if we wrap
// component with withState
setState({users: response});
} );
}
// this is the callback function which will be
// passed as prop to Users component
// it will be used as callback for onChange event
// inside the select box
const setUserData = (userId) => {
const user = users.find(u => u.id == userId);
if ( userId ) {
// setAttributes is provided for us by WordPress package
// it will update attributes property. Make sure to allways
// use this function, do Not update attributes directly like props.attributes.x = y
setAttributes({
id: user.id,
name: user.name,
avatar: user.avatar_urls[96],
desc: user.description
})
}
}
if ( typeof attributes.id === 'string' && attributes.id.search('user-') !== -1 ) {
// if we have prefixed id it means we already have saved user
// and this is new block insert, we need to filter id
attributes.id = attributes.id.replace('user-', '');
}
return(
<Fragment>
<Users data={users} existingUser={attributes.id} userSelect={setUserData} />
<UserBox data={attributes} />
</Fragment>
)
}),
/**
* Save function will handle the client side rendering
* This is the code (html markup) which will be saved into the_content
* once post is saved
*/
save: props => {
}
});
<?php
/**
* callback function for registering our block style
* in both Gutemberg editor and frontend
*
* @return void
*/
function uib_block_assets() {
// include css style which will be used on both block preview
// inside Gutemberg block Editor and on the frontend
wp_enqueue_style( 'uib-style-css', UIB_BLOCK . 'style.css', array(), '1.0.0' );
}
.uib-wrapper {
display: flex;
align-items: center;
justify-content: left;
padding: 20px;
border-radius: 5px;
background: #f7f7f7
}
.uib-wrapper figure {
padding: 15px;
margin-right: 15px;
border-radius: 5px;
background: #eee;
overflow: hidden;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment