Last active
May 16, 2022 23:28
-
-
Save pdclark/da1448b587f6cbfe9cd579a32bfbeea6 to your computer and use it in GitHub Desktop.
Gutenberg block to wrap the `[pods]` shortcode.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 <[email protected]> | |
*/ | |
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