: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( $field['type'] === $this->type ) {
unset( $form_data['fields'][ $id ] );
* Remove field from form data before processing the form submit.
* @param array $form_data Form data.
* @param array $entry Form submission raw data ($_POST).
public function process_before_form_data( $form_data, $entry ) {
return $this->remove_internal_fields_on_front_end( $form_data );
* Do not display the duplicate button.
* @param bool $is_visible If true, the duplicate button will be displayed.
* @param array $field Field data and settings.
* @param array $form_data Form data and settings.
public function display_duplicate_button( $is_visible, $field, $form_data ) {
if ( $this->is_internal_information_field( $field ) && ! $this->is_editable() ) {
* Hide column from the entry list table.
* @param array|mixed $disallowed Table columns.
public function hide_column_in_entries_table( $disallowed ): array {
$disallowed = (array) $disallowed;
$disallowed[] = $this->type;
* Add CSS class for the field parent div informing about mode (editable or not).
* @param string $css CSS classes.
* @param array $field Field data and settings.
public function add_css_class_for_field_wrapper( $css, $field ) {
if ( ! $this->is_internal_information_field( $field ) ) {
if ( $this->is_editable() ) {
$css .= ' internal-information-editable ';
$css .= ' ui-sortable-disabled internal-information-not-editable internal-information-not-draggable ';
return str_replace( 'ui-sortable-handle', '', $css );
* Save checkbox state to the post meta table.
public function save_internal_information_checkbox() {
// Run several checks: required items, security, permissions.
! isset( $_POST['formId'], $_POST['name'], $_POST['checked'] ) ||
! check_ajax_referer( 'wpforms-builder', 'nonce', false ) ||
! wpforms_current_user_can( 'edit_forms' )
$form_id = (int) $_POST['formId'];
$checked = (int) $_POST['checked'];
$name = sanitize_text_field( wp_unslash( $_POST['name'] ) );
$post_meta = get_post_meta( $form_id, self::CHECKBOX_META_KEY, true );
$post_meta = ! empty( $post_meta ) ? (array) $post_meta : [];
$post_meta[ $name ] = $checked;
unset( $post_meta[ $name ] );
update_post_meta( $form_id, self::CHECKBOX_META_KEY, $post_meta );
* Localized strings for wpforms-internal-information-field JS script.
* @param array $strings Localized strings.
* @param array $form The form element.
* @noinspection PhpUnusedParameterInspection
public function builder_strings( $strings, $form ) {
$strings['iif_redirect_url_field_error'] = esc_html__( 'You should enter a valid absolute address to the CTA Link field or leave it empty.', 'wpforms-lite' );
$strings['iif_dismiss'] = esc_html__( 'Dismiss', 'wpforms-lite' );
$strings['iif_more'] = esc_html__( 'Learn More', 'wpforms-lite' );
* Enqueue wpforms-internal-information-field script.
* @param string $view Current view.
* @noinspection PhpUnusedParameterInspection, PhpUnnecessaryCurlyVarSyntaxInspection
public function builder_enqueues( $view ) {
$min = wpforms_get_min_suffix();
WPFORMS_PLUGIN_URL . 'assets/lib/md5.min.js',
'wpforms-internal-information-field',
WPFORMS_PLUGIN_URL . "assets/js/admin/builder/fields/internal-information{$min}.js",
[ 'wpforms-builder', 'wpforms-md5-hash', 'wpforms-builder-drag-fields' ],
* Checks if user is allowed to edit the field's content.
private function is_editable() {
* @param bool $is_editable True if editable mode is allowed. Default: false.
return (bool) apply_filters( 'wpforms_field_internal_information_is_editable', false );
* Check if the field has type internal-information.
* @param array $field Field data.
private function is_internal_information_field( $field ) {
return isset( $field['type'] ) && $field['type'] === $this->type;
* Render result of field_preview_option into custom div.
* If field has no value, do not echo anything.
* @param string $label Field label.
* @param array $field Field settings and data.
* @param array $args Field arguments.
private function render_preview( $label, $field, $args = [] ) {
$key = $label === 'heading' ? 'label' : $label;
if ( empty( $field[ $key ] ) && ! $this->is_editable() ) {
$allowed_tags = $this->get_allowed_tags();
'<div class="wpforms-field-internal-information-row wpforms-field-internal-information-row-%s">%s</div>',
wp_kses( $this->render_custom_preview( $label, $field, $args ), $allowed_tags )
* Replace `[] some text` with checkboxes.
* Additionally, generates input name by hashing the line of text where the checkbox is.
* @param string $description Expanded description.
* @param array $field Field data and settings.
private function replace_checkboxes( $description, array $field ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
if ( ! $this->form_id ) {
$lines = explode( PHP_EOL, $description );
$post_meta = get_post_meta( $this->form_id, self::CHECKBOX_META_KEY, true );
$post_meta = ! empty( $post_meta ) ? (array) $post_meta : [];
$field_id = isset( $field['id'] ) ? $field['id'] : 0;
foreach ( $lines as $line_number => $line ) {
if ( strpos( $line, $needle ) !== 0 ) {
$replaced[] = $line . PHP_EOL;
$field_name = sprintf( 'iif-%d-%s-%d', $field_id, md5( $line ), $line_number );
$checked = (int) isset( $post_meta[ $field_name ] );
'name' => esc_attr( $field_name ),
if ( $this->is_editable() ) {
$attributes['disabled'] = 'disabled';
$attributes['title'] = esc_html__( 'This field is disabled in the editor mode.', 'wpforms-lite' );
'<div class="wpforms-field-internal-information-checkbox-input"><input type="checkbox" %s %s /></div><div class="wpforms-field-internal-information-checkbox-label">',
[ 'wpforms-field-internal-information-checkbox' ],
! $this->is_editable() ? checked( $checked, 1, false ) : ''
$line = substr_replace( $line, $html, 0, strlen( $needle ) );
$replaced[] = '<div class="wpforms-field-internal-information-checkbox-wrap">' . $line . '</div></div>';
return implode( '', $replaced );
* Return allowed tags specific to internal information field content.
private function get_allowed_tags() {
$allowed_tags = wpforms_builder_preview_get_allowed_tags();
$allowed_tags['input'] = [
* Adds link parameters to all links in the provided content.
* @param string $content The content to modify.
* @return string The modified content with UTM parameters added to links.
private function add_link_attributes( $content ) {
if ( empty( $content ) || ! class_exists( 'DOMDocument' ) ) {
$dom = new DOMDocument();
$form_data = wpforms()->get( 'form' )->get( $this->form_id, [ 'content_only' => true ] );
$template_data = ! empty( $form_data['meta'] ) ? wpforms()->get( 'builder_templates' )->get_template( $form_data['meta']['template'] ) : [];
$template_name = ! empty( $template_data ) ? $template_data['name'] : '';
$dom->loadHTML( htmlspecialchars_decode( htmlentities( $content ) ) );
$links = $dom->getElementsByTagName( 'a' );
foreach ( $links as $link ) {
$href = $link->getAttribute( 'href' );
$text = $link->textContent; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$modified_href = wpforms_utm_link( $href, 'Form Template Information Note', $template_name, $text );
$link->setAttribute( 'href', $modified_href );
$link->setAttribute( 'target', '_blank' );
$link->setAttribute( 'rel', 'noopener noreferrer' );
// Remove the wrapper elements.
$body = $dom->getElementsByTagName( 'body' )->item( 0 );
foreach ( $body->childNodes as $node ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$inner_html .= $dom->saveHTML( $node );
* Add UTM parameters to the CTA button link.
* @param array $field Field data.
private function add_url_utm( $field ) {
if ( strpos( $field['cta-link'], 'https://wpforms.com' ) === 0 ) {
return wpforms_utm_link( $field['cta-link'], 'Template Documentation' );
return $field['cta-link'];
new WPForms_Field_Internal_Information();