/
home
/
altere25
/
public_html
/
wp-content
/
plugins
/
formidable
/
classes
/
helpers
/
/home/altere25/public_html/wp-content/plugins/formidable/classes/helpers
mkdir
upload
Name
Size
Mode
Actions
FrmAddonsHelper.php
7140
0644
edit
dl
rm
FrmAppHelper.php
123272
0644
edit
dl
rm
FrmCSVExportHelper.php
21675
0644
edit
dl
rm
FrmCurrencyHelper.php
10146
0644
edit
dl
rm
FrmDashboardHelper.php
11696
0644
edit
dl
rm
FrmEmailHelper.php
1191
0644
edit
dl
rm
FrmEmailSummaryHelper.php
14725
0644
edit
dl
rm
FrmEntriesHelper.php
27795
0644
edit
dl
rm
FrmEntriesListHelper.php
13920
0644
edit
dl
rm
FrmFieldGridHelper.php
6081
0644
edit
dl
rm
FrmFieldsHelper.php
71408
0644
edit
dl
rm
FrmFormActionsHelper.php
817
0644
edit
dl
rm
FrmFormMigratorsHelper.php
5211
0644
edit
dl
rm
FrmFormsHelper.php
56523
0644
edit
dl
rm
FrmFormsListHelper.php
13074
0644
edit
dl
rm
FrmFormTemplatesHelper.php
6227
0644
edit
dl
rm
FrmHtmlHelper.php
1699
0644
edit
dl
rm
FrmListHelper.php
33139
0644
edit
dl
rm
FrmOnboardingWizardHelper.php
4088
0644
edit
dl
rm
FrmOnSubmitHelper.php
14768
0644
edit
dl
rm
FrmSerializedStringParserHelper.php
3138
0644
edit
dl
rm
FrmShortcodeHelper.php
2214
0644
edit
dl
rm
FrmStringReaderHelper.php
2397
0644
edit
dl
rm
FrmStylesCardHelper.php
13417
0644
edit
dl
rm
FrmStylesHelper.php
25644
0644
edit
dl
rm
FrmStylesPreviewHelper.php
11284
0644
edit
dl
rm
FrmSubmitHelper.php
4425
0644
edit
dl
rm
FrmTipsHelper.php
12468
0644
edit
dl
rm
FrmXMLHelper.php
66398
0644
edit
dl
rm
Edit:
/home/altere25/public_html/wp-content/plugins/formidable/classes/helpers/FrmXMLHelper.php
(66398B)
<?php if ( ! defined( 'ABSPATH' ) ) { die( 'You are not allowed to call this page directly.' ); } class FrmXMLHelper { /** * @var bool true if importing an XML from API, false if importing an XML file manually. */ private static $installing_template = false; public static function get_xml_values( $opt, $padding ) { if ( is_array( $opt ) ) { foreach ( $opt as $ok => $ov ) { echo "\n" . esc_html( $padding ); $tag = ( is_numeric( $ok ) ? 'key:' : '' ) . $ok; echo '<' . esc_html( $tag ) . '>'; self::get_xml_values( $ov, $padding . ' ' ); if ( is_array( $ov ) ) { echo "\n" . esc_html( $padding ); } echo '</' . esc_html( $tag ) . '>'; } } else { echo self::cdata( $opt ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } /** * @param string $file * @return array|WP_Error The items imported */ public static function import_xml( $file ) { if ( ! defined( 'WP_IMPORTING' ) ) { define( 'WP_IMPORTING', true ); } if ( ! class_exists( 'DOMDocument' ) ) { $error_message = sprintf( /* translators: 1: Documentation link */ __( 'In order to install XML, your server must have DOMDocument installed. Follow our documentation on %1$s to ensure DOMDocument is properly set up and XML support is enabled.', 'formidable' ), '<a href="https://formidableforms.com/knowledgebase/import-forms-entries-and-views/#kb-your-server-does-not-have-xml-enabled" target="_blank">Importing Forms, Entries, and Views</a>' ); return new WP_Error( 'SimpleXML_parse_error', $error_message, libxml_get_errors() ); } $xml_string = file_get_contents( $file ); self::maybe_fix_xml( $xml_string ); $dom = new DOMDocument(); // LIBXML_COMPACT activates small nodes allocation optimization. // Use LIBXML_PARSEHUGE to avoid "parser error : internal error: Huge input lookup" for large (300MB) files. $success = $dom->loadXML( $xml_string, LIBXML_COMPACT | LIBXML_PARSEHUGE ); if ( ! $success ) { return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this XML file', 'formidable' ), libxml_get_errors() ); } if ( ! function_exists( 'simplexml_import_dom' ) ) { return new WP_Error( 'SimpleXML_parse_error', __( 'Your server is missing the simplexml_import_dom function', 'formidable' ), libxml_get_errors() ); } $xml = simplexml_import_dom( $dom ); unset( $dom ); // halt if loading produces an error if ( ! $xml ) { return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this XML file', 'formidable' ), libxml_get_errors() ); } return self::import_xml_now( $xml ); } /** * @since 6.2.3 * * @param string $xml_string * @return void */ private static function maybe_fix_xml( &$xml_string ) { if ( '<?xml' !== substr( $xml_string, 0, 5 ) ) { // Some XML files have may have unexpected characters at the start. $xml_string = substr( $xml_string, strpos( $xml_string, '<?xml' ) ); } // The Equity theme adds a <meta name="generator" content="Equity 1.7.13" /> tag using the "the_generator" filter. // Strip that out as it breaks the XML import. $channel_start_position = strpos( $xml_string, '<channel>' ); $content_before_channel_tag = substr( $xml_string, 0, $channel_start_position ); if ( 0 !== strpos( $content_before_channel_tag, '<meta name="generator" ' ) ) { $content_before_channel_tag = preg_replace( '/<meta\s+[^>]*name="generator"[^>]*\/>/i', '', $content_before_channel_tag, 1 ); $xml_string = $content_before_channel_tag . substr( $xml_string, $channel_start_position ); } } /** * Add terms, forms (form and field ids), posts (post ids), and entries to db, in that order * * @since 3.06 * * @param object $xml * @param bool $installing_template * @return array The number of items imported */ public static function import_xml_now( $xml, $installing_template = false ) { if ( ! defined( 'WP_IMPORTING' ) ) { define( 'WP_IMPORTING', true ); } self::$installing_template = $installing_template; $imported = self::pre_import_data(); foreach ( array( 'term', 'form', 'view' ) as $item_type ) { // Grab cats, tags, and terms, or forms or posts. if ( isset( $xml->{$item_type} ) ) { $function_name = 'import_xml_' . $item_type . 's'; $imported = self::$function_name( $xml->{$item_type}, $imported ); unset( $function_name, $xml->{$item_type} ); } } $imported = apply_filters( 'frm_importing_xml', $imported, $xml ); if ( empty( $imported['form_status'] ) ) { // Check for an error message in the XML. if ( isset( $xml->Code ) && isset( $xml->Message ) ) { // phpcs:ignore WordPress.NamingConventions $imported['error'] = (string) $xml->Message; // phpcs:ignore WordPress.NamingConventions } } return $imported; } /** * @since 3.06 * @return array */ private static function pre_import_data() { $defaults = array( 'forms' => 0, 'fields' => 0, 'terms' => 0, 'posts' => 0, 'views' => 0, 'actions' => 0, 'styles' => 0, ); return array( 'imported' => $defaults, 'updated' => $defaults, 'forms' => array(), 'terms' => array(), ); } /** * @param SimpleXMLElement $terms * @param array $imported * @return array */ public static function import_xml_terms( $terms, $imported ) { foreach ( $terms as $t ) { if ( term_exists( (string) $t->term_slug, (string) $t->term_taxonomy ) ) { continue; } $parent = self::get_term_parent_id( $t ); $term = wp_insert_term( (string) $t->term_name, (string) $t->term_taxonomy, array( 'slug' => (string) $t->term_slug, 'description' => (string) $t->term_description, 'parent' => empty( $parent ) ? 0 : $parent, ) ); if ( $term && is_array( $term ) ) { ++$imported['imported']['terms']; $imported['terms'][ (int) $t->term_id ] = $term['term_id']; } unset( $term, $t ); }//end foreach return $imported; } /** * @since 2.0.8 * * @param object $t * @return int|string */ private static function get_term_parent_id( $t ) { $parent = (string) $t->term_parent; if ( ! empty( $parent ) ) { $parent = term_exists( (string) $t->term_parent, (string) $t->term_taxonomy ); if ( $parent ) { $parent = $parent['term_id']; } else { $parent = 0; } } return $parent; } /** * @param SimpleXMLElement $forms * @param array $imported * @return array */ public static function import_xml_forms( $forms, $imported ) { $child_forms = array(); // Import child forms first self::put_child_forms_first( $forms ); foreach ( $forms as $item ) { $form = self::fill_form( $item ); self::update_custom_style_setting_on_import( $form ); $this_form = self::maybe_get_form( $form ); $old_id = false; $form_fields = false; if ( ! empty( $this_form ) ) { $form_id = $this_form->id; $old_id = $this_form->id; self::update_form( $this_form, $form, $imported ); $form_fields = self::get_form_fields( $form_id ); } else { $form_id = FrmForm::create( $form ); if ( $form_id ) { if ( empty( $form['parent_form_id'] ) ) { // Don't include the repeater form in the imported count. ++$imported['imported']['forms']; } // Keep track of whether this specific form was updated or not. $imported['form_status'][ $form_id ] = 'imported'; } } if ( $form_id ) { self::track_imported_child_forms( (int) $form_id, $form['parent_form_id'], $child_forms ); } self::import_xml_fields( $item->field, $form_id, $this_form, $form_fields, $imported ); self::delete_removed_fields( $form_fields ); // Update field ids/keys to new ones. do_action( 'frm_after_duplicate_form', $form_id, $form, array( 'old_id' => $old_id ) ); $imported['forms'][ (int) $item->id ] = $form_id; // Send pre 2.0 form options through function that creates actions. self::migrate_form_settings_to_actions( $form['options'], $form_id, $imported, true ); do_action( 'frm_after_import_form', $form_id, $form ); unset( $form, $item ); }//end foreach self::maybe_update_child_form_parent_id( $imported['forms'], $child_forms ); return $imported; } private static function fill_form( $item ) { $form = array( 'id' => (int) $item->id, 'form_key' => (string) $item->form_key, 'name' => (string) $item->name, 'description' => (string) $item->description, 'options' => (string) $item->options, 'logged_in' => (int) $item->logged_in, 'is_template' => (int) $item->is_template, 'editable' => (int) $item->editable, 'status' => (string) $item->status, 'parent_form_id' => isset( $item->parent_form_id ) ? (int) $item->parent_form_id : 0, 'created_at' => gmdate( 'Y-m-d H:i:s', strtotime( (string) $item->created_at ) ), ); if ( empty( $item->created_at ) ) { $form['created_at'] = current_time( 'mysql', 1 ); } $form['options'] = FrmAppHelper::maybe_json_decode( $form['options'] ); if ( self::$installing_template ) { // Templates don't necessarily have antispam on, but we want our templates to all have antispam on by default. $form['options']['antispam'] = 1; } return $form; } private static function maybe_get_form( $form ) { // if template, allow to edit if form keys match, otherwise, creation date must also match $edit_query = array( 'form_key' => $form['form_key'], 'is_template' => $form['is_template'], ); if ( ! $form['is_template'] ) { $edit_query['created_at'] = $form['created_at']; } $edit_query = apply_filters( 'frm_match_xml_form', $edit_query, $form ); $form = FrmForm::getAll( $edit_query, '', 1 ); if ( is_object( $form ) && $form->status === 'trash' ) { FrmForm::destroy( $form->id ); return false; } return $form; } private static function update_form( $this_form, $form, &$imported ) { $form_id = $this_form->id; FrmForm::update( $form_id, $form ); if ( empty( $form['parent_form_id'] ) ) { // Don't include the repeater form in the updated count. ++$imported['updated']['forms']; } // Keep track of whether this specific form was updated or not $imported['form_status'][ $form_id ] = 'updated'; } private static function get_form_fields( $form_id ) { $form_fields = FrmField::get_all_for_form( $form_id, '', 'exclude', 'exclude' ); $old_fields = array(); foreach ( $form_fields as $f ) { $old_fields[ $f->id ] = $f; $old_fields[ $f->field_key ] = $f->id; unset( $f ); } $form_fields = $old_fields; return $form_fields; } /** * Delete any fields attached to this form that were not included in the template */ private static function delete_removed_fields( $form_fields ) { if ( ! empty( $form_fields ) ) { foreach ( $form_fields as $field ) { if ( is_object( $field ) ) { FrmField::destroy( $field->id ); } unset( $field ); } } } /** * Put child forms first so they will be imported before parents * * @since 2.0.16 * * @param array $forms */ private static function put_child_forms_first( &$forms ) { $child_forms = array(); $regular_forms = array(); foreach ( $forms as $form ) { $parent_form_id = isset( $form->parent_form_id ) ? (int) $form->parent_form_id : 0; if ( $parent_form_id ) { $child_forms[] = $form; } else { $regular_forms[] = $form; } } $forms = array_merge( $child_forms, $regular_forms ); } /** * Keep track of all imported child forms * * @since 2.0.16 * * @param int $form_id * @param int $parent_form_id * @param array $child_forms */ private static function track_imported_child_forms( $form_id, $parent_form_id, &$child_forms ) { if ( $parent_form_id ) { $child_forms[ $form_id ] = $parent_form_id; } } /** * Update the parent_form_id on imported child forms * Child forms are imported first so their parent_form_id will need to be updated after the parent is imported * * @since 2.0.6 * * @param array $imported_forms * @param array $child_forms */ private static function maybe_update_child_form_parent_id( $imported_forms, $child_forms ) { foreach ( $child_forms as $child_form_id => $old_parent_form_id ) { if ( isset( $imported_forms[ $old_parent_form_id ] ) && (int) $imported_forms[ $old_parent_form_id ] !== (int) $old_parent_form_id ) { // Update all children with this old parent_form_id $new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ]; FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) ); do_action( 'frm_update_child_form_parent_id', $child_form_id, $new_parent_form_id ); } } } /** * Import all fields for a form * * @since 2.0.13 * * TODO: Cut down on params */ private static function import_xml_fields( $xml_fields, $form_id, $this_form, &$form_fields, &$imported ) { $in_section = 0; $keys_by_original_field_id = array(); foreach ( $xml_fields as $field ) { $f = self::fill_field( $field, $form_id ); self::set_default_value( $f ); self::maybe_add_required( $f ); self::maybe_update_in_section_variable( $in_section, $f ); self::maybe_update_form_select( $f, $imported ); self::maybe_update_get_values_form_setting( $imported, $f ); self::migrate_placeholders( $f ); if ( ! empty( $this_form ) ) { // check for field to edit by field id if ( isset( $form_fields[ $f['id'] ] ) ) { FrmField::update( $f['id'], $f ); ++$imported['updated']['fields']; unset( $form_fields[ $f['id'] ] ); // Unset old field key. if ( isset( $form_fields[ $f['field_key'] ] ) ) { unset( $form_fields[ $f['field_key'] ] ); } } elseif ( isset( $form_fields[ $f['field_key'] ] ) ) { $keys_by_original_field_id[ $f['id'] ] = $f['field_key']; $old_field_id = $f['id']; // check for field to edit by field key unset( $f['id'] ); FrmField::update( $form_fields[ $f['field_key'] ], $f ); ++$imported['updated']['fields']; self::do_after_field_imported_action( $f, $form_fields, $old_field_id ); // Unset old field id. unset( $form_fields[ $form_fields[ $f['field_key'] ] ] ); // Unset old field key. unset( $form_fields[ $f['field_key'] ] ); } else { // If no matching field id or key in this form, create the field. self::create_imported_field( $f, $imported ); }//end if } else { self::create_imported_field( $f, $imported ); }//end if }//end foreach if ( $keys_by_original_field_id ) { self::maybe_update_field_ids( $form_id, $keys_by_original_field_id ); } } /** * @since 6.8.4 * * @param array $field_array * @return array */ private static function update_field_options_with_defaults( $field_array ) { $defaults = self::default_field_options( $field_array['type'] ); $field_array['field_options'] = array_merge( $defaults, $field_array['field_options'] ); return $field_array; } /** * @since 6.8.4 * * @param array $field_array * @param array $form_fields * @param int $old_field_id * * @return void */ private static function do_after_field_imported_action( $field_array, $form_fields, $old_field_id ) { // Assign field array the update field's ID. $field_array['id'] = $form_fields[ $field_array['field_key'] ]; /** * Fires when an existing field is imported. * * @since 6.8.4 * * @param array $field_array * @param int $field_id * @param int $old_field_id */ do_action( 'frm_after_existing_field_is_imported', $field_array, $form_fields[ $field_array['field_key'] ], $old_field_id ); } private static function fill_field( $field, $form_id ) { return array( 'id' => (int) $field->id, 'field_key' => (string) $field->field_key, 'name' => (string) $field->name, 'description' => (string) $field->description, 'type' => (string) $field->type, 'default_value' => FrmAppHelper::maybe_json_decode( (string) $field->default_value ), 'field_order' => (int) $field->field_order, 'form_id' => (int) $form_id, 'required' => (int) $field->required, 'options' => FrmAppHelper::maybe_json_decode( (string) $field->options ), 'field_options' => FrmAppHelper::maybe_json_decode( (string) $field->field_options ), ); } /** * @since 4.06 */ private static function set_default_value( &$f ) { $has_default = array( 'text', 'email', 'url', 'textarea', 'number', 'phone', 'date', 'hidden', 'password', 'tag', ); if ( is_array( $f['default_value'] ) && in_array( $f['type'], $has_default, true ) ) { if ( count( $f['default_value'] ) === 1 ) { $f['default_value'] = '[' . reset( $f['default_value'] ) . ']'; } else { $f['default_value'] = reset( $f['default_value'] ); } } } /** * Make sure the required indicator is set. * * @since 4.05 */ private static function maybe_add_required( &$f ) { if ( $f['required'] && ! isset( $f['field_options']['required_indicator'] ) ) { $f['field_options']['required_indicator'] = '*'; } } /** * Update the current in_section value at the beginning of the field loop * * @since 2.0.25 * @param int $in_section * @param array $f */ private static function maybe_update_in_section_variable( &$in_section, &$f ) { // If we're at the end of a section, switch $in_section is 0 if ( in_array( $f['type'], array( 'end_divider', 'break', 'form' ) ) ) { $in_section = 0; } // Update the current field's in_section value if ( ! isset( $f['field_options']['in_section'] ) ) { $f['field_options']['in_section'] = $in_section; } // If we're starting a new section, switch $in_section to ID of divider if ( $f['type'] === 'divider' ) { $in_section = $f['id']; } } /** * Switch the form_select on a repeating field or embedded form if it needs to be switched * * @since 2.0.16 * * @param array $f * @param array $imported */ private static function maybe_update_form_select( &$f, $imported ) { if ( ! isset( $imported['forms'] ) ) { return; } if ( $f['type'] === 'form' || ( $f['type'] === 'divider' && FrmField::is_option_true( $f['field_options'], 'repeat' ) ) ) { if ( FrmField::is_option_true( $f['field_options'], 'form_select' ) ) { $form_select = (int) $f['field_options']['form_select']; if ( isset( $imported['forms'][ $form_select ] ) ) { $f['field_options']['form_select'] = $imported['forms'][ $form_select ]; } } } } /** * Update the get_values_form setting if the form was imported * * @since 2.01.0 * * @param array $imported * @param array $f */ private static function maybe_update_get_values_form_setting( $imported, &$f ) { if ( ! isset( $imported['forms'] ) ) { return; } if ( FrmField::is_option_true_in_array( $f['field_options'], 'get_values_form' ) ) { $old_form = $f['field_options']['get_values_form']; if ( isset( $imported['forms'][ $old_form ] ) ) { $f['field_options']['get_values_form'] = $imported['forms'][ $old_form ]; } } } /** * If field settings have been migrated, update the values during import. * * @since 4.0 */ private static function run_field_migrations( &$f ) { self::migrate_placeholders( $f ); $f = apply_filters( 'frm_import_xml_field', $f ); } /** * @since 4.0 */ private static function migrate_placeholders( &$f ) { $update_values = self::migrate_field_placeholder( $f, 'clear_on_focus' ); foreach ( $update_values as $k => $v ) { $f[ $k ] = $v; } $update_values = self::migrate_field_placeholder( $f, 'default_blank' ); foreach ( $update_values as $k => $v ) { $f[ $k ] = $v; } } /** * Move clear_on_focus or default_blank to placeholder. * Also called during database migration in FrmMigrate. * * @since 4.0 * @return array */ public static function migrate_field_placeholder( $field, $type ) { $field = (array) $field; $field_options = $field['field_options']; if ( empty( $field_options[ $type ] ) || empty( $field['default_value'] ) ) { return array(); } $field_options['placeholder'] = is_array( $field['default_value'] ) ? reset( $field['default_value'] ) : $field['default_value']; unset( $field_options['default_blank'], $field_options['clear_on_focus'] ); $changes = array( 'field_options' => $field_options, 'default_value' => '', ); // If a dropdown placeholder was used, remove the option so it won't be included twice. $options = $field['options']; if ( $type === 'default_blank' && is_array( $options ) ) { $default_value = $field['default_value']; if ( is_array( $default_value ) ) { $default_value = reset( $default_value ); } foreach ( $options as $opt_key => $opt ) { if ( is_array( $opt ) ) { $opt = isset( $opt['value'] ) ? $opt['value'] : ( isset( $opt['label'] ) ? $opt['label'] : reset( $opt ) ); } if ( $opt == $default_value ) { unset( $options[ $opt_key ] ); break; } } $changes['options'] = $options; } return $changes; } /** * Create an imported field * * @since 2.0.25 * * @param array $f * @param array $imported */ private static function create_imported_field( $f, &$imported ) { $f = self::update_field_options_with_defaults( $f ); if ( is_callable( 'FrmProFileImport::import_attachment' ) ) { $f = self::maybe_import_images_for_options( $f ); } $new_id = FrmField::create( $f ); if ( $new_id != false ) { ++$imported['imported']['fields']; do_action( 'frm_after_field_is_imported', $f, $new_id ); } } /** * Import images for radio buttons and checkboxes from image src if available. * * @since 5.5.1 * * @param array $field * @return array */ private static function maybe_import_images_for_options( $field ) { if ( empty( $field['options'] ) || ! is_array( $field['options'] ) ) { return $field; } foreach ( $field['options'] as $key => $option ) { if ( ! is_array( $option ) || empty( $option['src'] ) ) { continue; } $field_object = (object) $field; // Fake the file type as FrmProImport::import_attachment checks for file type. $field_object->type = 'file'; $image_id = FrmProFileImport::import_attachment( $option['src'], $field_object ); // Remove the src from options as it isn't required after import. unset( $field['options'][ $key ]['src'] ); if ( is_numeric( $image_id ) ) { $field['options'][ $key ]['image'] = $image_id; } } return $field; } /** * Fix field ids for fields that already exist prior to import. * * @since 4.07 * @param int $form_id * @param array $keys_by_original_field_id */ protected static function maybe_update_field_ids( $form_id, $keys_by_original_field_id ) { global $frm_duplicate_ids; $former_duplicate_ids = $frm_duplicate_ids; $where = array( array( 'or' => 1, 'fi.form_id' => $form_id, 'fr.parent_form_id' => $form_id, ), ); $fields = FrmField::getAll( $where, 'field_order' ); $field_id_by_key = wp_list_pluck( $fields, 'id', 'field_key' ); foreach ( $fields as $field ) { $before = (array) clone $field; $field = (array) $field; $frm_duplicate_ids = $keys_by_original_field_id; $after = FrmFieldsHelper::switch_field_ids( $field ); if ( $before['field_options'] !== $after['field_options'] ) { $frm_duplicate_ids = $field_id_by_key; $after = FrmFieldsHelper::switch_field_ids( $after ); if ( $before['field_options'] !== $after['field_options'] ) { FrmField::update( $field['id'], array( 'field_options' => $after['field_options'] ) ); } } } $frm_duplicate_ids = $former_duplicate_ids; } /** * Updates the custom style setting on import * Convert the post slug to an ID * * @since 2.0.19 * * @param array $form */ private static function update_custom_style_setting_on_import( &$form ) { if ( ! isset( $form['options']['custom_style'] ) ) { return; } if ( is_numeric( $form['options']['custom_style'] ) && 1 === intval( $form['options']['custom_style'] ) ) { // Set to default $form['options']['custom_style'] = 1; } else { // Replace the style name with the style ID on import global $wpdb; $table = $wpdb->prefix . 'posts'; $where = array( 'post_name' => $form['options']['custom_style'], 'post_type' => 'frm_styles', ); $select = 'ID'; $style_id = FrmDb::get_var( $table, $where, $select ); if ( $style_id ) { $form['options']['custom_style'] = $style_id; } else { // save the old style to maybe update after styles import $form['options']['old_style'] = $form['options']['custom_style']; // Set to default $form['options']['custom_style'] = 1; } }//end if } /** * After styles are imported, check for any forms that were linked * and link them back up. * * @since 2.2.7 */ private static function update_custom_style_setting_after_import( $form_id ) { $form = FrmForm::getOne( $form_id ); if ( $form && isset( $form->options['old_style'] ) ) { $form = (array) $form; $saved_style = $form['options']['custom_style']; $form['options']['custom_style'] = $form['options']['old_style']; self::update_custom_style_setting_on_import( $form ); $has_changed = ( $form['options']['custom_style'] != $saved_style && $form['options']['custom_style'] != $form['options']['old_style'] ); if ( $has_changed ) { FrmForm::update( $form['id'], $form ); } } } /** * Handle import for all posts. This includes views, styles, pages, and form actions. * * @param SimpleXMLElement $views * @param array $imported * @return array */ public static function import_xml_views( $views, $imported ) { $imported['posts'] = array(); $form_action_type = FrmFormActionsController::$action_post_type; $post_types = array( 'frm_display' => 'views', $form_action_type => 'actions', 'frm_styles' => 'styles', ); $view_ids = array(); $posts_with_shortcodes = array(); foreach ( $views as $item ) { $post = array( 'post_title' => (string) $item->title, 'post_name' => (string) $item->post_name, 'post_type' => (string) $item->post_type, 'post_password' => (string) $item->post_password, 'guid' => (string) $item->guid, 'post_status' => (string) $item->status, 'post_author' => FrmAppHelper::get_user_id_param( (string) $item->post_author ), 'post_id' => (int) $item->post_id, 'post_parent' => (int) $item->post_parent, 'menu_order' => (int) $item->menu_order, 'post_content' => FrmFieldsHelper::switch_field_ids( (string) $item->content ), 'post_excerpt' => FrmFieldsHelper::switch_field_ids( (string) $item->excerpt ), 'is_sticky' => (string) $item->is_sticky, 'comment_status' => (string) $item->comment_status, 'post_date' => (string) $item->post_date, 'post_date_gmt' => (string) $item->post_date_gmt, 'ping_status' => (string) $item->ping_status, 'postmeta' => array(), 'layout' => array(), 'tax_input' => array(), ); $post['post_content'] = self::switch_form_ids( $post['post_content'], $imported['forms'] ); $old_id = $post['post_id']; self::populate_post( $post, $item, $imported ); unset( $item ); $post_id = false; if ( $post['post_type'] === $form_action_type ) { $action_control = FrmFormActionsController::get_form_actions( $post['post_excerpt'] ); if ( $action_control && is_object( $action_control ) ) { $post_id = $action_control->maybe_create_action( $post, $imported['form_status'] ); } unset( $action_control ); } elseif ( $post['post_type'] === 'frm_styles' ) { // Properly encode post content before inserting the post $post['post_content'] = FrmAppHelper::maybe_json_decode( $post['post_content'] ); $post['post_content'] = FrmAppHelper::prepare_and_encode( $post['post_content'] ); // Store template data additionally to a postmeta that can be used to revert the style to default template style. $post['postmeta']['frm_style_default'] = $post['post_content']; // Create/update post now $post_id = wp_insert_post( $post ); } else { if ( $post['post_type'] === 'frm_display' ) { $post['post_content'] = self::maybe_prepare_json_view_content( $post['post_content'] ); } elseif ( 'page' === $post['post_type'] && isset( $imported['posts'][ $post['post_parent'] ] ) ) { $post['post_parent'] = $imported['posts'][ $post['post_parent'] ]; } // Create/update post now $post_id = wp_insert_post( $post ); }//end if if ( ! is_numeric( $post_id ) ) { continue; } if ( false !== strpos( $post['post_content'], '[display-frm-data' ) || false !== strpos( $post['post_content'], '[formidable' ) ) { $posts_with_shortcodes[ $post_id ] = $post; } self::update_postmeta( $post, $post_id ); self::update_layout( $post, $post_id ); $this_type = 'posts'; if ( isset( $post_types[ $post['post_type'] ] ) ) { $this_type = $post_types[ $post['post_type'] ]; } if ( isset( $post['ID'] ) && $post_id == $post['ID'] ) { ++$imported['updated'][ $this_type ]; } else { ++$imported['imported'][ $this_type ]; } $imported['posts'][ $old_id ] = $post_id; if ( $post['post_type'] === 'frm_display' ) { $view_ids[ $old_id ] = $post_id; } do_action( 'frm_after_import_view', $post_id, $post ); unset( $post ); }//end foreach if ( $posts_with_shortcodes && $view_ids ) { self::maybe_switch_view_ids_after_importing_posts( $posts_with_shortcodes, $view_ids ); } unset( $posts_with_shortcodes, $view_ids ); if ( ! empty( $imported['forms'] ) ) { // clear imported forms style cache to make sure the new styles are applied to the forms self::clear_forms_style_caches( $imported['forms'] ); } self::maybe_update_stylesheet( $imported ); flush_rewrite_rules(); return $imported; } /** * Clears styles from cache for imported forms * * @param array $imported_forms */ private static function clear_forms_style_caches( $imported_forms ) { $where = array( 'id' => $imported_forms, 'options LIKE' => '"old_style"', ); $forms = FrmDb::get_results( 'frm_forms', $where ); foreach ( $forms as $form ) { FrmAppHelper::unserialize_or_decode( $form->options ); if ( ! $form->options ) { continue; } $where = array( 'post_name' => $form->options['old_style'], 'post_type' => FrmStylesController::$post_type, ); $select = 'ID'; $cache_key = FrmDb::generate_cache_key( $where, array( 'limit' => 1 ), $select, 'var' ); FrmDb::delete_cache_and_transient( $cache_key, 'post' ); } } /** * Replace old form ids with new ones in a string. * * @param string $string * @param array<int> $form_ids new form ids indexed by old form id. * @return string */ private static function switch_form_ids( $string, $form_ids ) { if ( false === strpos( $string, '[formidable' ) ) { // Skip string replacing if there are no form shortcodes in string. return $string; } foreach ( $form_ids as $old_id => $new_id ) { $string = str_replace( array( '[formidable id="' . $old_id . '"', '[formidable id=' . $old_id . ']', '[formidable id=' . $old_id . ' ', '"formId":"' . $old_id . '"', ), array( '[formidable id="' . $new_id . '"', '[formidable id=' . $new_id . ']', '[formidable id=' . $new_id . ' ', '"formId":"' . $new_id . '"', ), $string ); } return $string; } /** * @param array<array> $posts_with_shortcodes indexed by current post id. * @param array<int> $view_ids new view ids indexed by old view id. * @return void */ private static function maybe_switch_view_ids_after_importing_posts( $posts_with_shortcodes, $view_ids ) { foreach ( $posts_with_shortcodes as $imported_post_id => $post ) { $post_content = self::switch_view_ids( $post['post_content'], $view_ids ); if ( $post_content === $post['post_content'] ) { continue; } wp_update_post( array( 'ID' => $imported_post_id, 'post_content' => $post_content, ) ); } } /** * Replace old view ids with new ones in a string. * * @param string $string * @param array<int> $view_ids new view ids indexed by old view id. * @return string */ private static function switch_view_ids( $string, $view_ids ) { if ( false === strpos( $string, '[display-frm-data' ) ) { // Skip string replacing if there are no view shortcodes in string. return $string; } foreach ( $view_ids as $old_id => $new_id ) { $string = str_replace( array( '[display-frm-data id="' . $old_id . '"', '[display-frm-data id=' . $old_id . ']', '[display-frm-data id=' . $old_id . ' ', '"viewId":"' . $old_id . '"', ), array( '[display-frm-data id="' . $new_id . '"', '[display-frm-data id=' . $new_id . ']', '[display-frm-data id=' . $new_id . ' ', '"viewId":"' . $new_id . '"', ), $string ); unset( $old_id, $new_id ); } return $string; } /** * @param string $content * @return string */ private static function maybe_prepare_json_view_content( $content ) { $maybe_decoded = FrmAppHelper::maybe_json_decode( $content ); if ( is_array( $maybe_decoded ) && isset( $maybe_decoded[0] ) && isset( $maybe_decoded[0]['box'] ) ) { return FrmAppHelper::prepare_and_encode( $maybe_decoded ); } return $content; } private static function populate_post( &$post, $item, $imported ) { if ( isset( $item->attachment_url ) ) { $post['attachment_url'] = (string) $item->attachment_url; } if ( $post['post_type'] == FrmFormActionsController::$action_post_type && isset( $imported['forms'][ (int) $post['menu_order'] ] ) ) { // update to new form id $post['menu_order'] = $imported['forms'][ (int) $post['menu_order'] ]; } // Don't allow default styles to take over a site's default style if ( 'frm_styles' == $post['post_type'] ) { $post['menu_order'] = 0; } foreach ( $item->postmeta as $meta ) { self::populate_postmeta( $post, $meta, $imported ); unset( $meta ); } foreach ( $item->layout as $layout ) { self::populate_layout( $post, $layout ); unset( $layout ); } self::populate_taxonomies( $post, $item ); self::maybe_editing_post( $post ); } /** * @param array $post * @param stdClass $meta * @param array $imported */ private static function populate_postmeta( &$post, $meta, $imported ) { global $frm_duplicate_ids; $m = array( 'key' => (string) $meta->meta_key, 'value' => (string) $meta->meta_value, ); // Switch old form and field ids to new ones. if ( 'frm_form_id' === $m['key'] && isset( $imported['forms'][ (int) $m['value'] ] ) ) { $m['value'] = $imported['forms'][ (int) $m['value'] ]; } else { $m['value'] = FrmAppHelper::maybe_json_decode( $m['value'] ); if ( ! empty( $frm_duplicate_ids ) ) { if ( 'frm_dyncontent' === $m['key'] ) { $m['value'] = self::maybe_prepare_json_view_content( $m['value'] ); $m['value'] = FrmFieldsHelper::switch_field_ids( $m['value'] ); } elseif ( 'frm_options' === $m['key'] ) { foreach ( array( 'date_field_id', 'edate_field_id' ) as $setting_name ) { if ( isset( $m['value'][ $setting_name ] ) && is_numeric( $m['value'][ $setting_name ] ) && isset( $frm_duplicate_ids[ $m['value'][ $setting_name ] ] ) ) { $m['value'][ $setting_name ] = $frm_duplicate_ids[ $m['value'][ $setting_name ] ]; } } if ( ! empty( $m['value']['map_address_fields'] ) ) { foreach ( $m['value']['map_address_fields'] as $address_field_key => $address_field_id ) { if ( isset( $frm_duplicate_ids[ $address_field_id ] ) ) { $m['value']['map_address_fields'][ $address_field_key ] = $frm_duplicate_ids[ $address_field_id ]; } } } if ( ! empty( $m['value']['calendar_options'] ) ) { foreach ( $m['value']['calendar_options'] as $calendar_option_group_key => $calendar_option ) { if ( isset( $frm_duplicate_ids[ $calendar_option['value'] ] ) ) { $m['value']['calendar_options'][ $calendar_option_group_key ]['value'] = $frm_duplicate_ids[ $calendar_option['value'] ]; } } } $check_dup_array = array(); if ( ! empty( $m['value']['order_by'] ) ) { if ( is_numeric( $m['value']['order_by'] ) && isset( $frm_duplicate_ids[ $m['value']['order_by'] ] ) ) { $m['value']['order_by'] = $frm_duplicate_ids[ $m['value']['order_by'] ]; } elseif ( is_array( $m['value']['order_by'] ) ) { $check_dup_array[] = 'order_by'; } } if ( ! empty( $m['value']['where'] ) ) { $check_dup_array[] = 'where'; } foreach ( $check_dup_array as $check_k ) { foreach ( (array) $m['value'][ $check_k ] as $mk => $mv ) { if ( isset( $frm_duplicate_ids[ $mv ] ) ) { $m['value'][ $check_k ][ $mk ] = $frm_duplicate_ids[ $mv ]; } unset( $mk, $mv ); } } }//end if }//end if }//end if if ( ! is_array( $m['value'] ) ) { $m['value'] = FrmAppHelper::maybe_json_decode( $m['value'] ); } $post['postmeta'][ (string) $meta->meta_key ] = $m['value']; } private static function populate_layout( &$post, $layout ) { $post['layout'][ (string) $layout->type ] = (string) $layout->data; } /** * Add terms to post * * @param array $post By reference. * @param object $item The XML object data. */ private static function populate_taxonomies( &$post, $item ) { foreach ( $item->category as $c ) { $att = $c->attributes(); if ( ! isset( $att['nicename'] ) ) { continue; } $taxonomy = (string) $att['domain']; if ( is_taxonomy_hierarchical( $taxonomy ) ) { $name = (string) $att['nicename']; $h_term = get_term_by( 'slug', $name, $taxonomy ); if ( $h_term ) { $name = $h_term->term_id; } unset( $h_term ); } else { $name = (string) $c; } if ( ! isset( $post['tax_input'][ $taxonomy ] ) ) { $post['tax_input'][ $taxonomy ] = array(); } $post['tax_input'][ $taxonomy ][] = $name; unset( $name ); }//end foreach } /** * Edit post if the key and created time match. */ private static function maybe_editing_post( &$post ) { $match_by = array( 'post_type' => $post['post_type'], 'name' => $post['post_name'], 'post_status' => $post['post_status'], 'posts_per_page' => 1, ); if ( in_array( $post['post_status'], array( 'trash', 'draft' ), true ) ) { $match_by['include'] = $post['post_id']; unset( $match_by['name'] ); } $editing = get_posts( $match_by ); if ( ! empty( $editing ) && current( $editing )->post_date == $post['post_date'] ) { // set the id of the post to edit $post['ID'] = current( $editing )->ID; } } /** * @param array $post * @param int $post_id * @return void */ private static function update_postmeta( &$post, $post_id ) { foreach ( $post['postmeta'] as $k => $v ) { switch ( $k ) { case '_edit_last': $v = FrmAppHelper::get_user_id_param( $v ); break; case '_thumbnail_id': if ( FrmAppHelper::pro_is_installed() ) { // Change the attachment ID. $field_obj = FrmFieldFactory::get_field_type( 'file' ); $v = $field_obj->get_file_id( $v ); } break; case 'frm_dyncontent': if ( is_array( $v ) ) { $v = json_encode( $v ); } break; case 'frm_param': add_rewrite_endpoint( $v, EP_PERMALINK | EP_PAGES ); break; }//end switch update_post_meta( $post_id, $k, $v ); unset( $k, $v ); }//end foreach } /** * @param array $post * @param int $post_id */ private static function update_layout( &$post, $post_id ) { if ( is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) { $listing_layout = ! empty( $post['layout']['listing'] ) ? json_decode( $post['layout']['listing'], true ) : array(); $detail_layout = ! empty( $post['layout']['detail'] ) ? json_decode( $post['layout']['detail'], true ) : array(); if ( $listing_layout || $detail_layout ) { FrmViewsLayout::maybe_create_layouts_for_view( $post_id, $listing_layout, $detail_layout ); } } } private static function maybe_update_stylesheet( $imported ) { $new_styles = ! empty( $imported['imported']['styles'] ); $updated_styles = ! empty( $imported['updated']['styles'] ); if ( $new_styles || $updated_styles ) { if ( is_admin() && function_exists( 'get_filesystem_method' ) ) { $frm_style = new FrmStyle(); $frm_style->update( 'default' ); } foreach ( $imported['forms'] as $form_id ) { self::update_custom_style_setting_after_import( $form_id ); } } } /** * @param mixed $result * @param string $message * @param array $errors */ public static function parse_message( $result, &$message, &$errors ) { if ( is_wp_error( $result ) ) { $errors[] = $result->get_error_message(); // Remove the SimpleXML_parse_error from the WP_Error object to avoid // displaying duplicate error messages from $result->get_error_message() $error_codes = $result->get_error_codes(); $error_details = array(); foreach ( $error_codes as $error_code ) { // Clone WP_Error data because WP_Error removes all error messages and data // associated with the specified error code when an item is removed. // Source: https://developer.wordpress.org/reference/classes/wp_error/remove/#source $error_details = $result->get_error_data( $error_code ); if ( $error_code === 'SimpleXML_parse_error' ) { $result->remove( $error_code ); break; } } if ( ! empty( $error_details ) ) { $errors[] = '<br />' . esc_html_x( 'Error details:', 'import xml message', 'formidable' ) . '<br />' . esc_html( print_r( $error_details, 1 ) ); } return; }//end if if ( ! $result ) { return; } if ( ! is_array( $result ) ) { $message = is_string( $result ) ? $result : htmlentities( print_r( $result, 1 ) ); return; } $t_strings = array( 'imported' => __( 'Imported', 'formidable' ), 'updated' => __( 'Updated', 'formidable' ), ); $message = '<ul>'; foreach ( $result as $type => $results ) { if ( ! isset( $t_strings[ $type ] ) ) { // only print imported and updated continue; } $s_message = array(); foreach ( $results as $k => $m ) { self::item_count_message( $m, $k, $s_message ); unset( $k, $m ); } if ( ! empty( $s_message ) ) { $message .= '<li><strong>' . $t_strings[ $type ] . ':</strong> '; $message .= implode( ', ', $s_message ); $message .= '</li>'; } } if ( $message === '<ul>' ) { $message = ''; $errors[] = __( 'Nothing was imported or updated', 'formidable' ); } else { self::add_form_link_to_message( $result, $message ); /** * @since 5.3 * * @param string $message * @param array $result */ $message = apply_filters( 'frm_xml_parsed_message', $message, $result ); $message .= '</ul>'; } } /** * @param int $m * @param string $type * @param array<string> $s_message */ public static function item_count_message( $m, $type, &$s_message ) { if ( ! $m ) { return; } $strings = array( /* translators: %1$s: Number of items */ 'forms' => sprintf( _n( '%1$s Form', '%1$s Forms', $m, 'formidable' ), $m ), /* translators: %1$s: Number of items */ 'fields' => sprintf( _n( '%1$s Field', '%1$s Fields', $m, 'formidable' ), $m ), /* translators: %1$s: Number of items */ 'items' => sprintf( _n( '%1$s Entry', '%1$s Entries', $m, 'formidable' ), $m ), /* translators: %1$s: Number of items */ 'views' => sprintf( _n( '%1$s View', '%1$s Views', $m, 'formidable' ), $m ), /* translators: %1$s: Number of items */ 'posts' => sprintf( _n( '%1$s Page/Post', '%1$s Pages/Posts', $m, 'formidable' ), $m ), /* translators: %1$s: Number of items */ 'styles' => sprintf( _n( '%1$s Style', '%1$s Styles', $m, 'formidable' ), $m ), /* translators: %1$s: Number of items */ 'terms' => sprintf( _n( '%1$s Term', '%1$s Terms', $m, 'formidable' ), $m ), /* translators: %1$s: Number of items */ 'actions' => sprintf( _n( '%1$s Form Action', '%1$s Form Actions', $m, 'formidable' ), $m ), ); if ( isset( $strings[ $type ] ) ) { $s_message[] = $strings[ $type ]; } else { $string = ' ' . $m . ' ' . ucfirst( $type ); /** * @since 5.3 * * @param string $string Message string for imported item. * @param int $m Number of item that was imported. * } */ $string = apply_filters( 'frm_xml_' . $type . '_count_message', $string, $m ); $s_message[] = $string; } } /** * If a single form was imported, include a link in the success message. * * @since 4.0 * @param array $result The response from the XML import. * @param string $message The response shown on the page after import. */ private static function add_form_link_to_message( $result, &$message ) { $total_forms = $result['imported']['forms'] + $result['updated']['forms']; if ( $total_forms > 1 ) { return; } $primary_form = reset( $result['forms'] ); if ( ! empty( $primary_form ) ) { $primary_form = FrmForm::getOne( $primary_form ); $form_id = empty( $primary_form->parent_form_id ) ? $primary_form->id : $primary_form->parent_form_id; $message .= '<li><a href="' . esc_url( FrmForm::get_edit_link( $form_id ) ) . '">' . esc_html__( 'Go to imported form', 'formidable' ) . '</a></li>'; } } /** * Prepare the form options for export * * @since 2.0.19 * * @param string $options * * @return string */ public static function prepare_form_options_for_export( $options ) { FrmAppHelper::unserialize_or_decode( $options ); // Change custom_style to the post_name instead of ID (1 may be a string) $not_default = isset( $options['custom_style'] ) && 1 != $options['custom_style']; if ( $not_default ) { global $wpdb; $table = $wpdb->prefix . 'posts'; $where = array( 'ID' => $options['custom_style'] ); $select = 'post_name'; $style_name = FrmDb::get_var( $table, $where, $select ); if ( $style_name ) { $options['custom_style'] = $style_name; } else { $options['custom_style'] = 1; } } self::remove_default_form_options( $options ); $options = serialize( $options ); return self::cdata( $options ); } /** * If the saved value is the same as the default, remove it from the export * This keeps file size down and prevents overriding global settings after import * * @since 3.06 */ private static function remove_default_form_options( &$options ) { $defaults = FrmFormsHelper::get_default_opts(); if ( is_callable( 'FrmProFormsHelper::get_default_opts' ) ) { $defaults += FrmProFormsHelper::get_default_opts(); } self::remove_defaults( $defaults, $options ); } /** * Remove extra settings from field to keep file size down * * @since 3.06 */ public static function prepare_field_for_export( &$field ) { self::remove_default_field_options( $field ); self::add_image_src_to_image_options( $field ); } /** * Remove defaults from field options too * * @since 3.06 */ private static function remove_default_field_options( &$field ) { $defaults = self::default_field_options( $field->type ); if ( empty( $defaults['blank'] ) ) { $global_settings = new FrmSettings(); $global_defaults = $global_settings->default_options(); $defaults['blank'] = $global_defaults['blank_msg']; } $options = $field->field_options; FrmAppHelper::unserialize_or_decode( $options ); self::remove_defaults( $defaults, $options ); self::remove_default_html( 'custom_html', $defaults, $options ); // Get variations on the defaults. if ( isset( $options['invalid'] ) ) { $defaults = array( /* translators: %s: Field name */ 'invalid' => sprintf( __( '%s is invalid', 'formidable' ), $field->name ), ); self::remove_defaults( $defaults, $options ); } $field->field_options = serialize( $options ); } /** * Add image "src" key to each image option so the image can be imported to another website. * * @since 5.5.1 * * @param stdClass $field * @return void */ private static function add_image_src_to_image_options( $field ) { if ( empty( $field->options ) || false === strpos( $field->options, 'image' ) ) { return; } $updated = false; $options = $field->options; FrmAppHelper::unserialize_or_decode( $options ); if ( ! $options || ! is_array( $options ) ) { return; } foreach ( $options as $key => $option ) { if ( is_array( $option ) && ! empty( $option['image'] ) ) { $options[ $key ]['src'] = wp_get_attachment_url( $option['image'] ); $updated = true; } } if ( $updated ) { $field->options = maybe_serialize( $options ); } } /** * @since 3.06.03 */ private static function default_field_options( $type ) { $defaults = FrmFieldsHelper::get_default_field_options( $type ); if ( empty( $defaults['custom_html'] ) ) { $defaults['custom_html'] = FrmFieldsHelper::get_default_html( $type ); } return $defaults; } /** * Compare the default array to the saved values and * remove if they are the same * * @since 3.06 */ private static function remove_defaults( $defaults, &$saved ) { foreach ( $saved as $key => $value ) { if ( isset( $defaults[ $key ] ) && $defaults[ $key ] === $value ) { unset( $saved[ $key ] ); } } } /** * The line endings may prevent html from being equal when it should * * @since 3.06 */ private static function remove_default_html( $html_name, $defaults, &$options ) { if ( ! isset( $options[ $html_name ] ) || ! isset( $defaults[ $html_name ] ) ) { return; } $old_html = str_replace( "\r\n", "\n", $options[ $html_name ] ); $default_html = $defaults[ $html_name ]; if ( $old_html == $default_html ) { unset( $options[ $html_name ] ); return; } // Account for some of the older field default HTML. $default_html = str_replace( ' id="frm_desc_field_[key]"', '', $default_html ); if ( $old_html == $default_html ) { unset( $options[ $html_name ] ); } } public static function cdata( $str ) { FrmAppHelper::unserialize_or_decode( $str ); if ( is_array( $str ) ) { $str = json_encode( $str ); } elseif ( seems_utf8( $str ) === false ) { $str = FrmAppHelper::maybe_utf8_encode( $str ); } if ( is_numeric( $str ) ) { return $str; } self::remove_invalid_characters_from_xml( $str ); // $str = ent2ncr(esc_html( $str)); $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>'; return $str; } /** * Remove <US> character (unit separator) from exported strings * * @since 2.0.22 * * @param string $str */ private static function remove_invalid_characters_from_xml( &$str ) { // Remove <US> character $str = str_replace( '\x1F', '', $str ); } public static function migrate_form_settings_to_actions( $form_options, $form_id, &$imported = array(), $switch = false ) { // Get post type $post_type = FrmFormActionsController::$action_post_type; // Set up imported index, if not set up yet if ( ! isset( $imported['imported']['actions'] ) ) { $imported['imported']['actions'] = 0; } // Migrate post settings to action self::migrate_post_settings_to_action( $form_options, $form_id, $post_type, $imported, $switch ); // Migrate email settings to action self::migrate_email_settings_to_action( $form_options, $form_id, $post_type, $imported, $switch ); } /** * Migrate post settings to form action * * @param array $form_options * @param int $form_id * @param string $post_type * @param array $imported * @param bool $switch */ private static function migrate_post_settings_to_action( $form_options, $form_id, $post_type, &$imported, $switch ) { if ( ! isset( $form_options['create_post'] ) || ! $form_options['create_post'] ) { return; } $new_action = array( 'post_type' => $post_type, 'post_excerpt' => 'wppost', 'post_title' => __( 'Create Posts', 'formidable' ), 'menu_order' => $form_id, 'post_status' => 'publish', 'post_content' => array(), 'post_name' => $form_id . '_wppost_1', ); $post_settings = array( 'post_type', 'post_category', 'post_content', 'post_excerpt', 'post_title', 'post_name', 'post_date', 'post_status', 'post_custom_fields', 'post_password', 'post_parent', ); foreach ( $post_settings as $post_setting ) { if ( isset( $form_options[ $post_setting ] ) ) { $new_action['post_content'][ $post_setting ] = $form_options[ $post_setting ]; } unset( $post_setting ); } $new_action['event'] = array( 'create', 'update' ); if ( $switch ) { // Fields with string or int saved. $basic_fields = array( 'post_title', 'post_content', 'post_excerpt', 'post_password', 'post_date', 'post_status', 'post_parent', ); // Fields with arrays saved. $array_fields = array( 'post_category', 'post_custom_fields' ); $new_action['post_content'] = self::switch_action_field_ids( $new_action['post_content'], $basic_fields, $array_fields ); } $new_action['post_content'] = json_encode( $new_action['post_content'] ); $exists = get_posts( array( 'name' => $new_action['post_name'], 'post_type' => $new_action['post_type'], 'post_status' => $new_action['post_status'], 'numberposts' => 1, ) ); if ( ! $exists ) { // this isn't an email, but we need to use a class that will always be included FrmDb::save_json_post( $new_action ); ++$imported['imported']['actions']; } } /** * Switch old field IDs for new field IDs in emails and post * * @since 2.0 * * @param array $post_content Check for old field IDs. * @param array $basic_fields Fields with string or int saved. * @param array $array_fields Fields with arrays saved. * * @return string $post_content - new field IDs */ private static function switch_action_field_ids( $post_content, $basic_fields, $array_fields = array() ) { global $frm_duplicate_ids; // If there aren't IDs that were switched, end now if ( ! $frm_duplicate_ids ) { return; } // Get old IDs $old = array_keys( $frm_duplicate_ids ); // Get new IDs $new = array_values( $frm_duplicate_ids ); // Do a str_replace with each item to set the new IDs foreach ( $post_content as $key => $setting ) { if ( ! is_array( $setting ) && in_array( $key, $basic_fields ) ) { // Replace old IDs with new IDs $post_content[ $key ] = str_replace( $old, $new, $setting ); } elseif ( is_array( $setting ) && in_array( $key, $array_fields ) ) { foreach ( $setting as $k => $val ) { // Replace old IDs with new IDs $post_content[ $key ][ $k ] = str_replace( $old, $new, $val ); } } unset( $key, $setting ); } return $post_content; } private static function migrate_email_settings_to_action( $form_options, $form_id, $post_type, &$imported, $switch ) { // No old notifications or autoresponders to carry over if ( ! isset( $form_options['auto_responder'] ) && ! isset( $form_options['notification'] ) && ! isset( $form_options['email_to'] ) ) { return; } // Initialize notifications array $notifications = array(); // Migrate regular notifications self::migrate_notifications_to_action( $form_options, $form_id, $notifications ); // Migrate autoresponders self::migrate_autoresponder_to_action( $form_options, $form_id, $notifications ); if ( empty( $notifications ) ) { return; } foreach ( $notifications as $new_notification ) { $new_notification['post_type'] = $post_type; $new_notification['post_excerpt'] = 'email'; $new_notification['post_title'] = __( 'Email Notification', 'formidable' ); $new_notification['menu_order'] = $form_id; $new_notification['post_status'] = 'publish'; // Switch field IDs and keys, if needed if ( $switch ) { // Switch field IDs in email conditional logic self::switch_email_condition_field_ids( $new_notification['post_content'] ); // Switch all other field IDs in email $new_notification['post_content'] = FrmFieldsHelper::switch_field_ids( $new_notification['post_content'] ); } $new_notification['post_content'] = FrmAppHelper::prepare_and_encode( $new_notification['post_content'] ); $exists = get_posts( array( 'name' => $new_notification['post_name'], 'post_type' => $new_notification['post_type'], 'post_status' => $new_notification['post_status'], 'numberposts' => 1, ) ); if ( empty( $exists ) ) { FrmDb::save_json_post( $new_notification ); ++$imported['imported']['actions']; } unset( $new_notification ); }//end foreach self::remove_deprecated_notification_settings( $form_id, $form_options ); } /** * Remove deprecated notification settings after migration * * @since 2.05 * * @param int|string $form_id * @param array $form_options */ private static function remove_deprecated_notification_settings( $form_id, $form_options ) { $delete_settings = array( 'notification', 'autoresponder', 'email_to' ); foreach ( $delete_settings as $index ) { if ( isset( $form_options[ $index ] ) ) { unset( $form_options[ $index ] ); } } FrmForm::update( $form_id, array( 'options' => $form_options ) ); } private static function migrate_notifications_to_action( $form_options, $form_id, &$notifications ) { if ( ! isset( $form_options['notification'] ) && ! empty( $form_options['email_to'] ) ) { // add old settings into notification array $form_options['notification'] = array( 0 => $form_options ); } elseif ( isset( $form_options['notification']['email_to'] ) ) { // make sure it's in the correct format $form_options['notification'] = array( 0 => $form_options['notification'] ); } if ( isset( $form_options['notification'] ) && is_array( $form_options['notification'] ) ) { foreach ( $form_options['notification'] as $email_key => $notification ) { $atts = array( 'email_to' => '', 'reply_to' => '', 'reply_to_name' => '', 'event' => '', 'form_id' => $form_id, 'email_key' => $email_key, ); // Format the email data self::format_email_data( $atts, $notification ); if ( isset( $notification['twilio'] ) && $notification['twilio'] ) { do_action( 'frm_create_twilio_action', $atts, $notification ); } // Setup the new notification $new_notification = array(); self::setup_new_notification( $new_notification, $notification, $atts ); $notifications[] = $new_notification; }//end foreach }//end if } private static function format_email_data( &$atts, $notification ) { // Format email_to self::format_email_to_data( $atts, $notification ); // Format the reply to email and name $reply_fields = array( 'reply_to' => '', 'reply_to_name' => '', ); foreach ( $reply_fields as $f => $val ) { if ( isset( $notification[ $f ] ) ) { $atts[ $f ] = $notification[ $f ]; if ( 'custom' == $notification[ $f ] ) { $atts[ $f ] = $notification[ 'cust_' . $f ]; } elseif ( is_numeric( $atts[ $f ] ) && ! empty( $atts[ $f ] ) ) { $atts[ $f ] = '[' . $atts[ $f ] . ']'; } } unset( $f, $val ); } // Format event $atts['event'] = array( 'create' ); if ( isset( $notification['update_email'] ) && 1 == $notification['update_email'] ) { $atts['event'][] = 'update'; } elseif ( isset( $notification['update_email'] ) && 2 == $notification['update_email'] ) { $atts['event'] = array( 'update' ); } } private static function format_email_to_data( &$atts, $notification ) { if ( isset( $notification['email_to'] ) ) { $atts['email_to'] = preg_split( '/ (,|;) /', $notification['email_to'] ); } else { $atts['email_to'] = array(); } if ( isset( $notification['also_email_to'] ) ) { $email_fields = (array) $notification['also_email_to']; $atts['email_to'] = array_merge( $email_fields, $atts['email_to'] ); unset( $email_fields ); } foreach ( $atts['email_to'] as $key => $email_field ) { if ( is_numeric( $email_field ) ) { $atts['email_to'][ $key ] = '[' . $email_field . ']'; } if ( strpos( $email_field, '|' ) ) { $email_opt = explode( '|', $email_field ); if ( isset( $email_opt[0] ) ) { $atts['email_to'][ $key ] = '[' . $email_opt[0] . ' show=' . $email_opt[1] . ']'; } unset( $email_opt ); } } $atts['email_to'] = implode( ', ', $atts['email_to'] ); } private static function setup_new_notification( &$new_notification, $notification, $atts ) { // Set up new notification $new_notification = array( 'post_content' => array( 'email_to' => $atts['email_to'], 'event' => $atts['event'], ), 'post_name' => $atts['form_id'] . '_email_' . $atts['email_key'], ); // Add more fields to the new notification $add_fields = array( 'email_message', 'email_subject', 'plain_text', 'inc_user_info', 'conditions' ); foreach ( $add_fields as $add_field ) { if ( isset( $notification[ $add_field ] ) ) { $new_notification['post_content'][ $add_field ] = $notification[ $add_field ]; } elseif ( in_array( $add_field, array( 'plain_text', 'inc_user_info' ) ) ) { $new_notification['post_content'][ $add_field ] = 0; } else { $new_notification['post_content'][ $add_field ] = ''; } unset( $add_field ); } // Set reply to $new_notification['post_content']['reply_to'] = $atts['reply_to']; // Set from if ( ! empty( $atts['reply_to'] ) || ! empty( $atts['reply_to_name'] ) ) { $new_notification['post_content']['from'] = ( empty( $atts['reply_to_name'] ) ? '[sitename]' : $atts['reply_to_name'] ) . ' <' . ( empty( $atts['reply_to'] ) ? '[admin_email]' : $atts['reply_to'] ) . '>'; } } /** * Switch field IDs in pre-2.0 email conditional logic * * @param array $post_content Pass by reference. */ private static function switch_email_condition_field_ids( &$post_content ) { // Switch field IDs in conditional logic if ( isset( $post_content['conditions'] ) && is_array( $post_content['conditions'] ) ) { foreach ( $post_content['conditions'] as $email_key => $val ) { if ( is_numeric( $email_key ) ) { $post_content['conditions'][ $email_key ] = self::switch_action_field_ids( $val, array( 'hide_field' ) ); } unset( $email_key, $val ); } } } private static function migrate_autoresponder_to_action( $form_options, $form_id, &$notifications ) { if ( isset( $form_options['auto_responder'] ) && $form_options['auto_responder'] && isset( $form_options['ar_email_message'] ) && $form_options['ar_email_message'] ) { // migrate autoresponder $email_field = isset( $form_options['ar_email_to'] ) ? $form_options['ar_email_to'] : 0; if ( strpos( $email_field, '|' ) ) { // data from entries field $email_field = explode( '|', $email_field ); if ( isset( $email_field[1] ) ) { $email_field = $email_field[1]; } } if ( is_numeric( $email_field ) && ! empty( $email_field ) ) { $email_field = '[' . $email_field . ']'; } $notification = $form_options; $new_notification2 = array( 'post_content' => array( 'email_message' => $notification['ar_email_message'], 'email_subject' => isset( $notification['ar_email_subject'] ) ? $notification['ar_email_subject'] : '', 'email_to' => $email_field, 'plain_text' => isset( $notification['ar_plain_text'] ) ? $notification['ar_plain_text'] : 0, 'inc_user_info' => 0, ), 'post_name' => $form_id . '_email_' . count( $notifications ), ); $reply_to = isset( $notification['ar_reply_to'] ) ? $notification['ar_reply_to'] : ''; $reply_to_name = isset( $notification['ar_reply_to_name'] ) ? $notification['ar_reply_to_name'] : ''; if ( ! empty( $reply_to ) ) { $new_notification2['post_content']['reply_to'] = $reply_to; } if ( ! empty( $reply_to ) || ! empty( $reply_to_name ) ) { $new_notification2['post_content']['from'] = ( empty( $reply_to_name ) ? '[sitename]' : $reply_to_name ) . ' <' . ( empty( $reply_to ) ? '[admin_email]' : $reply_to ) . '>'; } $notifications[] = $new_notification2; unset( $new_notification2 ); }//end if } /** * PHP 8 backward compatibility for the libxml_disable_entity_loader function * * @param bool $loader * * @return bool */ public static function maybe_libxml_disable_entity_loader( $loader ) { if ( version_compare( phpversion(), '8.0', '<' ) && function_exists( 'libxml_disable_entity_loader' ) ) { $loader = libxml_disable_entity_loader( $loader ); // phpcs:disable Generic.PHP.DeprecatedFunctions.Deprecated } return $loader; } public static function check_if_libxml_disable_entity_loader_exists() { return version_compare( phpversion(), '8.0', '<' ) && ! function_exists( 'libxml_disable_entity_loader' ); } /** * Get the file types allowed for importing. * This is used in the "accept" attribute for the file upload input on the XML import page. * * @since 6.8.3 * * @return array */ public static function get_supported_upload_file_types() { $file_types = array( '.xml' ); if ( FrmAppHelper::pro_is_installed() ) { // CSV Importing is only available in Pro. $file_types[] = '.csv'; } return $file_types; } }
Save
cmd:
run