Skip to content

Instantly share code, notes, and snippets.

@pdclark
Last active Aug 3, 2021
Embed
What would you like to do?
Gutenberg block to wrap the `[pods]` shortcode.
<?php
/**
* Plugin Name: Pods — Block
* Description: Gutenberg block to wrap the `[pods]` shortcode.
* Author: Paul Clark
* Author URI: https://pdclark.com
* Plugin URI: https://pd.cm/pods-block
* Version: 28
*
* @package pd
*/
// See post_type attribute below.
foreach( get_post_types() as $post_type ) {
$pd_pods_post_type_options[] = [
'label' => $post_type,
'value' => $post_type,
];
}
new PD_Block( [
'slug_hyphen' => 'pods-magic-tags',
'slug_slash' => 'pods/magic-tags',
'title' => __( 'Pods — Magic Tags', 'pd' ),
'icon' => 'image-rotate', // https://developer.wordpress.org/resource/dashicons/
'category' => 'widgets',
'render_callback' => function( $a /* attributes */, $c /* content */, $o /* PD_Block instance */ ) {
echo apply_shortcodes(
'[pods '
. ' limit="' . $a['limit'] . '" '
. ' id="' . $a['id'] . '" '
. ' slug="' . $a['slug'] . '" '
. ' where="' . $a['where'] . '" '
. ' name="' . $a['post_type'] . '"]'
. $a['textarea']
. '[/pods]'
);
},
'attributes' => [
'post_type' => [
'type' => 'string',
'component' => 'wp.components.SelectControl',
'default' => 'post',
'label' => __( 'Post Type', 'pd' ),
'options' => $pd_pods_post_type_options, // see foreach above.
],
'limit' => [
'type' => 'number',
'component' => 'wp.components.RangeControl',
'default' => 3,
'label' => __( 'Limit', 'pd' ),
'min' => -1,
'max' => 200,
],
'where' => [
'type' => 'string',
'component' => 'wp.components.TextControl',
'default' => '',
'label' => 'Where',
'input_type' => 'text', // text, number, email, or url.
],
'id' => [
'type' => 'string',
'component' => 'wp.components.TextControl',
'default' => '',
'label' => 'ID',
'input_type' => 'number', // text, number, email, or url.
],
'slug' => [
'type' => 'string',
'component' => 'wp.components.TextControl',
'default' => '',
'label' => 'Slug',
'input_type' => 'text', // text, number, email, or url.
],
'textarea' => [
'type' => 'string',
'component' => 'wp.components.TextareaControl',
'label' => __( 'HTML / Magic Tags', 'pd' ),
'rows' => 7,
],
],
] );
/**
* PD_Block class.
* Allows instantiation of PHP-powered blocks with some attributes.
*
* @author Paul Clark <pd@pd.cm>
*/
class PD_Block {
/**
* Assign all keys in input array to class vars.
* Register block in PHP on init.
* Register block in JavaScript with wp_ajax_register_block
* Filters for attributes & inspector controls.
*
* @param array $atts Block configuration. See examples above.
*/
public function __construct( $atts ) {
foreach( $atts as $key => $att ) {
$this->$key = $att;
}
add_action( 'init', [ $this, 'init' ] );
add_action( 'wp_ajax_register_block_' . $this->slug_hyphen, [ $this, 'wp_ajax_register_block' ] );
add_filter( 'pd/block/attributes-php/' . $this->slug_hyphen, [ $this, 'block_attributes_php' ] );
add_filter( 'pd/block/attributes-js/' . $this->slug_hyphen, [ $this, 'block_attributes_js' ] );
add_filter( 'pd/block/inspector-controls-js/' . $this->slug_hyphen, [ $this, 'block_inspector_controls_js' ] );
}
/**
* Register: PHP.
*/
public function init() {
wp_register_script(
$this->slug_hyphen,
add_query_arg(
[
'action' => 'register_block_' . $this->slug_hyphen,
'_wpnonce' => wp_create_nonce(),
],
admin_url( 'admin-ajax.php' ) ),
[ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ],
microtime(),
true
);
$block_params = [
'editor_script' => $this->slug_hyphen,
/**
* @param array $attributes Optional. Block attributes. Default empty array.
* @param string $content Optional. Block content. Default empty string.
*/
'render_callback' => function( $attributes, $content ) {
ob_start();
call_user_func( $this->render_callback, $attributes, $content, $this );
return ob_get_clean();
},
];
$attributes = apply_filters( 'pd/block/attributes-php/' . $this->slug_hyphen, [] );
if ( ! empty( $attributes ) ) {
$block_params['attributes'] = $attributes;
}
register_block_type( $this->slug_slash, $block_params );
}
/**
* Register: JavaScript.
* Outputs ES2015.
* Calls wp.blocks.registerBlockType.
* Builds attributes and InspectorControls components.
*
* @see https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/
*/
public function wp_ajax_register_block() {
check_ajax_referer();
header( 'Content-Type: text/javascript' );
?>
( function ( el ) {
wp.blocks.registerBlockType( '<?php echo esc_js( $this->slug_slash ); ?>', {
apiVersion: 2,
title: '<?php echo esc_js( $this->title ); ?>',
icon: '<?php echo esc_js( $this->icon ); ?>',
category: '<?php echo esc_js( $this->category ); ?>',
attributes: <?php
echo wp_json_encode(
apply_filters( 'pd/block/attributes-js/' . $this->slug_hyphen, [] ),
JSON_FORCE_OBJECT
);
?>,
edit: function ( props ) {
return [
el(
'div',
{ ...wp.blockEditor.useBlockProps(), 'key': 'block_wrapper' },
el(
wp.serverSideRender,
{
key: 'server_side_render',
block: '<?php echo esc_js( $this->slug_slash ); ?>',
attributes: props.attributes,
}
)
)
<?php
$inspector_controls = apply_filters( 'pd/block/inspector-controls-js/' . $this->slug_hyphen, [] );
if ( ! empty( $inspector_controls ) ) :
?>
, el(
wp.blockEditor.InspectorControls,
{ key: "inspector" },
el(
wp.components.PanelBody,
{ title: "Settings", initialOpen: true },
<?php echo implode( ',', $inspector_controls ); ?>
)
)
<?php
endif;
?>
];
},
} );
} )( wp.element.createElement );
<?php
exit;
}
/**
* Outputs PHP attribute configuration for register_block_type().
*
* Array of attribute types and default values.
* See filter pd/block/attributes-php/
*/
public function block_attributes_php( $attributes = array() ) {
foreach ( (array) $this->attributes as $key => $values ) {
$attributes[ $key ] = [
'type' => $values['type'],
'default' => $values['default'],
];
if ( isset( $values['source'] ) ) {
$attributes[$key] = $values['source'];
}
}
return $attributes;
}
/**
* Outputs JavaScript attribute configuration.
*
* Array of attribute default values to be JSON encoded.
* See filter pd/block/attributes-js/
*/
public function block_attributes_js( $attributes = array() ) {
foreach ( (array) $this->attributes as $key => $values ) {
$attributes[ $key ] = [
'value' => $values['default'],
];
}
return $attributes;
}
/**
* Outputs ES5 components according to defined attributes.
* el is wp.element.createElement.
*/
public function block_inspector_controls_js( $controls = [] ) {
foreach ( (array) $this->attributes as $key => $values ) {
ob_start();
switch ( $values['component'] ) {
case 'wp.components.RadioControl':
?>
el( <?php echo esc_js( $values['component'] ); ?>, {
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
help: "<?php echo esc_js( $values['help'] ); ?>",
selected: props.attributes.<?php echo esc_js( $key ); ?>,
options: <?php echo wp_json_encode( $values['options'] ); ?>,
onChange: function (option) {
return props.setAttributes({
<?php echo esc_js( $key ); ?>: option
});
}
})
<?php
break;
case 'wp.components.SelectControl':
?>
el( <?php echo esc_js( $values['component'] ); ?>, {
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
value: props.attributes.<?php echo esc_js( $key ); ?>,
options: <?php echo wp_json_encode( $values['options'] ); ?>,
onChange: function (option) {
return props.setAttributes({
<?php echo esc_js( $key ); ?>: option
});
}
})
<?php
break;
case 'wp.components.ColorPicker':
?>
el(
'span',
null,
"<?php echo esc_js( $values['label'] ); ?>"
),
el(
<?php echo esc_js( $values['component'] ); ?>,
{
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
type: 'color',
color: props.attributes.<?php echo esc_js( $key ); ?>,
onChangeComplete: function(newValue) {
props.setAttributes({
<?php echo esc_js( $key ); ?>: newValue.hex
});
},
disableAlpha: true
}
)
<?php
break;
case 'wp.components.ColorPalette':
?>
el(
'span',
null,
"<?php echo esc_js( $values['label'] ); ?>"
),
el( <?php echo esc_js( $values['component'] ); ?>, {
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
colors: <?php echo wp_json_encode( $values['colors'] ); ?>,
value: props.attributes.<?php echo esc_js( $key ); ?>,
onChange: function(newValue) {
props.setAttributes({
<?php echo esc_js( $key ); ?>: newValue
});
},
disableAlpha: false
})
<?php
break;
case 'wp.components.ToggleControl':
?>
el( <?php echo esc_js( $values['component'] ); ?>, {
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
checked: props.attributes.<?php echo esc_js( $key ); ?>,
onChange: function(newValue) {
props.setAttributes({
<?php echo esc_js( $key ); ?>: newValue
});
}
})
<?php
break;
case 'wp.components.RangeControl':
?>
el( <?php echo esc_js( $values['component'] ); ?>, {
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
value: props.attributes.<?php echo esc_js( $key ); ?>,
onChange: function(newValue) {
props.setAttributes({
<?php echo esc_js( $key ); ?>: newValue
});
},
min: <?php echo (int) $values['min']; ?>,
max: <?php echo (int) $values['max']; ?>
})
<?php
break;
case 'wp.components.TextControl':
?>
el( <?php echo esc_js( $values['component'] ); ?>, {
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
value: props.attributes.<?php echo esc_js( $key ); ?>,
onChange: function(newValue) {
props.setAttributes({
<?php echo esc_js( $key ); ?>: newValue
});
},
type: '<?php echo esc_js( $values['input_type'] ); ?>'
})
<?php
break;
case 'wp.components.TextareaControl':
?>
el( <?php echo esc_js( $values['component'] ); ?>, {
key: '<?php echo esc_js( $key ); ?>',
label: "<?php echo esc_js( $values['label'] ); ?>",
value: props.attributes.<?php echo esc_js( $key ); ?>,
onChange: function(newValue) {
props.setAttributes({
<?php echo esc_js( $key ); ?>: newValue
});
},
rows: <?php echo ( $values['rows'] ) ? (int) $values['rows'] : 4; ?>
})
<?php
break;
}
$controls[] = ob_get_clean();
}
return $controls;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment