, Ruben Garcia * @since 1.6.0 */ // Exit if accessed directly if( !defined( 'ABSPATH' ) ) exit; /** * Select the right "block_categories" filter according to WP version * * @since 2.1.9 */ function gamipress_init_block_category() { global $wp_version; if( version_compare( $wp_version, '5.8', '<' ) ) { // WP version is less than 5.8 add_filter( 'block_categories', 'gamipress_register_block_categories', 10, 2 ); } else { // WP version is 5.8 or higher add_filter( 'block_categories_all', 'gamipress_register_block_categories', 10, 2 ); } } add_action( 'gamipress_init', 'gamipress_init_block_category' ); /** * Register GamiPress as block category * * @since 1.6.0 */ function gamipress_register_block_categories( $categories, $post ) { // Register GamiPress as block category $categories[] = array( 'title' => 'GamiPress', 'slug' => 'gamipress', 'icon' => 'gamipress', ); return $categories; } /** * GamiPress block icons * * @since 1.6.1 */ function gamipress_get_block_icons() { $icons = array( 'gamipress' => ' ', 'rank' => ' ', ); /** * Filter to register custom GamiPress block icons * * @since 1.6.1 * * @param array $icons Icons already registered * * @return array */ return apply_filters( 'gamipress_block_icons', $icons ); } /** * Register GamiPress blocks * * Important: Priority is set to 20 to let every add-on register their shortcodes first * * @since 1.6.0 */ function gamipress_register_block_types() { // Bail if Gutenberg is not enabled if( ! function_exists( 'register_block_type' ) ) { return; } foreach( GamiPress()->shortcodes as $shortcode ) { // Block name requires to be a prefix/block-slug // So let's turn gamipress_points_types to gamipress/points-types $block_name = str_replace( '_', '-', str_replace( 'gamipress_', 'gamipress/', $shortcode->slug ) ); // Register block and attributes register_block_type( $block_name, array( 'attributes' => gamipress_get_block_attributes( $shortcode ), 'render_callback' => $shortcode->output_callback, ) ); // Filter to remove null attributes passed by Gutenberg add_filter( "shortcode_atts_{$shortcode->slug}", 'gamipress_remove_null_block_attributes', 10, 4 ); } } add_action( 'init', 'gamipress_register_block_types', 20 ); /** * Setup block fields from give shortcode object * * @since 1.6.0 * * @param GamiPress_Shortcode $shortcode * * @return array */ function gamipress_get_block_fields( $shortcode ) { $fields = array(); foreach( $shortcode->fields as $field_id => $field ) { // Parse options callbacks if( isset( $field['options_cb'] ) ) { $field['options'] = gamipress_blocks_parse_options_cb( $field ); } // Move tooltip to desc if( isset( $field['tooltip'] ) ) { if( ! isset( $field['desc'] ) ) { $field['desc'] = ''; } if( ! is_array( $field['tooltip'] ) ) { // tooltip => description $field['desc'] .= $field['tooltip']; } else { // tooltip => array() $field['desc'] .= ( isset( $field['tooltip']['desc'] ) ? $field['tooltip']['desc'] : '' ); } } // Set the definitive object field $fields[$field_id] = $field; } /** * Filter to override specific block fields * * @since 1.6.0 * * @param array $fields * @param GamiPress_Shortcode $shortcode * * @return array */ $fields = apply_filters( "gamipress_get_{$shortcode->slug}_block_fields", $fields, $shortcode ); /** * Filter to override block fields * * @since 1.6.0 * * @param array $fields * @param GamiPress_Shortcode $shortcode * * @return array */ return apply_filters( 'gamipress_get_block_fields', $fields, $shortcode ); } /** * Turn select2 fields into 'post' or 'user' field types * * @since 1.6.0 * * @param array $fields * @param GamiPress_Shortcode $shortcode * * @return array */ function gamipress_blocks_selector_fields( $fields, $shortcode ) { switch ( $shortcode->slug ) { case 'gamipress_achievement': case 'gamipress_inline_achievement': // Achievement ID $fields['id']['type'] = 'post'; $fields['id']['post_type'] = gamipress_get_achievement_types_slugs(); break; case 'gamipress_achievements': // Include $fields['include']['type'] = 'post'; $fields['include']['post_type'] = gamipress_get_achievement_types_slugs(); // Exclude $fields['exclude']['type'] = 'post'; $fields['exclude']['post_type'] = gamipress_get_achievement_types_slugs(); break; case 'gamipress_rank': case 'gamipress_inline_rank': // Rank ID $fields['id']['type'] = 'post'; $fields['id']['post_type'] = gamipress_get_rank_types_slugs(); break; case 'gamipress_ranks': // Include $fields['include']['type'] = 'post'; $fields['include']['post_type'] = gamipress_get_rank_types_slugs(); // Exclude $fields['exclude']['type'] = 'post'; $fields['exclude']['post_type'] = gamipress_get_rank_types_slugs(); break; case 'gamipress_points': case 'gamipress_user_points': case 'gamipress_site_points': // Period start and end visibility $fields['period_start']['conditions'] = array( 'period' => 'custom' ); $fields['period_end']['conditions'] = array( 'period' => 'custom' ); // Inline conditions $inline_condition = array( 'field_id' => 'inline', 'value' => true, 'compare' => '!=', ); $fields['columns']['conditions'] = array( $inline_condition ); $fields['columns_small']['conditions'] = array( $inline_condition ); $fields['layout']['conditions'] = array( $inline_condition ); $fields['align']['conditions'] = array( $inline_condition ); break; case 'gamipress_points_types': // Points Types attributes $fields['toggle']['conditions'] = array( 'awards' => true, 'deducts' => true, 'relation' => 'OR' ); $fields['heading']['conditions'] = array( 'awards' => true, 'deducts' => true, 'relation' => 'OR' ); $fields['heading_size']['conditions'] = array( 'heading' => true ); break; } // Common attributes switch ( $shortcode->slug ) { case 'gamipress_achievement': case 'gamipress_achievements': case 'gamipress_last_achievements_earned': // Achievement common attributes $fields['title_size']['conditions'] = array( 'title' => true ); $fields['thumbnail_size']['conditions'] = array( 'thumbnail' => true ); $fields['points_awarded_thumbnail']['conditions'] = array( 'points_awarded' => true ); $fields['toggle']['conditions'] = array( 'steps' => true ); $fields['heading']['conditions'] = array( 'steps' => true ); $fields['heading_size']['conditions'] = array( 'steps' => true, 'heading' => true ); $fields['earners_limit']['conditions'] = array( 'earners' => true ); break; case 'gamipress_inline_achievement': case 'gamipress_inline_last_achievements_earned': // Inline achievement common attributes $fields['thumbnail_size']['conditions'] = array( 'thumbnail' => true ); break; case 'gamipress_rank': case 'gamipress_ranks': case 'gamipress_user_rank': // Rank common attributes $fields['title_size']['conditions'] = array( 'title' => true ); $fields['thumbnail_size']['conditions'] = array( 'thumbnail' => true ); $fields['toggle']['conditions'] = array( 'requirements' => true ); $fields['heading']['conditions'] = array( 'requirements' => true ); $fields['heading_size']['conditions'] = array( 'requirements' => true, 'heading' => true ); $fields['earners_limit']['conditions'] = array( 'earners' => true ); break; case 'gamipress_inline_rank': case 'gamipress_inline_user_rank': // Inline rank common attributes $fields['thumbnail_size']['conditions'] = array( 'thumbnail' => true ); break; case 'gamipress_points': case 'gamipress_user_points': case 'gamipress_site_points': case 'gamipress_points_types': // Points common attributes $fields['thumbnail_size']['conditions'] = array( 'thumbnail' => true ); break; } // Common fields to all shortcodes // User ID if( isset( $fields['user_id'] ) ) { // User ID $fields['user_id']['type'] = 'user'; } // User ID visibility when current user field is in form if( isset( $fields['user_id'] ) && isset( $fields['current_user'] ) ) { // Setup as display condition that current_user needs to be false (unchecked) $fields['user_id']['conditions'] = array( 'current_user' => false, ); } return $fields; } add_filter( 'gamipress_get_block_fields', 'gamipress_blocks_selector_fields', 10, 2 ); /** * Setup block attributes from give shortcode object * * @since 1.6.0 * * @param GamiPress_Shortcode $shortcode * * @return array */ function gamipress_get_block_attributes( $shortcode ) { $attributes = array(); // Turn fields into attributes foreach( $shortcode->fields as $field_id => $field ) { if( $field['type'] === 'checkbox' ) { // Checkboxes as boolean $attributes[$field_id] = array( 'type' => 'boolean', ); } else { // String is the default type $attributes[$field_id] = array( 'type' => 'string', ); } } /** * Filter to override specific block attributes * * @since 1.6.0 * * @param array $attributes * @param GamiPress_Shortcode $shortcode * * @return array */ $attributes = apply_filters( "gamipress_gutenberg_blocks_get_{$shortcode->slug}_block_attributes", $attributes, $shortcode ); /** * Filter to override block attributes * * @since 1.6.0 * * @param array $attributes * @param GamiPress_Shortcode $shortcode * * @return array */ return apply_filters( 'gamipress_gutenberg_blocks_get_block_attributes', $attributes, $shortcode ); } /** * Removes null attributes passed by Gutenberg * * @since 1.6.0 * * @param array $out The output array of shortcode attributes * @param array $pairs The supported attributes and their defaults * @param array $atts The user defined shortcode attributes * @param string $shortcode The shortcode name * * @return array */ function gamipress_remove_null_block_attributes( $out, $pairs, $atts, $shortcode ) { // Bail if shortcode is not registered if( ! isset( GamiPress()->shortcodes[$shortcode] ) ) return $out; // Setup the shortcode object $shortcode_obj = GamiPress()->shortcodes[$shortcode]; foreach( $out as $name => $value ) { // Gutenberg pass default values and empty as null // So let's force default value instead of null if( $value === null ) { $out[$name] = $pairs[$name]; } if( isset( $shortcode_obj->fields[$name] ) ) { $field = $shortcode_obj->fields[$name]; if( $field['type'] === 'checkbox' && is_bool( $out[$name] ) ) { // Turn booleans into yes|no $out[$name] = ( $out[$name] === true ? 'yes' : 'no' ); } } } return $out; } /** * Filter block per-rendering to setup the renderer for error messages * * @since 1.7.6 * * @param string $pre_render The pre-rendered content. Default null. * @param array $block The block being rendered. * * @return string */ function gamipress_pre_render_block( $pre_render, $block ) { global $gamipress_renderer; // Setup renderer $gamipress_renderer = 'block'; return $pre_render; } add_filter( 'pre_render_block', 'gamipress_pre_render_block', 10, 2 ); /** * Filter block rendering to reset the renderer for error messages * * @since 1.7.6 * * @param string $block_content The block content about to be appended. * @param array $block The full block, including name and attributes. * * @return string */ function gamipress_render_block( $block_content, $block ) { global $gamipress_renderer; // Reset renderer $gamipress_renderer = false; return $block_content; } add_filter( 'render_block', 'gamipress_render_block', 10, 2 ); /** * Simulates CMB2 options_cb processing * * @since 1.6.0 * * @param array $field * * @return array */ function gamipress_blocks_parse_options_cb( $field ) { $field_options = ( isset( $field['options'] ) ? (array) $field['options'] : array() ); if ( isset( $field['options_cb'] ) && is_callable( $field['options_cb'] ) ) { $options = call_user_func( $field['options_cb'], gamipress_blocks_cmb_field_object( $field ) ); if ( $options && is_array( $options ) ) { $field_options = $options + $field_options; } } return $field_options; } /** * Builds a false CMB2 field object * * @since 1.6.0 * * @param array $field * * @return stdClass */ function gamipress_blocks_cmb_field_object( $field ) { return (object) array( 'args' => $field, 'value' => '', 'escaped_value' => '', ); }