maybe_override_block_attributes( array $attr ): array {
$theme_slug = (string) ( $attr['theme'] ?? '' );
// Previously added blocks (FS 1.0) don't have the themeName attribute.
// To preserve existing styling of such old blocks, we shouldn't override attributes.
if ( ! isset( $attr['themeName'] ) || ( empty( $attr['themeName'] ) && $theme_slug === 'default' ) ) {
return $attr;
}
$theme_data = $this->themes_data_obj->get_theme( $theme_slug );
// Theme doesn't exist, let's return.
if ( ! $theme_data ) {
return $attr;
}
// Override block attributes with the theme settings.
return array_merge( $attr, $theme_data['settings'] );
}
/**
* Add class callback.
*
* @since 1.8.1
*
* @param int $id Form id.
* @param array $attr Form attributes.
*
* @return void
*/
private function add_class_callback( $id, $attr ) { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
$class_callback = static function ( $classes, $form_data ) use ( $id, $attr ) {
if ( (int) $form_data['id'] !== $id ) {
return $classes;
}
$cls = [];
// Add custom class to form container.
if ( ! empty( $attr['className'] ) ) {
$cls = array_map( 'esc_attr', explode( ' ', $attr['className'] ) );
}
// Add classes to identify that the form displays inside the block.
$cls[] = 'wpforms-block';
if ( ! empty( $attr['clientId'] ) ) {
$cls[] = 'wpforms-block-' . $attr['clientId'];
}
return array_unique( array_merge( $classes, $cls ) );
};
if ( empty( $this->callbacks[ $id ] ) ) {
add_filter( 'wpforms_frontend_container_class', $class_callback, 10, 2 );
}
$this->callbacks[ $id ][] = $class_callback;
}
/**
* Get content.
*
* @since 1.8.1
*
* @param int $id Form id.
* @param bool $title Form title is not empty.
* @param bool $desc Form desc is not empty.
* @param array $attr Form attributes.
*
* @return string
*/
private function get_content( $id, $title, $desc, $attr ): string {
/**
* Filter allow render block content flag.
*
* @since 1.8.8
*
* @param bool $allow_render Allow render flag. Defaults to `true`.
*/
$allow_render = (bool) apply_filters( 'wpforms_integrations_gutenberg_form_selector_allow_render', true );
if ( ! $allow_render ) {
return '';
}
ob_start();
// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName
/**
* Fires before Gutenberg block output.
*
* @since 1.5.8.2
*/
do_action( 'wpforms_gutenberg_block_before' );
/**
* Filter block title display flag.
*
* @since 1.5.8.2
*
* @param bool $title Title display flag.
* @param int $id Form id.
*/
$title = (bool) apply_filters( 'wpforms_gutenberg_block_form_title', $title, $id );
/**
* Filter block description display flag.
*
* @since 1.5.8.2
*
* @param bool $desc Description display flag.
* @param int $id Form id.
*/
$desc = (bool) apply_filters( 'wpforms_gutenberg_block_form_desc', $desc, $id );
$this->output_css_vars( $attr );
$this->output_custom_css( $attr );
wpforms_display( $id, $title, $desc );
/**
* Fires after Gutenberg block output.
*
* @since 1.5.8.2
*/
do_action( 'wpforms_gutenberg_block_after' );
// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
$content = (string) ob_get_clean();
if ( ! $this->is_gb_editor() ) {
return $content;
}
if ( empty( $content ) ) {
return '
' .
'
' .
esc_html__( 'The form cannot be displayed.', 'wpforms-lite' ) .
'
';
}
/**
* Unfortunately, the inline 'script' tag cannot be executed in the GB editor.
* This is the hacky way to trigger custom event on form loaded in the Block Editor / GB / FSE.
*/
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_export
$content .= sprintf(
'',
absint( $id ),
var_export( (bool) $title, true ),
var_export( (bool) $desc, true )
);
// phpcs:enable WordPress.PHP.DevelopmentFunctions.error_log_var_export
return $content;
}
/**
* Checking if is Gutenberg REST API call.
*
* @since 1.5.7
*
* @return bool True if is Gutenberg REST API call.
*/
public function is_gb_editor(): bool {
// TODO: Find a better way to check if is GB editor API call.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
return defined( 'REST_REQUEST' ) && REST_REQUEST && ! empty( $_REQUEST['context'] ) && $_REQUEST['context'] === 'edit';
}
/**
* Disable form fields if called from the Gutenberg editor.
*
* @since 1.7.5
*
* @return void
*/
private function disable_fields_in_gb_editor() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
add_filter(
'wpforms_frontend_container_class',
static function ( $classes ) {
$classes[] = 'wpforms-gutenberg-form-selector';
return $classes;
}
);
add_action(
'wpforms_frontend_output',
static function () {
echo '';
},
30
);
}
/**
* Output CSS variables for the particular form.
*
* @since 1.8.1
*
* @param array $attr Attributes passed by WPForms Gutenberg block.
*/
private function output_css_vars( $attr ) {
if ( empty( $this->css_vars_obj ) || ! method_exists( $this->css_vars_obj, 'get_vars' ) ) {
return;
}
$this->css_vars_obj->output_root();
if ( $this->render_engine === 'classic' || $this->disable_css_setting !== 1 ) {
return;
}
$css_vars = $this->css_vars_obj->get_customized_css_vars( $attr );
if ( empty( $css_vars ) ) {
return;
}
$style_id = "#wpforms-css-vars-{$attr['formId']}-block-{$attr['clientId']}";
/**
* Filter the CSS selector for output CSS variables for styling the GB block form.
*
* @since 1.8.1
*
* @param string $selector The CSS selector for output CSS variables for styling the GB block form.
* @param array $attr Attributes passed by WPForms Gutenberg block.
* @param array $css_vars CSS variables data.
*/
$vars_selector = apply_filters(
'wpforms_integrations_gutenberg_form_selector_output_css_vars_selector',
"#wpforms-{$attr['formId']}.wpforms-block-{$attr['clientId']}",
$attr,
$css_vars
);
$this->css_vars_obj->output_selector_vars( $vars_selector, $css_vars, $style_id, $this->current_form_id );
}
/**
* Output custom CSS styles.
*
* @since 1.8.8
*
* @param array $attr Attributes passed by WPForms Gutenberg block.
*/
private function output_custom_css( $attr ) {
if ( wpforms_get_render_engine() === 'classic' ) {
return;
}
$custom_css = trim( $attr['customCss'] ?? '' );
if ( empty( $custom_css ) ) {
return;
}
$style_id = "#wpforms-custom-css-{$attr['formId']}-block-{$attr['clientId']}";
printf(
'',
sanitize_key( $style_id ),
esc_html( $custom_css )
);
}
/**
* Disable loading media for the richtext editor for edit action to prevent script conflicts.
*
* @since 1.9.1
*
* @param bool|mixed $media_enabled Whether to enable media.
* @param array $field Field data.
*
* @return bool
*/
public function disable_richtext_media( $media_enabled, array $field ): bool {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] === 'edit' && is_admin() ) {
return false;
}
return (bool) $media_enabled;
}
}