├── changelog ├── 1.4.0.md ├── 1.5.0.md └── 1.5.4.md ├── classes ├── class-gfml-conditional-logic.php ├── class-gfml-form.php ├── class-gfml-hooks.php ├── class-wpml-gfml-filter-field-meta.php ├── class-wpml-gfml-plugin-activation.php ├── class-wpml-gfml-requirements.php ├── compatibility │ ├── quiz │ │ └── class-wpml-gf-quiz.php │ └── survey │ │ └── wpml-gf-survey.php └── wpml-gfml-filter-country-field.php ├── inc ├── gfml-migration.class.php ├── gfml-string-name-helper.class.php ├── gfml-tm-api.class.php └── gravity-forms-multilingual.class.php ├── locale ├── gravityforms-multilingual-ar.mo ├── gravityforms-multilingual-de_DE.mo ├── gravityforms-multilingual-el.mo ├── gravityforms-multilingual-es_ES.mo ├── gravityforms-multilingual-fr_FR.mo ├── gravityforms-multilingual-he_IL.mo ├── gravityforms-multilingual-it_IT.mo ├── gravityforms-multilingual-ja.mo ├── gravityforms-multilingual-ko_KR.mo ├── gravityforms-multilingual-nl_NL.mo ├── gravityforms-multilingual-pl_PL.mo ├── gravityforms-multilingual-pt_BR.mo ├── gravityforms-multilingual-pt_PT.mo ├── gravityforms-multilingual-ru_RU.mo ├── gravityforms-multilingual-sv_SE.mo ├── gravityforms-multilingual-uk.mo ├── gravityforms-multilingual-vi.mo ├── gravityforms-multilingual-zh_CN.mo ├── gravityforms-multilingual-zh_TW.mo └── orig │ └── gravityforms-multilingual.po ├── plugin.php ├── vendor ├── autoload.php ├── composer │ ├── ClassLoader.php │ ├── LICENSE │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_real.php │ └── autoload_static.php └── wpml-shared │ ├── wpml-lib-cache │ └── src │ │ └── cache │ │ └── class-wpml-cache-directory.php │ └── wpml-lib-dependencies │ └── src │ └── dependencies │ └── class-wpml-dependencies.php └── wpml-dependencies.json /changelog/1.4.0.md: -------------------------------------------------------------------------------- 1 | # Features 2 | * [gfml-84] Added fix for compatibility between Gravity Forms Product Add-Ons and WCML 3 | 4 | # Fixes 5 | * [gfml-74] Added ability to translate the prefix field for the "Name" Advanced Field 6 | * [gfml-67] Translated Save and continue later confirmation strings showing original values 7 | * [gfml-136] .mo file for Ukrainian language renamed since we adjusted locale to uk -------------------------------------------------------------------------------- /changelog/1.5.0.md: -------------------------------------------------------------------------------- 1 | # Fixes 2 | * [gfml-144] Fix so that confirmation and notification messages are updated when saving -------------------------------------------------------------------------------- /changelog/1.5.4.md: -------------------------------------------------------------------------------- 1 | # Fixes 2 | * [gfml-152] Fixed "Save and Continue" email sent untranslated. 3 | 4 | # Compatibility 5 | * [gfml-151] Added proper translation of captcha field. -------------------------------------------------------------------------------- /classes/class-gfml-conditional-logic.php: -------------------------------------------------------------------------------- 1 | &$field ) { 18 | 19 | if ( $field->conditionalLogic && $field->conditionalLogic['rules'] ) { 20 | 21 | foreach ( $field->conditionalLogic['rules'] as &$rule ) { 22 | 23 | $rule_field = $this->get_field_from_rule( $form, $rule ); 24 | 25 | if ( isset( $rule_field->choices ) && is_array( $rule_field->choices ) ) { 26 | $translations = $this->get_multi_input_translations( $rule_field, $st_context ); 27 | $rule['value'] = $translations[ $rule['value'] ]; 28 | } 29 | } 30 | } 31 | } 32 | 33 | return $form; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /classes/class-gfml-form.php: -------------------------------------------------------------------------------- 1 | id; 27 | 28 | if ( ! is_array( $field->choices ) ) { 29 | return []; 30 | } 31 | 32 | if ( ! array_key_exists( $field_id, $this->multi_input_translations ) ) { 33 | $snh = new GFML_String_Name_Helper(); 34 | $snh->field = $field; 35 | 36 | $translations = []; 37 | 38 | foreach ( $field->choices as $index => $choice ) { 39 | $snh->field_choice = $choice; 40 | $snh->field_choice_index = $index; 41 | 42 | $choice_id = $choice['value']; // We use the 'text' property in the original language as ID for the translations cluster. 43 | 44 | $translations[ $choice_id ] = icl_t( $st_context, $snh->get_field_multi_input_choice_value(), $choice['value'] ); 45 | } 46 | 47 | $this->multi_input_translations[ $field_id ] = $translations; 48 | } 49 | 50 | return $this->multi_input_translations[ $field_id ]; 51 | } 52 | 53 | /** 54 | * It matches the field in the rule with the form's field (if present). 55 | * 56 | * @param array $form 57 | * @param array $rule 58 | * 59 | * @return \GF_Field|null 60 | */ 61 | protected function get_field_from_rule( $form, $rule ) { 62 | if ( $rule && array_key_exists( 'fieldId', $rule ) ) { 63 | foreach ( $form['fields'] as $field ) { 64 | if ( (int) $rule['fieldId'] === $field->id ) { 65 | return $field; 66 | } 67 | } 68 | } 69 | 70 | return null; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /classes/class-gfml-hooks.php: -------------------------------------------------------------------------------- 1 | gfml = $gfml; 19 | } 20 | 21 | /** 22 | * Gravity Forms actions and filters hooks. 23 | */ 24 | public function init() { 25 | add_action( 'gform_post_form_duplicated', [ $this, 'gform_post_form_duplicated' ], 10, 2 ); 26 | add_action( 'gform_forms_post_import', [ $this, 'gform_forms_post_import' ] ); 27 | add_filter( 'wpml_tm_dashboard_date', [ $this, 'set_gfml_date_on_tm_dashboard' ], 10, 3 ); 28 | } 29 | 30 | /** 31 | * @param int $old_id 32 | * @param int $new_id 33 | */ 34 | public function gform_post_form_duplicated( $old_id, $new_id ) { 35 | $form = GFAPI::get_form( $new_id ); 36 | 37 | $this->gfml->update_form_translations( $form, true ); 38 | } 39 | 40 | /** 41 | * @param array $forms 42 | */ 43 | public function gform_forms_post_import( array $forms ) { 44 | if ( is_array( $forms ) ) { 45 | foreach ( $forms as $form ) { 46 | $this->gfml->update_form_translations( $form, true ); 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * @param int|false $current_time 53 | * @param int $package_id 54 | * @param string $type 55 | * 56 | * @return false|int 57 | */ 58 | public function set_gfml_date_on_tm_dashboard( $current_time, $package_id, $type ) { 59 | $date = $current_time; 60 | if ( 'package_' . $this->gfml->get_type() === $type && class_exists( 'GFAPI' ) ) { 61 | /** @var \WPML_Package $package */ 62 | $package = apply_filters( 'wpml_st_get_string_package', false, $package_id ); 63 | if ( $package && $package->name ) { 64 | $form = GFAPI::get_form( $package->name ); 65 | $date = strtotime( $form['date_created'] ); 66 | } 67 | } 68 | 69 | return $date; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /classes/class-wpml-gfml-filter-field-meta.php: -------------------------------------------------------------------------------- 1 | current_language = $current_language; 20 | add_filter( 'gform_form_post_get_meta', [ $this, 'filter_taxonomy_terms' ], 10, 1 ); 21 | } 22 | 23 | /** 24 | * @param array $field_data 25 | * 26 | * @return array 27 | */ 28 | public function filter_taxonomy_terms( $field_data ) { 29 | if ( is_array( $field_data['fields'] ) ) { 30 | foreach ( $field_data['fields'] as &$field ) { 31 | if ( ! empty( $field->choices ) && 'post_category' === $field->type ) { 32 | foreach ( $field->choices as &$choice ) { 33 | $tr_cat = apply_filters( 'wpml_object_id', $choice['value'], 'category', false, $this->current_language ); 34 | if ( null !== $tr_cat ) { 35 | $tr_cat = get_category( $tr_cat ); 36 | $choice['value'] = $tr_cat->term_id; 37 | $choice['text'] = $tr_cat->name; 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | return $field_data; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /classes/class-wpml-gfml-plugin-activation.php: -------------------------------------------------------------------------------- 1 | missing = []; 16 | $this->missing_one = false; 17 | add_action( 'admin_notices', [ $this, 'missing_plugins_warning' ] ); 18 | add_action( 'plugins_loaded', [ $this, 'plugins_loaded_action' ], 999999 ); 19 | } 20 | 21 | private function check_required_plugins() { 22 | $this->missing = []; 23 | $this->missing_one = false; 24 | 25 | if ( ! defined( 'ICL_SITEPRESS_VERSION' ) 26 | || ICL_PLUGIN_INACTIVE 27 | || version_compare( ICL_SITEPRESS_VERSION, '2.0.5', '<' ) 28 | ) { 29 | $this->missing['WPML'] = [ 30 | 'url' => 'http://wpml.org', 31 | 'slug' => 'sitepress-multilingual-cms', 32 | ]; 33 | 34 | $this->missing_one = true; 35 | } 36 | 37 | if ( ! class_exists( 'GFForms' ) ) { 38 | $this->missing['Gravity Forms'] = [ 39 | 'url' => 'http://gravityforms.com', 40 | 'slug' => 'gravity-forms', 41 | ]; 42 | 43 | $this->missing_one = true; 44 | } 45 | 46 | if ( ! defined( 'WPML_TM_VERSION' ) ) { 47 | $this->missing['WPML Translation Management'] = [ 48 | 'url' => 'http://wpml.org', 49 | 'slug' => 'wpml-translation-management', 50 | ]; 51 | 52 | $this->missing_one = true; 53 | } 54 | 55 | if ( ! defined( 'WPML_ST_VERSION' ) ) { 56 | $this->missing['WPML String Translation'] = [ 57 | 'url' => 'http://wpml.org', 58 | 'slug' => 'wpml-string-stranslation', 59 | ]; 60 | 61 | $this->missing_one = true; 62 | } 63 | } 64 | 65 | public function plugins_loaded_action() { 66 | $this->check_required_plugins(); 67 | 68 | if ( ! $this->missing_one ) { 69 | do_action( 'wpml_gfml_has_requirements' ); 70 | } 71 | } 72 | 73 | /** 74 | * Missing plugins warning. 75 | */ 76 | public function missing_plugins_warning() { 77 | if ( $this->missing ) { 78 | $missing = ''; 79 | $missing_slugs = []; 80 | $counter = 0; 81 | foreach ( $this->missing as $title => $data ) { 82 | $url = $data['url']; 83 | $missing_slugs[] = 'wpml-missing-' . sanitize_title_with_dashes( $data['slug'] ); 84 | $counter ++; 85 | if ( count( $this->missing ) === $counter ) { 86 | $sep = ''; 87 | } elseif ( count( $this->missing ) - 1 === $counter ) { 88 | $sep = ' ' . __( 'and', 'wpml-translation-management' ) . ' '; 89 | } else { 90 | $sep = ', '; 91 | } 92 | $missing .= '' . $title . '' . $sep; 93 | } 94 | 95 | $missing_slugs_classes = implode( ' ', $missing_slugs ); 96 | ?> 97 |
107 | gfml_tm_api = &$gfml_tm_api; 20 | 21 | $this->quiz_messages = [ 22 | 'failConfirmationMessage' => 'Fail Confirmation', 23 | 'letterConfirmationMessage' => 'Letter Confirmation', 24 | 'passConfirmationMessage' => 'Pass Confirmation', 25 | ]; 26 | 27 | // Hook functions. 28 | add_action( 'gform_after_save_form', [ $this, 'gform_after_save_form_action' ], 10, 1 ); 29 | add_action( 'wpml_gf_register_strings_field_quiz', [ $this, 'register_fields_strings' ], 10, 3 ); 30 | 31 | if ( ! is_admin() ) { 32 | add_filter( 'gform_pre_render', [ $this, 'gform_pre_render' ], 10 ); 33 | add_filter( 'gform_pre_submission_filter', [ $this, 'gform_pre_submission_filter' ], 10 ); 34 | add_filter( 'gform_form_post_get_meta', [ $this, 'quiz_explanation_pre_render' ], 10 ); 35 | } 36 | } 37 | 38 | /** 39 | * Register un-handled quiz main strings 40 | * 41 | * @param array $form Form. 42 | */ 43 | public function gform_after_save_form_action( $form ) { 44 | $this->register_main_strings( $form ); 45 | } 46 | 47 | /** 48 | * Register un-handled quiz main strings 49 | * 50 | * @param array $form Form. 51 | */ 52 | private function register_main_strings( $form ) { 53 | if ( $this->is_quiz( $form ) ) { 54 | $this->register_messages_strings( $this->quiz_messages, $form ); 55 | $this->register_grades_strings( $form ); 56 | } 57 | } 58 | 59 | 60 | /** 61 | * Register messages strings of the form 62 | * 63 | * @param array $quiz_messages Messages. 64 | * @param array $form Form. 65 | */ 66 | private function register_messages_strings( $quiz_messages, $form ) { 67 | if ( ! isset( $form['gravityformsquiz'] ) ) { 68 | return; 69 | } 70 | 71 | $form_package = $this->gfml_tm_api->get_form_package( $form ); 72 | 73 | foreach ( $quiz_messages as $message => $title ) { 74 | $string_name = $this->get_quiz_message_string_name( $message ); 75 | $this->gfml_tm_api->register_gf_string( $form['gravityformsquiz'][ $message ], $string_name, $form_package, $title, 'AREA' ); 76 | } 77 | } 78 | 79 | /** 80 | * Register grades strings of the form 81 | * 82 | * @param array $form Form. 83 | */ 84 | private function register_grades_strings( $form ) { 85 | if ( isset( $form['gravityformsquiz']['grades'] ) ) { 86 | $form_package = $this->gfml_tm_api->get_form_package( $form ); 87 | 88 | foreach ( $form['gravityformsquiz']['grades'] as $grade ) { 89 | $string_name = $this->get_quiz_grade_string_name( $grade['value'] ); 90 | $title = 'Form Grade ' . $grade['value']; 91 | $this->gfml_tm_api->register_gf_string( $grade['text'], $string_name, $form_package, $title, 'LINE' ); 92 | } 93 | } 94 | } 95 | 96 | /** 97 | * Register un-handled quiz field strings 98 | * 99 | * @param array $form Form. 100 | * @param array $form_package String form package. 101 | * @param object $form_field Form field. 102 | */ 103 | public function register_fields_strings( $form, $form_package, $form_field ) { 104 | if ( $this->is_quiz( $form ) && in_array( $form_field->inputType, [ 'select', 'radio', 'checkbox' ], true ) ) { 105 | $this->gfml_tm_api->register_strings_field_option( $this->gfml_tm_api->get_form_package( $form ), $form_field ); 106 | $this->register_quiz_explanation_string( $this->gfml_tm_api->get_form_package( $form ), $form_field ); 107 | } 108 | } 109 | 110 | /** 111 | * Register quiz explanation strings 112 | * 113 | * @param object $form_package Form Package. 114 | * @param object $form_field Form field. 115 | */ 116 | private function register_quiz_explanation_string( $form_package, $form_field ) { 117 | if ( ! empty( $form_field['gquizAnswerExplanation'] ) ) { 118 | $string_name = $this->get_quiz_explanation_string_name( $form_field ); 119 | $string_title = 'Quiz explanation'; 120 | $this->gfml_tm_api->register_gf_string( $form_field['gquizAnswerExplanation'], $string_name, $form_package, $string_title, 'AREA' ); 121 | } 122 | } 123 | 124 | 125 | /** 126 | * Get quiz explanation string name 127 | * 128 | * @param object $form_field Form field. 129 | * 130 | * @return array Form 131 | */ 132 | private function get_quiz_explanation_string_name( $form_field ) { 133 | $snh = new GFML_String_Name_Helper(); 134 | return $snh->sanitize_string( 'quiz-' . $form_field->id . '-explanation' ); 135 | } 136 | 137 | 138 | /** 139 | * Get quiz message string name 140 | * 141 | * @param string $message message slug. 142 | * 143 | * @return array Form 144 | */ 145 | private function get_quiz_message_string_name( $message ) { 146 | $snh = new GFML_String_Name_Helper(); 147 | return $snh->sanitize_string( 'quiz_' . $message ); 148 | } 149 | 150 | 151 | /** 152 | * Get quiz grade string name 153 | * 154 | * @param string $value grade value. 155 | * 156 | * @return array Form 157 | */ 158 | protected function get_quiz_grade_string_name( $value ) { 159 | $snh = new GFML_String_Name_Helper(); 160 | return $snh->sanitize_string( 'quiz-grade-value_' . $value ); 161 | } 162 | 163 | 164 | /** 165 | * Replace strings with translations 166 | * 167 | * @param array $form Form. 168 | * 169 | * @return array Form 170 | */ 171 | public function gform_pre_render( $form ) { 172 | if ( $this->is_quiz( $form ) ) { 173 | $form_package = $this->gfml_tm_api->get_form_package( $form ); 174 | 175 | $form = $this->translate_messages_strings( $form, $form_package, $this->quiz_messages ); 176 | $form = $this->translate_grades_strings( $form, $form_package ); 177 | // Choices options are already translated in Gravity_Forms_Multilingual::get_form_strings(). 178 | } 179 | return $form; 180 | } 181 | 182 | 183 | /** 184 | * Replace strings with translations on form submission 185 | * 186 | * @param array $form Form. 187 | * 188 | * @return array $form Form 189 | */ 190 | public function gform_pre_submission_filter( $form ) { 191 | $form = $this->gform_pre_render( $form ); 192 | return $form; 193 | } 194 | 195 | 196 | /** 197 | * Replace quiz explanation strings with translations 198 | * Note: Those strings are passed as JS vars in GFQuiz::enqueue_front_end_scripts() 199 | * which is called earlier, so this is also hooked earlier. 200 | * 201 | * @param array $form Form. 202 | * 203 | * @return array Form 204 | */ 205 | public function quiz_explanation_pre_render( $form ) { 206 | if ( $this->is_quiz( $form ) ) { 207 | $form_package = $this->gfml_tm_api->get_form_package( $form ); 208 | 209 | $form = $this->translate_quiz_explanation_strings( $form, $form_package ); 210 | } 211 | return $form; 212 | } 213 | 214 | 215 | /** 216 | * Translate main strings 217 | * 218 | * @param array $form Form. 219 | * @param object $form_package Form Package. 220 | * @param array $quiz_messages List of quiz messages. 221 | * 222 | * @return array Form 223 | */ 224 | private function translate_messages_strings( $form, $form_package, $quiz_messages ) { 225 | foreach ( $quiz_messages as $message => $title ) { 226 | if ( ! empty( $form['gravityformsquiz'][ $message ] ) ) { 227 | $string_value = $form['gravityformsquiz'][ $message ]; 228 | $string_name = $this->get_quiz_message_string_name( $message ); 229 | $form['gravityformsquiz'][ $message ] = apply_filters( 'wpml_translate_string', $string_value, $string_name, $form_package ); 230 | } 231 | } 232 | return $form; 233 | } 234 | 235 | 236 | /** 237 | * Translate grade strings 238 | * 239 | * @param array $form Form. 240 | * @param object $form_package Form Package. 241 | * 242 | * @return array Form 243 | */ 244 | private function translate_grades_strings( $form, $form_package ) { 245 | if ( isset( $form['gravityformsquiz']['grades'] ) ) { 246 | foreach ( $form['gravityformsquiz']['grades'] as $key => $grade ) { 247 | if ( ! empty( $form['gravityformsquiz']['grades'][ $key ]['text'] ) ) { 248 | $string_value = $form['gravityformsquiz']['grades'][ $key ]['text']; 249 | $string_name = $this->get_quiz_grade_string_name( $grade['value'] ); 250 | $form['gravityformsquiz']['grades'][ $key ]['text'] = apply_filters( 'wpml_translate_string', $string_value, $string_name, $form_package ); 251 | } 252 | } 253 | } 254 | return $form; 255 | } 256 | 257 | 258 | /** 259 | * Translate explanation strings 260 | * 261 | * @param array $form Form. 262 | * @param object $form_package Form Package. 263 | * 264 | * @return array Form 265 | */ 266 | private function translate_quiz_explanation_strings( $form, $form_package ) { 267 | foreach ( $form['fields'] as $key => $form_field ) { 268 | if ( ! empty( $form_field['gquizAnswerExplanation'] ) ) { 269 | $string_value = $form['fields'][ $key ]['gquizAnswerExplanation']; 270 | $string_name = $this->get_quiz_explanation_string_name( $form_field ); 271 | $form['fields'][ $key ]['gquizAnswerExplanation'] = apply_filters( 'wpml_translate_string', $string_value, $string_name, $form_package ); 272 | } 273 | } 274 | return $form; 275 | } 276 | 277 | /** 278 | * Check if this form has a quiz 279 | * 280 | * @param array $form Form. 281 | * 282 | * @return bool 283 | */ 284 | private function is_quiz( $form ) { 285 | $is_quiz = false; 286 | if ( isset( $form['gravityformsquiz'] ) ) { 287 | $is_quiz = true; 288 | } elseif ( isset( $form['fields'] ) ) { 289 | foreach ( $form['fields'] as $field ) { 290 | if ( isset( $field['gquizFieldType'] ) ) { 291 | $is_quiz = true; 292 | } 293 | } 294 | } 295 | return $is_quiz; 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /classes/compatibility/survey/wpml-gf-survey.php: -------------------------------------------------------------------------------- 1 | gfml_tm_api = $gfml_tm_api; 22 | $this->string_name_helper = $string_name_helper; 23 | } 24 | 25 | public function add_hooks() { 26 | add_action( 'wpml_gf_register_strings_field_survey', [ $this, 'register_field_strings' ], 10, 3 ); 27 | 28 | if ( ! is_admin() ) { 29 | add_filter( 'gform_pre_render', [ $this, 'gform_pre_render' ], 10 ); 30 | } 31 | } 32 | 33 | /** 34 | * @param array $form 35 | * 36 | * @return array 37 | */ 38 | public function gform_pre_render( $form ) { 39 | if ( $this->has_survey_field( $form ) ) { 40 | $form_package = $this->gfml_tm_api->get_form_package( $form ); 41 | $form = $this->translate_strings_for_likert_rows( $form, $form_package ); 42 | } 43 | 44 | return $form; 45 | } 46 | 47 | private function translate_strings_for_likert_rows( $form, $form_package ) { 48 | foreach ( $form['fields'] as &$field ) { 49 | if ( $this->is_likert_rows_type( $field ) ) { 50 | foreach ( $field->{self::LIKERT_ROWS_KEY} as &$likert_row ) { 51 | $likert_row['text'] = apply_filters( 52 | 'wpml_translate_string', 53 | $likert_row['text'], 54 | $this->get_likert_row_string_name( $likert_row['text'] ), 55 | $form_package 56 | ); 57 | } 58 | } 59 | } 60 | 61 | return $form; 62 | } 63 | 64 | /** 65 | * @param array $form 66 | * @param stdClass $form_package 67 | * @param object $form_field 68 | */ 69 | public function register_field_strings( $form, $form_package, $form_field ) { 70 | if ( ! $this->is_survey_field( $form_field ) ) { 71 | return; 72 | } 73 | 74 | $this->gfml_tm_api->register_strings_field_option( $form_package, $form_field ); 75 | $this->register_strings_for_likert_rows( $form_package, $form_field ); 76 | } 77 | 78 | private function register_strings_for_likert_rows( $form_package, $form_field ) { 79 | if ( $this->is_likert_rows_type( $form_field ) ) { 80 | foreach ( $form_field->{self::LIKERT_ROWS_KEY} as $likert_row ) { 81 | $value = $likert_row['text']; 82 | $name = $this->get_likert_row_string_name( $value ); 83 | $this->gfml_tm_api->register_gf_string( $value, $name, $form_package, $name ); 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * @param string $value 90 | * 91 | * @return string 92 | */ 93 | private function get_likert_row_string_name( $value ) { 94 | return $this->string_name_helper->sanitize_string( self::LIKERT_ROWS_NAME_PREFIX . $value ); 95 | } 96 | 97 | /** 98 | * @param stdClass|GF_Field $form_field 99 | * 100 | * @return bool 101 | */ 102 | private function is_likert_rows_type( $form_field ) { 103 | return isset( $form_field->{self::LIKERT_ROWS_KEY} ); 104 | } 105 | 106 | /** 107 | * @param stdClass|GF_Field $form_field 108 | * 109 | * @return bool 110 | */ 111 | private function is_survey_field( $form_field ) { 112 | return isset( $form_field->type ) && self::FIELD_TYPE === $form_field->type; 113 | } 114 | 115 | /** 116 | * @param array $form 117 | * 118 | * @return bool 119 | */ 120 | private function has_survey_field( $form ) { 121 | foreach ( $form['fields'] as $field ) { 122 | if ( $this->is_survey_field( $field ) ) { 123 | return true; 124 | } 125 | } 126 | 127 | return false; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /classes/wpml-gfml-filter-country-field.php: -------------------------------------------------------------------------------- 1 | tm_api = $tm_api; 13 | } 14 | 15 | public function migrate() { 16 | global $wpdb; 17 | 18 | // todo: Add caching. 19 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery 20 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching 21 | $form_ids = $wpdb->get_col( 22 | // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 23 | "SELECT id FROM {$this->tm_api->get_forms_table_name()}" 24 | ); 25 | 26 | foreach ( $form_ids as $id ) { 27 | $form = RGFormsModel::get_form_meta( $id ); 28 | $this->tm_api->update_form_translations( $form, true ); 29 | $wpdb->delete( 30 | $wpdb->prefix . 'icl_translations', 31 | [ 32 | 'element_id' => $id, 33 | 'element_type' => 'post_gravity_form', 34 | ] 35 | ); 36 | 37 | $this->migrate_old_translated_values( $id ); 38 | } 39 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching 40 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery 41 | } 42 | 43 | private function migrate_old_translated_values( $form_id ) { 44 | global $wpdb; 45 | 46 | $st_context = $this->tm_api->get_st_context( $form_id ); 47 | $form_strings = array_keys( $this->tm_api->get_form_strings( $form_id ) ); 48 | foreach ( $form_strings as &$string_name ) { 49 | $string_name = "{$form_id}_" . $string_name; 50 | } 51 | $s_name_in = wpml_prepare_in( $form_strings ); 52 | 53 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery 54 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching 55 | // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared 56 | $id_s_needing_update = $wpdb->get_results( 57 | $wpdb->prepare( 58 | "SELECT st.id AS id, cs.id AS right_id 59 | FROM {$wpdb->prefix}icl_strings s 60 | JOIN {$wpdb->prefix}icl_strings cs 61 | ON CONCAT(%s,cs.name) = s.name 62 | JOIN {$wpdb->prefix}icl_string_translations st 63 | ON s.id = st.string_id 64 | LEFT JOIN {$wpdb->prefix}icl_string_translations cst 65 | ON cs.id = cst.string_id AND st.language = cst.language 66 | WHERE s.context = 'gravity_form' 67 | AND cs.context = %s 68 | AND cst.language IS NULL 69 | AND s.name IN ({$s_name_in})", 70 | $form_id . '_', 71 | $st_context 72 | ) 73 | ); 74 | // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared 75 | 76 | foreach ( $id_s_needing_update as $id_data ) { 77 | $wpdb->update( 78 | $wpdb->prefix . 'icl_string_translations', 79 | [ 'string_id' => $id_data->right_id ], 80 | [ 'id' => $id_data->id ] 81 | ); 82 | 83 | icl_update_string_status( $id_data->right_id ); 84 | icl_update_string_status( $id_data->id ); 85 | } 86 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching 87 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /inc/gfml-string-name-helper.class.php: -------------------------------------------------------------------------------- 1 | field->type; 35 | $string_name_parts[] = $this->field->id; 36 | $string_name_parts[] = 'placeholder'; 37 | 38 | return $string_name_parts; 39 | } 40 | 41 | private function get_field_customLabel_parts() { 42 | $string_name_parts = []; 43 | $string_name_parts[] = $this->field->type; 44 | $string_name_parts[] = $this->field->id; 45 | $string_name_parts[] = 'customLabel'; 46 | 47 | return $string_name_parts; 48 | } 49 | 50 | private function get_field_input_placeholder_parts() { 51 | $string_name_parts = $this->get_field_placeholder_parts(); 52 | $string_name_parts[] = 'input'; 53 | $string_name_parts[] = $this->field_input['id']; 54 | 55 | return $string_name_parts; 56 | } 57 | 58 | private function get_field_input_customLabel_parts() { 59 | $string_name_parts = $this->get_field_customLabel_parts(); 60 | $string_name_parts[] = 'input'; 61 | $string_name_parts[] = $this->field_input['id']; 62 | 63 | return $string_name_parts; 64 | } 65 | 66 | public function sanitize_string( $string_name, $max_length = self::SANITIZE_STRING_MAX_LENGTH ) { 67 | $string_name = preg_replace( '/[ \[\]]+/', '-', $string_name ); 68 | if ( mb_strlen( $string_name ) > $max_length ) { 69 | $string_name = mb_substr( $string_name, 0, $max_length ); 70 | } 71 | 72 | return $string_name; 73 | } 74 | 75 | public function get_field_post_category() { 76 | return $this->sanitize_string( "field-{$this->field->id}-categoryInitialItem" ); 77 | } 78 | 79 | public function get_field_address_copy_values_option() { 80 | return $this->sanitize_string( "field-{$this->field->id}-copyValuesOptionLabel" ); 81 | } 82 | 83 | public function get_field_post_custom_field() { 84 | return $this->sanitize_string( "field-{$this->field->id}-customFieldTemplate" ); 85 | } 86 | 87 | public function get_field_page_previousButton() { 88 | return $this->sanitize_string( 'page-' . ( intval( $this->field->pageNumber ) - 1 ) . "-previousButton-{$this->field_key}" ); 89 | } 90 | 91 | public function get_field_page_nextButton() { 92 | return $this->sanitize_string( 'page-' . ( intval( $this->field->pageNumber ) - 1 ) . "-nextButton-{$this->field_key}" ); 93 | } 94 | 95 | public function get_field_html() { 96 | return $this->sanitize_string( "field-{$this->field->id}-content" ); 97 | } 98 | 99 | public function get_field_multi_input_choice_text() { 100 | $sanitized_value = sanitize_text_field( $this->field_choice['text'] ); 101 | return $this->sanitize_string( 102 | "{$this->field->type}-{$this->field->id}-choice-{$this->field_choice_index}-{$sanitized_value}", 103 | self::SANITIZE_STRING_MAX_LENGTH - mb_strlen( self::CHOICE_VALUE_SUFFIX ) 104 | ); 105 | } 106 | 107 | public function get_field_multi_input_choice_value() { 108 | return $this->get_field_multi_input_choice_text() . self::CHOICE_VALUE_SUFFIX; 109 | } 110 | 111 | public function get_form_confirmation_message() { 112 | return $this->sanitize_string( 'field-confirmation-message_' . $this->confirmation['name'] ); 113 | } 114 | 115 | public function get_form_confirmation_page_id() { 116 | return $this->sanitize_string( 'confirmation-page_' . $this->confirmation['name'] ); 117 | } 118 | 119 | public function get_form_notification_subject() { 120 | return $this->sanitize_string( 'notification-subject_' . $this->notification['name'] ); 121 | } 122 | 123 | public function get_form_notification_message() { 124 | return $this->sanitize_string( 'field-notification-message_' . $this->notification['name'] ); 125 | } 126 | 127 | public function get_field_validation_message() { 128 | return $this->sanitize_string( 'field-' . $this->field['id'] . '-errorMessage' ); 129 | } 130 | 131 | public function get_field_common() { 132 | return $this->sanitize_string( "field-{$this->field->id}-{$this->field_key}" ); 133 | } 134 | 135 | public function get_form_pagination_page_title() { 136 | return $this->sanitize_string( 'page-' . ( intval( $this->page_index ) + 1 ) . '-title' ); 137 | } 138 | 139 | public function get_form_pagination_completion_text() { 140 | return $this->sanitize_string( 'progressbar_completion_text' ); 141 | } 142 | 143 | public function get_form_pagination_last_page_button_text() { 144 | return $this->sanitize_string( 'lastPageButton' ); 145 | } 146 | 147 | public function get_form_confirmation_redirect_url() { 148 | return $this->sanitize_string( 'confirmation-redirect_' . $this->confirmation['name'] ); 149 | } 150 | 151 | public function get_field_placeholder() { 152 | $string_name_parts = $this->get_field_placeholder_parts(); 153 | $string_name = implode( '-', $string_name_parts ); 154 | $string_name = $this->sanitize_string( $string_name ); 155 | 156 | return $string_name; 157 | } 158 | 159 | public function get_field_input_placeholder() { 160 | $string_name_parts = $this->get_field_input_placeholder_parts(); 161 | $string_name = implode( '-', $string_name_parts ); 162 | $string_name = $this->sanitize_string( $string_name ); 163 | 164 | return $string_name; 165 | } 166 | 167 | public function get_field_input_customLabel() { 168 | $string_name_parts = $this->get_field_input_customLabel_parts(); 169 | $string_name = implode( '-', $string_name_parts ); 170 | $string_name = $this->sanitize_string( $string_name ); 171 | 172 | return $string_name; 173 | } 174 | 175 | public function get_form_submit_button() { 176 | return $this->sanitize_string( 'form_submit_button' ); 177 | } 178 | 179 | public function get_form_title() { 180 | return $this->sanitize_string( 'form_title' ); 181 | } 182 | 183 | public function get_form_description() { 184 | return $this->sanitize_string( 'form_description' ); 185 | } 186 | 187 | public function get_form_save_and_continue_later_text() { 188 | return $this->sanitize_string( 'form_save_and_continue_later_text' ); 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /inc/gfml-tm-api.class.php: -------------------------------------------------------------------------------- 1 | gravity_form_table_exists() && $this->has_post_gravity_from_translations() ) { 16 | require dirname( __FILE__ ) . '/gfml-migration.class.php'; 17 | $migration_object = new GFML_Migration( $this ); 18 | $migration_object->migrate(); 19 | } 20 | update_option( 'gfml_pt_migr_comp', true ); 21 | } 22 | } 23 | 24 | public function gform_post_update_form_meta_action() { 25 | if ( ! get_option( 'wpml-package-translation-refresh-required' ) ) { 26 | update_option( 'wpml-package-translation-refresh-required', true ); 27 | } 28 | } 29 | 30 | private function gravity_form_table_exists() { 31 | return (bool) $this->get_forms_table_name(); 32 | } 33 | 34 | /** 35 | * @param string $source 36 | * @param int $max_length 37 | * 38 | * @return string 39 | */ 40 | private function trim_with_ellipsis( $source, $max_length ) { 41 | $source_length = mb_strlen( $source ); 42 | 43 | if ( $source_length > $max_length ) { 44 | $offset = $max_length - 3; 45 | $source = mb_substr( $source, 0, $offset ) . '...'; 46 | } 47 | 48 | return $source; 49 | } 50 | 51 | private function build_string_title( $form_field, $form_field_key, $sub_title = '' ) { 52 | $max_length = 160; 53 | 54 | $form_field_key = $this->trim_with_ellipsis( $form_field_key, $max_length / 3 ); 55 | $field_title = '{' . $form_field['id'] . ':' . $form_field['type'] . '} ' . $form_field_key; 56 | $current_length = mb_strlen( $field_title ); 57 | 58 | if ( $current_length < $max_length && $sub_title && $sub_title !== $form_field_key ) { 59 | $sub_title_max_length = $max_length - ( $current_length + 3 ); 60 | $sub_title = $this->trim_with_ellipsis( $sub_title, $sub_title_max_length ); 61 | if ( $sub_title_max_length > 0 ) { 62 | $field_title .= ' [' . $this->trim_with_ellipsis( $sub_title, $sub_title_max_length ) . ']'; 63 | } else { 64 | $field_title = '{' . $form_field['id'] . ':' . $form_field['type'] . '} [' . $sub_title . ']'; 65 | $field_title = $this->trim_with_ellipsis( $field_title, $max_length ); 66 | } 67 | } 68 | 69 | if ( mb_strlen( $field_title ) > $max_length ) { 70 | $field_title = $this->trim_with_ellipsis( $field_title, $max_length ); 71 | } 72 | 73 | return $field_title; 74 | } 75 | 76 | /** 77 | * @return string 78 | */ 79 | public function get_type() { 80 | return 'gravity_form'; 81 | } 82 | 83 | public function get_st_context( $form_id ) { 84 | return sanitize_title_with_dashes( ICL_GRAVITY_FORM_ELEMENT_TYPE . '-' . $form_id ); 85 | } 86 | 87 | public function get_form_package( $form ) { 88 | $form_package = new stdClass(); 89 | $form_package->kind = __( 'Gravity Form', 'gravity-forms-ml' ); 90 | $form_package->kind_slug = ICL_GRAVITY_FORM_ELEMENT_TYPE; 91 | $form_package->name = $form['id']; 92 | $form_package->title = $form['title']; 93 | $form_package->edit_link = admin_url( sprintf( 'admin.php?page=gf_edit_forms&id=%d', $form['id'] ) ); 94 | 95 | return $form_package; 96 | } 97 | 98 | public function register_gf_string( $string_value, $string_name, $package, $string_title, $string_kind = 'LINE' ) { 99 | $this->registered_strings[] = $string_name; 100 | do_action( 'wpml_register_string', $string_value, $string_name, $package, $string_title, $string_kind ); 101 | } 102 | 103 | protected function register_strings_common_fields( $form_field, $form_package ) { 104 | // Filter common properties. 105 | $snh = new GFML_String_Name_Helper(); 106 | $snh->field = $form_field; 107 | foreach ( $this->form_fields as $form_field_key ) { 108 | if ( ! empty( $form_field->{$form_field_key} ) && 'page' !== $form_field->type ) { 109 | $snh->field_key = $form_field_key; 110 | $string_name = $snh->get_field_common(); 111 | $string_title = $this->build_string_title( $form_field, $form_field_key, $form_field['label'] ); 112 | $string_type = 'LINE'; 113 | $area_fields = [ 'description', 'errorMessage' ]; 114 | if ( in_array( $form_field_key, $area_fields, true ) ) { 115 | $string_type = 'AREA'; 116 | } 117 | $this->register_gf_string( $form_field->{$form_field_key}, $string_name, $form_package, $string_title, $string_type ); 118 | $this->register_placeholders( $form_package, $form_field ); 119 | $this->register_customLabels( $form_package, $form_field ); 120 | } 121 | } 122 | } 123 | 124 | protected function register_global_strings( $form_package, $form ) { 125 | $snh = new GFML_String_Name_Helper(); 126 | 127 | if ( isset( $form['title'] ) ) { 128 | $string_title = 'Form title'; 129 | $this->register_gf_string( $form['title'], $snh->get_form_title(), $form_package, $string_title ); 130 | } 131 | 132 | if ( isset( $form['description'] ) ) { 133 | $string_title = 'Form description'; 134 | $this->register_gf_string( $form['description'], $snh->get_form_description(), $form_package, $string_title, 'AREA' ); 135 | } 136 | 137 | if ( isset( $form['button']['text'] ) ) { 138 | $string_title = 'Form submit button'; 139 | $this->register_gf_string( $form['button']['text'], $snh->get_form_submit_button(), $form_package, $string_title ); 140 | } 141 | 142 | if ( isset( $form['save']['button']['text'] ) ) { 143 | $string_title = 'Save and Continue Later'; 144 | $this->register_gf_string( $form['save']['button']['text'], $snh->get_form_save_and_continue_later_text(), $form_package, $string_title ); 145 | } 146 | 147 | $this->register_form_notifications( $form_package, $form ); 148 | $this->register_form_confirmations( $form_package, $form ); 149 | } 150 | 151 | protected function register_form_notifications( $form_package, $form ) { 152 | if ( isset( $form['notifications'] ) && $form['notifications'] ) { 153 | $snh = new GFML_String_Name_Helper(); 154 | foreach ( $form['notifications'] as $notification ) { 155 | $snh->notification = $notification; 156 | $string_title = 'Notification: ' . $notification['name'] . ' - subject'; 157 | $this->register_gf_string( $notification['subject'], $snh->get_form_notification_subject(), $form_package, $string_title ); 158 | $string_title = 'Notification: ' . $notification['name'] . ' - message'; 159 | $this->register_gf_string( $notification['message'], $snh->get_form_notification_message(), $form_package, $string_title, 'AREA' ); 160 | } 161 | } 162 | } 163 | 164 | protected function register_form_confirmations( $form_package, $form ) { 165 | if ( isset( $form['confirmations'] ) && $form['confirmations'] ) { 166 | $snh = new GFML_String_Name_Helper(); 167 | foreach ( $form['confirmations'] as $confirmation ) { 168 | $snh->confirmation = $confirmation; 169 | $string_title = 'Confirmation: ' . $confirmation['name'] . ' - ' . $confirmation['type']; 170 | 171 | switch ( $confirmation['type'] ) { 172 | case 'message': 173 | $this->register_gf_string( $confirmation['message'], $snh->get_form_confirmation_message(), $form_package, $string_title, 'AREA' ); 174 | break; 175 | case 'redirect': 176 | $this->register_gf_string( $confirmation['url'], $snh->get_form_confirmation_redirect_url(), $form_package, $string_title ); 177 | $string_data[ $snh->get_form_confirmation_redirect_url() ] = $confirmation['url']; 178 | break; 179 | case 'page': 180 | $this->register_gf_string( $confirmation['pageId'], $snh->get_form_confirmation_page_id(), $form_package, $string_title ); 181 | $string_data[ $snh->get_form_confirmation_page_id() ] = $confirmation['pageId']; 182 | break; 183 | } 184 | } 185 | } 186 | } 187 | 188 | protected function register_strings_field_page( $form_package, $form_field ) { 189 | $snh = new GFML_String_Name_Helper(); 190 | $snh->field = $form_field; 191 | 192 | foreach ( [ 'text', 'imageUrl' ] as $key ) { 193 | $snh->field_key = $key; 194 | if ( ! empty( $form_field->nextButton[ $key ] ) ) { 195 | $string_name = $snh->get_field_page_nextButton(); 196 | $string_title = $this->build_string_title( $form_field, 'next button', $form_field['label'] ); 197 | $this->register_gf_string( $form_field->nextButton[ $key ], $string_name, $form_package, $string_title ); 198 | } 199 | if ( ! empty( $form_field->previousButton[ $key ] ) ) { 200 | $string_name = $snh->get_field_page_previousButton(); 201 | $string_title = $this->build_string_title( $form_field, 'previous button', $form_field['label'] ); 202 | $this->register_gf_string( $form_field->previousButton[ $key ], $string_name, $form_package, $string_title ); 203 | } 204 | } 205 | } 206 | 207 | protected function register_strings_field_choices( $form_package, $form_field ) { 208 | if ( is_array( $form_field->choices ) ) { 209 | foreach ( $form_field->choices as $choice_index => $choice ) { 210 | $this->register_strings_field_choice( $form_package, $form_field, $choice_index, $choice ); 211 | } 212 | } 213 | } 214 | 215 | protected function register_strings_field_choice( $form_package, $form_field, $choice_index, $choice ) { 216 | $snh = new GFML_String_Name_Helper(); 217 | $snh->field = $form_field; 218 | $snh->field_choice = $choice; 219 | $snh->field_choice_index = $choice_index; 220 | 221 | $string_name = $snh->get_field_multi_input_choice_text(); 222 | $string_title = $this->build_string_title( $form_field, $choice_index . ': ' . $form_field['label'], 'label' ); 223 | $this->register_gf_string( $choice['text'], $string_name, $form_package, $string_title ); 224 | 225 | if ( isset( $choice['value'] ) ) { 226 | $string_name = $snh->get_field_multi_input_choice_value(); 227 | $string_title = $this->build_string_title( $form_field, $choice_index . ': ' . $form_field['label'], 'value' ); 228 | $this->register_gf_string( $choice['value'], $string_name, $form_package, $string_title ); 229 | } 230 | 231 | return $string_name; 232 | } 233 | 234 | protected function register_strings_field_post_custom( $form_package, $form_field ) { 235 | // TODO if multi options - 'choices' (register and translate) 'inputType' => select, etc. 236 | $this->register_string_field_property( $form_package, $form_field, 'customFieldTemplate', 'get_field_post_custom_field' ); 237 | } 238 | 239 | protected function register_strings_field_post_category( $form_package, $form_field ) { 240 | // TODO if multi options - 'choices' have static values (register and translate) 'inputType' => select, etc. 241 | $this->register_string_field_property( $form_package, $form_field, 'categoryInitialItem', 'get_field_post_category' ); 242 | } 243 | 244 | protected function register_strings_field_address( $form_package, $form_field ) { 245 | $this->register_string_field_property( $form_package, $form_field, 'copyValuesOptionLabel', 'get_field_address_copy_values_option' ); 246 | } 247 | 248 | protected function register_strings_field_html( $form_package, $form_field ) { 249 | $this->register_string_field_property( $form_package, $form_field, 'content', 'get_field_html', 'AREA' ); 250 | } 251 | 252 | protected function register_string_field_property( $form_package, $form_field, $field_property, $string_helper_function_name, $string_kind = 'LINE' ) { 253 | if ( ! empty( $form_field->{$field_property} ) ) { 254 | $snh = new GFML_String_Name_Helper(); 255 | $snh->field = $form_field; 256 | 257 | if ( ! method_exists( $snh, $string_helper_function_name ) ) { 258 | return; 259 | } 260 | 261 | $string_name = call_user_func( [ $snh, $string_helper_function_name ] ); 262 | $string_title = $this->build_string_title( $form_field, $form_field['label'] ); 263 | $this->register_gf_string( $form_field->{$field_property}, $string_name, $form_package, $string_title, $string_kind ); 264 | } 265 | } 266 | 267 | public function register_strings_field_option( $form_package, $form_field ) { 268 | $snh = new GFML_String_Name_Helper(); 269 | $snh->field = $form_field; 270 | 271 | if ( isset( $form_field->choices ) && is_array( $form_field->choices ) ) { 272 | $this->register_strings_field_choices( $form_package, $form_field ); 273 | } 274 | } 275 | 276 | protected function register_strings_fields( $form_package, $form ) { 277 | // Common field properties. 278 | $this->get_field_keys(); 279 | 280 | // Filter form fields (array of GF_Field objects). 281 | foreach ( $form['fields'] as $form_field ) { 282 | 283 | $this->register_strings_common_fields( $form_field, $form_package ); 284 | 285 | // Field specific code. 286 | switch ( $form_field->type ) { 287 | case 'html': 288 | $this->register_strings_field_html( $form_package, $form_field ); 289 | break; 290 | case 'page': 291 | $this->register_strings_field_page( $form_package, $form_field ); 292 | break; 293 | case 'list': 294 | case 'select': 295 | case 'multiselect': 296 | case 'checkbox': 297 | case 'radio': 298 | case 'product': 299 | case 'option': 300 | case 'shipping': 301 | $this->register_strings_field_option( $form_package, $form_field ); 302 | break; 303 | case 'post_custom_field': 304 | $this->register_strings_field_post_custom( $form_package, $form_field ); 305 | break; 306 | case 'post_category': 307 | $this->register_strings_field_post_category( $form_package, $form_field ); 308 | break; 309 | case 'address': 310 | $this->register_strings_field_address( $form_package, $form_field ); 311 | break; 312 | default: 313 | do_action( "wpml_gf_register_strings_field_{$form_field->type}", $form, $form_package, $form_field ); 314 | } 315 | 316 | $this->register_placeholders( $form_package, $form_field ); 317 | } 318 | } 319 | 320 | protected function register_placeholders( $form_package, $form_field ) { 321 | $snh = new GFML_String_Name_Helper(); 322 | $snh->field = $form_field; 323 | 324 | $string_name = $snh->get_field_placeholder(); 325 | if ( isset( $form_field->placeholder ) ) { 326 | $string_title = $this->build_string_title( $form_field, 'placeholder', $form_field['label'] ); 327 | $this->register_gf_string( $form_field->placeholder, $string_name, $form_package, $string_title ); 328 | } 329 | 330 | if ( isset( $form_field->inputs ) && is_array( $form_field->inputs ) ) { 331 | foreach ( $form_field->inputs as $key => $input ) { 332 | $snh->field_input = $input; 333 | $snh->field_key = $key; 334 | if ( isset( $input['placeholder'] ) && $input['placeholder'] ) { 335 | $string_input_name = $snh->get_field_input_placeholder(); 336 | $string_input_title = $this->build_string_title( $form_field, 'placeholder', $input['placeholder'] ); 337 | $this->register_gf_string( $input['placeholder'], $string_input_name, $form_package, $string_input_title ); 338 | } 339 | } 340 | } 341 | } 342 | 343 | protected function register_customLabels( $form_package, $form_field ) { 344 | $snh = new GFML_String_Name_Helper(); 345 | $snh->field = $form_field; 346 | 347 | if ( isset( $form_field->inputs ) && is_array( $form_field->inputs ) ) { 348 | foreach ( $form_field->inputs as $key => $input ) { 349 | $snh->field_input = $input; 350 | $snh->field_key = $key; 351 | if ( isset( $input['customLabel'] ) && $input['customLabel'] ) { 352 | $string_input_name = $snh->get_field_input_customLabel(); 353 | $string_input_title = $this->build_string_title( $form_field, 'custom label', $input['customLabel'] ); 354 | $this->register_gf_string( $input['customLabel'], $string_input_name, $form_package, $string_input_title ); 355 | } 356 | } 357 | } 358 | } 359 | 360 | protected function register_strings_main_fields( $form_package, $form ) { 361 | $form_keys = $this->get_form_keys(); 362 | foreach ( $form_keys as $key ) { 363 | $value = ! empty( $form[ $key ] ) ? $form[ $key ] : null; 364 | if ( null !== $value ) { 365 | $this->register_gf_string( $value, $key, $form_package, $key ); 366 | } 367 | } 368 | } 369 | 370 | protected function register_strings_pagination( $form_package, $form ) { 371 | // phpcs:ignore Squiz.PHP.CommentedOutCode.Found 372 | // Paging Page Names - $form["pagination"]["pages"][i]. 373 | if ( ! empty( $form['pagination'] ) 374 | && isset( $form['pagination']['pages'] ) 375 | && is_array( $form['pagination']['pages'] ) 376 | ) { 377 | 378 | $snh = new GFML_String_Name_Helper(); 379 | 380 | foreach ( $form['pagination']['pages'] as $key => $page_title ) { 381 | $snh->page_index = $key; 382 | $this->register_gf_string( $page_title, $snh->get_form_pagination_page_title(), $form_package, 'page-' . ( intval( $key ) + 1 ) . '-title' ); 383 | } 384 | $value = ! empty( $form['pagination']['progressbar_completion_text'] ) ? $form['pagination']['progressbar_completion_text'] : null; 385 | if ( null !== $value ) { 386 | $this->register_gf_string( $value, $snh->get_form_pagination_completion_text(), $form_package, 'progressbar_completion_text' ); 387 | } 388 | $value = ! empty( $form['lastPageButton']['text'] ) ? $form['lastPageButton']['text'] : null; 389 | if ( null !== $value ) { 390 | $this->register_gf_string( $value, $snh->get_form_pagination_last_page_button_text(), $form_package, 'lastPageButton' ); 391 | } 392 | } 393 | } 394 | 395 | protected function register_strings( $form ) { 396 | global $sitepress; 397 | 398 | if ( ! isset( $form['id'] ) ) { 399 | return false; 400 | } 401 | 402 | $form_id = $form['id']; 403 | $form_package = $this->get_form_package( $form ); 404 | 405 | // Cache. 406 | $current_lang = $sitepress->get_current_language(); 407 | if ( isset( $this->current_forms[ $form_id ][ $current_lang ] ) ) { 408 | return $this->current_forms[ $form_id ][ $current_lang ]; 409 | } 410 | 411 | $this->register_strings_main_fields( $form_package, $form ); 412 | $this->register_global_strings( $form_package, $form ); 413 | $this->register_strings_pagination( $form_package, $form ); 414 | $this->register_strings_fields( $form_package, $form ); 415 | 416 | $this->current_forms[ $form_id ][ $current_lang ] = $form; 417 | 418 | return $form; 419 | } 420 | 421 | public function update_form_translations( $form, $is_new, $needs_update = true ) { 422 | $this->register_strings( $form ); 423 | $this->cleanup_form_strings( $form ); 424 | } 425 | 426 | protected function cleanup_form_strings( $form ) { 427 | if ( isset( $form['id'] ) ) { 428 | 429 | global $wpdb; 430 | 431 | $form_id = $form['id']; 432 | $st_context = $this->get_st_context( $form_id ); 433 | 434 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery 435 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching 436 | $database_strings = false !== (bool) $this->registered_strings ? $wpdb->get_col( 437 | $wpdb->prepare( 438 | "SELECT s.name 439 | FROM {$wpdb->prefix}icl_strings s 440 | WHERE s.context = %s", 441 | $st_context 442 | ) 443 | ) : []; 444 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching 445 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery 446 | 447 | foreach ( $database_strings as $key => $string_name ) { 448 | if ( ! in_array( $string_name, $this->registered_strings, true ) ) { 449 | icl_unregister_string( $st_context, $string_name ); 450 | } 451 | } 452 | } 453 | } 454 | 455 | public function after_delete_form( $form_id ) { 456 | do_action( 'wpml_delete_package', $form_id, ICL_GRAVITY_FORM_ELEMENT_TYPE ); 457 | } 458 | 459 | protected function gform_id( $package_id ) { 460 | return $package_id; 461 | } 462 | 463 | private function has_post_gravity_from_translations() { 464 | global $wpdb; 465 | 466 | $post_gravity_from_translations_query = "SELECT COUNT(*) 467 | FROM {$wpdb->prefix}icl_translations 468 | WHERE element_type = 'post_gravity_from'"; 469 | 470 | // todo: Add caching. 471 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery 472 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching 473 | $post_gravity_from_translations_count = $wpdb->get_var( 474 | // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared 475 | $post_gravity_from_translations_query 476 | ); 477 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching 478 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery 479 | 480 | return 0 === (int) $post_gravity_from_translations_count; 481 | } 482 | 483 | public function register_missing_packages() { 484 | global $wpdb; 485 | 486 | // todo: Add caching. 487 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery 488 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching 489 | // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared 490 | // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared 491 | $post_gravity_from_translations_query = $wpdb->prepare( 492 | "SELECT rgf.id 493 | FROM {$this->get_forms_table_name()} rgf 494 | LEFT JOIN {$wpdb->prefix}icl_translations iclt 495 | ON rgf.id = iclt.element_id 496 | AND iclt.element_type = %s 497 | WHERE iclt.language_code IS NULL", 498 | 'package_' . ICL_GRAVITY_FORM_ELEMENT_TYPE 499 | ); 500 | 501 | $form_ids = $wpdb->get_col( $post_gravity_from_translations_query ); 502 | // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared 503 | // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared 504 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching 505 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery 506 | 507 | foreach ( $form_ids as $id ) { 508 | $form = RGFormsModel::get_form_meta( $id ); 509 | $this->update_form_translations( $form, true ); 510 | } 511 | } 512 | } 513 | -------------------------------------------------------------------------------- /inc/gravity-forms-multilingual.class.php: -------------------------------------------------------------------------------- 1 | current_forms = []; 45 | $this->form_fields = []; 46 | 47 | /* WPML translation job hooks */ 48 | add_filter( 'WPML_get_link', [ $this, 'get_link' ], 10, 4 ); 49 | add_filter( 'wpml_document_view_item_link', [ $this, 'get_document_view_link' ], 10, 5 ); 50 | add_filter( 'wpml_document_edit_item_link', [ $this, 'get_document_edit_link' ], 10, 5 ); 51 | add_filter( 'wpml_document_edit_item_url', [ $this, 'get_document_edit_url' ], 10, 3 ); 52 | add_filter( 'page_link', [ $this, 'gform_redirect' ], 10, 3 ); 53 | 54 | /* GF frontend hooks: form rendering and submission */ 55 | if ( version_compare( GFForms::$version, '1.9', '<' ) ) { 56 | add_filter( 'gform_pre_render', [ $this, 'gform_pre_render_deprecated' ], 10, 2 ); 57 | } else { 58 | add_filter( 'gform_pre_render', [ $this, 'gform_pre_render' ], 10, 2 ); 59 | } 60 | add_filter( 'gform_pre_submission_filter', [ $this, 'gform_pre_submission_filter' ] ); 61 | add_filter( 'gform_notification', [ $this, 'gform_notification' ], 10, 2 ); 62 | add_filter( 'gform_field_validation', [ $this, 'gform_field_validation' ], 10, 4 ); 63 | add_filter( 'gform_merge_tag_filter', [ $this, 'gform_merge_tag_filter' ], 10, 5 ); 64 | add_filter( 'gform_pre_replace_merge_tags', [ $this, 'gform_pre_replace_merge_tags' ], 100, 2 ); 65 | 66 | /* GF admin hooks for updating WPML translation jobs */ 67 | add_action( 'gform_after_save_form', [ $this, 'update_form_translations' ], 10, 2 ); 68 | add_action( 'gform_pre_confirmation_save', [ $this, 'update_confirmation_translations' ], 10, 2 ); 69 | add_action( 'gform_pre_notification_save', [ $this, 'update_notifications_translations' ], 10, 2 ); 70 | add_action( 'gform_after_delete_form', [ $this, 'after_delete_form' ] ); 71 | add_action( 'gform_after_delete_field', [ $this, 'after_delete_field' ], 10, 2 ); 72 | add_action( 'shutdown', [ $this, 'update_form_translations_on_shutdown' ] ); 73 | 74 | global $pagenow; 75 | 76 | // todo: Add nonce verification. 77 | // phpcs:disable WordPress.Security.NonceVerification.Recommended 78 | if ( 79 | 'admin.php' === $pagenow && isset( $_GET['page'] ) && 80 | 'gf_edit_forms' === $_GET['page'] && isset( $_GET['id'] ) 81 | ) { 82 | $form_id = filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT ); 83 | $form = RGFormsModel::get_form_meta( $form_id ); 84 | $package = $this->get_form_package( $form ); 85 | 86 | do_action( 'wpml_show_package_language_admin_bar', $package ); 87 | } 88 | // phpcs:enable WordPress.Security.NonceVerification.Recommended 89 | 90 | } 91 | 92 | abstract public function get_type(); 93 | 94 | abstract public function get_st_context( $form ); 95 | 96 | abstract public function update_form_translations( $form_meta, $is_new, $needs_update = true ); 97 | 98 | abstract public function after_delete_form( $form_id ); 99 | 100 | abstract protected function register_strings( $form ); 101 | 102 | abstract protected function gform_id( $id ); 103 | 104 | /** 105 | * Filters the link to the edit page of the Gravity Form 106 | * 107 | * @param string $item 108 | * @param Int $id 109 | * @param string $anchor 110 | * 111 | * @return bool|string 112 | */ 113 | public function get_link( $item, $id, $anchor ) { 114 | $id = $this->gform_id( $id ); 115 | if ( '' === $item && $id && false === $anchor ) { 116 | global $wpdb; 117 | // todo: Add caching. 118 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery 119 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching 120 | $anchor = $wpdb->get_var( 121 | // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 122 | $wpdb->prepare( "SELECT title FROM {$this->get_forms_table_name()} WHERE id = %d", $id ) 123 | ); 124 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching 125 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery 126 | 127 | $item = $anchor ? sprintf( '%s', 'admin.php?page=gf_edit_forms&id=' . $id, $anchor ) : ''; 128 | } 129 | 130 | return $id ? $item : ''; 131 | } 132 | 133 | public function get_document_view_link( $post_view_link, $label, $current_document, $element_type, $content_type ) { 134 | if ( 'package' === $element_type && 'gravity_form' === $content_type ) { 135 | $element_id = apply_filters( 'wpml_element_id_from_package', null, isset( $current_document->ID ) ? $current_document->ID : $current_document->original_doc_id ); 136 | if ( $element_id ) { 137 | $form_id = $this->gform_id( $element_id ); 138 | if ( $form_id ) { 139 | $post_view_link = sprintf( '%s', get_home_url() . '/?gf_page=preview&id=' . $form_id, $label ); 140 | } 141 | } 142 | } 143 | return $post_view_link; 144 | } 145 | 146 | public function get_document_edit_link( $post_view_link, $label, $current_document, $element_type, $content_type ) { 147 | if ( 'package' === $element_type && 'gravity_form' === $content_type ) { 148 | $element_id = apply_filters( 'wpml_element_id_from_package', null, $current_document->ID ); 149 | if ( $element_id ) { 150 | $form_id = $this->gform_id( $element_id ); 151 | if ( $form_id ) { 152 | $post_view_link = sprintf( '%s', 'admin.php?page=gf_edit_forms&id=' . $form_id, $label ); 153 | } 154 | } 155 | } 156 | 157 | return $post_view_link; 158 | } 159 | 160 | public function get_document_edit_url( $edit_url, $content_type, $element_id ) { 161 | if ( 'gravity_form' === $content_type ) { 162 | $element_id = apply_filters( 'wpml_element_id_from_package', null, $element_id ); 163 | if ( $element_id ) { 164 | $form_id = $this->gform_id( $element_id ); 165 | if ( $form_id ) { 166 | $edit_url = 'admin.php?page=gf_edit_forms&id=' . $form_id; 167 | } 168 | } 169 | } 170 | 171 | return $edit_url; 172 | } 173 | 174 | /** 175 | * Fix for default lang parameter settings + default WordPress permalinks. 176 | * 177 | * @param string $link 178 | * 179 | * @return mixed 180 | */ 181 | public function gform_redirect( $link ) { 182 | global $sitepress; 183 | $icl_settings = $sitepress->get_settings(); 184 | if ( 3 === (int) $icl_settings['language_negotiation_type'] ) { 185 | $link = str_replace( '&lang=', '&lang=', $link ); 186 | } 187 | 188 | return $link; 189 | } 190 | 191 | /** 192 | * Returns an array of keys under which translatable strings are saved in a Gravity Form array 193 | * 194 | * @return array 195 | */ 196 | protected function get_form_keys() { 197 | if ( ! isset( $this->_form_keys ) ) { 198 | $this->_form_keys = [ 199 | 'limitEntriesMessage', 200 | 'scheduleMessage', 201 | 'postTitleTemplate', 202 | 'postContentTemplate', 203 | 'button-imageUrl', 204 | 'lastPageButton-text', 205 | 'lastPageButton-imageUrl', 206 | ]; 207 | } 208 | 209 | return apply_filters( 'gform_multilingual_form_keys', $this->_form_keys ); 210 | } 211 | 212 | /** 213 | * Returns an array of keys under which a Gravity Form Field array stores translatable strings 214 | * 215 | * @return array 216 | */ 217 | public function get_field_keys() { 218 | $this->form_fields = apply_filters( 'gform_multilingual_field_keys', $this->field_keys ); 219 | 220 | return $this->form_fields; 221 | } 222 | 223 | private function add_button_to_data( $string_data, $field, $kind, $key ) { 224 | $kind .= 'Button'; 225 | if ( isset( $field[ $kind ][ $key ] ) ) { 226 | $string_data[ 'page-' . ( $field['pageNumber'] - 1 ) . '-' . $kind . '-' . $key ] = $field[ $kind ][ $key ]; 227 | } 228 | 229 | return $string_data; 230 | } 231 | 232 | private function add_pagination_data_deprecated( $string_data, $field ) { 233 | // Page breaks are stored as belonging to the next page, 234 | // but their buttons are actually displayed in the previous page. 235 | $string_data = $this->add_button_to_data( $string_data, $field, 'next', 'text' ); 236 | $string_data = $this->add_button_to_data( $string_data, $field, 'next', 'imageUrl' ); 237 | $string_data = $this->add_button_to_data( $string_data, $field, 'previous', 'text' ); 238 | $string_data = $this->add_button_to_data( $string_data, $field, 'previous', 'imageUrl' ); 239 | 240 | return $string_data; 241 | } 242 | 243 | /** 244 | * Translation job package - collect translatable strings from GF form. 245 | * 246 | * @param int $form_id 247 | * 248 | * @return array 249 | */ 250 | private function get_form_strings_deprecated( $form_id ) { 251 | 252 | $snh = new GFML_String_Name_Helper(); 253 | 254 | $form = RGFormsModel::get_form_meta( $form_id ); 255 | $string_data = $this->get_form_main_strings( $form ); 256 | 257 | // phpcs:ignore Squiz.PHP.CommentedOutCode.Found 258 | // - Paging Page Names - $form["pagination"]["pages"][i] 259 | if ( isset( $form['pagination'] ) ) { 260 | foreach ( $form['pagination']['pages'] as $field_key => $page_title ) { 261 | $snh->page_index = $field_key; 262 | $string_data[ $snh->get_form_pagination_page_title() ] = $page_title; 263 | } 264 | } 265 | 266 | // Fields (including paging fields). 267 | $keys = $this->get_field_keys(); 268 | 269 | foreach ( $form['fields'] as $id => $field ) { 270 | $snh->field = $field; 271 | 272 | if ( 'page' !== $field['type'] ) { 273 | foreach ( $keys as $field_key ) { 274 | if ( isset( $field[ $field_key ] ) && '' !== $field[ $field_key ] ) { 275 | $snh->field_key = $field_key; 276 | $string_data[ $snh->get_field_common() ] = $field[ $field_key ]; 277 | } 278 | } 279 | } 280 | 281 | switch ( $field['type'] ) { 282 | case 'text': 283 | case 'textarea': 284 | case 'email': 285 | case 'number': 286 | case 'section': 287 | break; 288 | 289 | case 'html': 290 | $string_data[ $snh->get_field_html() ] = $field['content']; 291 | break; 292 | 293 | case 'page': 294 | $string_data = $this->add_pagination_data_deprecated( $string_data, $field ); 295 | break; 296 | case 'select': 297 | case 'multiselect': 298 | case 'checkbox': 299 | case 'radio': 300 | case 'list': 301 | if ( ! empty( $field['choices'] ) ) { 302 | foreach ( $field['choices'] as $index => $choice ) { 303 | $snh->field_choice = $choice; 304 | $snh->field_choice_index = $index; 305 | $string_data[ $snh->get_field_multi_input_choice_text() ] = $choice['text']; 306 | } 307 | } 308 | break; 309 | 310 | case 'product': 311 | case 'shipping': 312 | case 'option': 313 | if ( 314 | in_array( $field['inputType'], [ 'select', 'checkbox', 'radio', 'hiddenproduct' ], true ) && 315 | ! empty( $field['choices'] ) 316 | ) { 317 | foreach ( $field['choices'] as $index => $choice ) { 318 | $snh->field_choice = $choice; 319 | $snh->field_choice_index = $index; 320 | $string_data[ $snh->get_field_multi_input_choice_text() ] = $choice['text']; 321 | } 322 | } 323 | break; 324 | case 'post_custom_field': 325 | if ( isset( $field['customFieldTemplate'] ) ) { 326 | $string_data[ $snh->get_field_post_custom_field() ] = $field['customFieldTemplate']; 327 | } 328 | break; 329 | case 'post_category': 330 | if ( isset( $field['categoryInitialItem'] ) ) { 331 | $string_data[ $snh->get_field_post_category() ] = $field['categoryInitialItem']; 332 | } 333 | break; 334 | } 335 | } 336 | 337 | // Confirmations. 338 | foreach ( $form['confirmations'] as $field_key => $confirmation ) { 339 | $snh->confirmation = $confirmation; 340 | switch ( $confirmation['type'] ) { 341 | case 'message': 342 | // Add prefix 'field-' to get a textarea editor box. 343 | $string_data[ $snh->get_form_confirmation_message() ] = $confirmation['message']; 344 | break; 345 | case 'redirect': 346 | $string_data[ $snh->get_form_confirmation_redirect_url() ] = $confirmation['url']; 347 | break; 348 | case 'page': 349 | $string_data[ $snh->get_form_confirmation_page_id() ] = $confirmation['pageId']; 350 | break; 351 | } 352 | } 353 | 354 | // Notifications: translate only those for user submitted emails. 355 | if ( ! empty( $form['notifications'] ) ) { 356 | foreach ( $form['notifications'] as $field_key => $notification ) { 357 | $snh->notification = $notification; 358 | if ( 'field' === $notification['toType'] || 'email' === $notification['toType'] ) { 359 | $string_data[ $snh->get_form_notification_subject() ] = $notification['subject']; 360 | $string_data[ $snh->get_form_notification_message() ] = $notification['message']; 361 | } 362 | } 363 | } 364 | 365 | return $string_data; 366 | } 367 | 368 | private function get_form_main_strings( $form ) { 369 | $string_data = []; 370 | $form_keys = $this->get_form_keys(); 371 | 372 | // Form main fields. 373 | foreach ( $form_keys as $key ) { 374 | $parts = explode( '-', $key ); 375 | if ( count( $parts ) === 1 ) { 376 | if ( isset( $form[ $key ] ) && '' !== $form[ $key ] ) { 377 | $string_data[ $key ] = $form[ $key ]; 378 | } 379 | } else { 380 | if ( isset( $form[ $parts[0] ][ $parts[1] ] ) && '' !== $form[ $parts[0] ][ $parts[1] ] ) { 381 | $string_data[ $key ] = $form[ $parts[0] ][ $parts[1] ]; 382 | } 383 | } 384 | } 385 | 386 | return $string_data; 387 | } 388 | 389 | /** 390 | * Translation job package - collect translatable strings from GF form. 391 | * 392 | * @todo See to merge this and gform_pre_render (already overlapping) 393 | * 394 | * @param int $form_id 395 | * 396 | * @return array Associative array that holds the forms string values as values and uses the ST string name field 397 | * suffixes as indexes. The value $form_id_$index would be the actual ST icl_strings string name. 398 | */ 399 | public function get_form_strings( $form_id ) { 400 | 401 | if ( version_compare( GFCommon::$version, '1.9', '<' ) ) { 402 | return $this->get_form_strings_deprecated( $form_id ); 403 | } 404 | 405 | $snh = new GFML_String_Name_Helper(); 406 | $form = RGFormsModel::get_form_meta( $form_id ); 407 | $string_data = $this->get_form_main_strings( $form ); 408 | 409 | // phpcs:ignore Squiz.PHP.CommentedOutCode.Found 410 | // Pagination - Paging Page Names - $form["pagination"]["pages"][i]. 411 | if ( isset( $form['pagination']['pages'] ) && is_array( $form['pagination']['pages'] ) ) { 412 | foreach ( $form['pagination']['pages'] as $page_index => $page_title ) { 413 | $snh->page_index = $page_index; 414 | $string_data[ $snh->get_form_pagination_page_title() ] = $page_title; 415 | } 416 | } 417 | 418 | // Common field properties. 419 | $keys = $this->get_field_keys(); 420 | 421 | // Fields. 422 | foreach ( $form['fields'] as $id => $field ) { 423 | $snh->field = $field; 424 | 425 | if ( 'page' !== $field->type ) { 426 | foreach ( $keys as $field_key ) { 427 | $snh->field_key = $field_key; 428 | if ( '' !== $field->{$field_key} ) { 429 | $string_data[ $snh->get_field_common() ] = $field->{$field_key}; 430 | } 431 | } 432 | } 433 | 434 | switch ( $field['type'] ) { 435 | case 'text': 436 | case 'textarea': 437 | case 'email': 438 | case 'number': 439 | case 'section': 440 | break; 441 | case 'html': 442 | $string_data[ $snh->get_field_html() ] = $field->content; 443 | break; 444 | case 'page': 445 | /* 446 | * Page breaks are stored as belonging to the next page, 447 | * but their buttons are actually displayed in the previous page 448 | */ 449 | foreach ( [ 'text', 'imageUrl' ] as $page_index ) { 450 | $snh->page_index = $page_index; 451 | if ( isset( $field->nextButton[ $page_index ] ) ) { 452 | $string_data[ $snh->get_field_page_nextButton() ] = $field->nextButton[ $page_index ]; 453 | } 454 | if ( isset( $field->previousButton[ $page_index ] ) ) { 455 | $string_data[ $snh->get_field_page_previousButton() ] = $field->previousButton[ $page_index ]; 456 | } 457 | } 458 | break; 459 | case 'post_custom_field': 460 | // TODO not registered at my tests. 461 | if ( '' !== $field->customFieldTemplate ) { 462 | $string_data[ $snh->get_field_post_custom_field() ] = $field->customFieldTemplate; 463 | } 464 | break; 465 | case 'post_category': 466 | if ( '' !== $field->categoryInitialItem ) { 467 | $string_data[ $snh->get_field_post_category() ] = $field->categoryInitialItem; 468 | } 469 | break; 470 | } 471 | 472 | if ( isset( $field->choices ) && is_array( $field->choices ) ) { 473 | foreach ( $field->choices as $index => $choice ) { 474 | $snh->field_choice = $choice; 475 | $snh->field_choice_index = $index; 476 | $string_data[ $snh->get_field_multi_input_choice_text() ] = $choice['text']; 477 | } 478 | } 479 | } 480 | 481 | // Confirmations. 482 | if ( is_array( $form['confirmations'] ) ) { 483 | foreach ( $form['confirmations'] as $confirmation_index => $confirmation ) { 484 | $snh->confirmation = $confirmation; 485 | switch ( $confirmation['type'] ) { 486 | case 'message': 487 | // Add prefix 'field-' to get a textarea editor box. 488 | $string_data[ $snh->get_form_confirmation_message() ] = $confirmation['message']; 489 | break; 490 | case 'redirect': 491 | $string_data[ $snh->get_form_confirmation_redirect_url() ] = $confirmation['url']; 492 | break; 493 | case 'page': 494 | $string_data[ $snh->get_form_confirmation_page_id() ] = $confirmation['pageId']; 495 | break; 496 | } 497 | } 498 | } 499 | 500 | // Notifications: translate only those for user submitted emails. 501 | if ( is_array( $form['notifications'] ) ) { 502 | foreach ( $form['notifications'] as $notification_index => $notification ) { 503 | $snh->notification = $notification; 504 | if ( 'field' === $notification['toType'] 505 | || 'email' === $notification['toType'] 506 | ) { 507 | $string_data[ $snh->get_form_notification_subject() ] = $notification['subject']; 508 | $string_data[ $snh->get_form_notification_message() ] = $notification['message']; 509 | } 510 | } 511 | } 512 | 513 | return $string_data; 514 | } 515 | 516 | /** 517 | * @param array $form 518 | * @param string $st_context 519 | * 520 | * @return array 521 | */ 522 | private function populate_translated_values( $form, $st_context ) { 523 | $form_keys = $this->get_form_keys(); 524 | 525 | foreach ( $form_keys as $key ) { 526 | $parts = explode( '-', $key ); 527 | if ( count( $parts ) === 1 ) { 528 | if ( isset( $form[ $key ] ) && '' !== $form[ $key ] ) { 529 | $form[ $key ] = icl_t( $st_context, $key, $form[ $key ] ); 530 | } 531 | } else { 532 | if ( isset( $form[ $parts[0] ][ $parts[1] ] ) && '' !== $form[ $parts[0] ][ $parts[1] ] ) { 533 | $form[ $parts[0] ][ $parts[1] ] = icl_t( $st_context, $key, $form[ $parts[0] ][ $parts[1] ] ); 534 | } 535 | } 536 | } 537 | 538 | return $form; 539 | } 540 | 541 | /** 542 | * Front-end form rendering (deprecated). 543 | * 544 | * @param array $form 545 | * 546 | * @return array 547 | */ 548 | public function gform_pre_render_deprecated( $form ) { 549 | // Render the form. 550 | global $sitepress; 551 | $st_context = $this->get_st_context( $form['id'] ); 552 | 553 | $current_lang = $sitepress->get_current_language(); 554 | if ( isset( $this->current_forms[ $form['id'] ][ $current_lang ] ) ) { 555 | return $this->current_forms[ $form['id'] ][ $current_lang ]; 556 | } 557 | 558 | $snh = new GFML_String_Name_Helper(); 559 | 560 | $form = $this->populate_translated_values( $form, $st_context ); 561 | 562 | // phpcs:ignore Squiz.PHP.CommentedOutCode.Found 563 | // - Paging Page Names - $form["pagination"]["pages"][i]. 564 | if ( isset( $form['pagination'] ) ) { 565 | foreach ( $form['pagination']['pages'] as $page_index => $page_title ) { 566 | $snh->page_index = $page_index; 567 | $form['pagination']['pages'][ $page_index ] = icl_t( $st_context, $snh->get_form_pagination_page_title(), $form['pagination']['pages'][ $page_index ] ); 568 | } 569 | } 570 | 571 | // Fields (including paging fields). 572 | $keys = $this->get_field_keys(); 573 | 574 | foreach ( $form['fields'] as $id => $field ) { 575 | 576 | $snh->field = $id; 577 | 578 | foreach ( $keys as $field_key ) { 579 | $snh->field_key = $field_key; 580 | if ( isset( $field[ $field_key ] ) && '' !== $field[ $field_key ] && 'page' !== $field['type'] ) { 581 | $form['fields'][ $id ][ $field_key ] = icl_t( $st_context, $snh->get_field_common(), $field[ $field_key ] ); 582 | } 583 | } 584 | 585 | switch ( $field['type'] ) { 586 | case 'text': 587 | case 'textarea': 588 | case 'email': 589 | case 'number': 590 | case 'section': 591 | break; 592 | 593 | case 'html': 594 | $form['fields'][ $id ]['content'] = icl_t( $st_context, $snh->get_field_html(), $field['content'] ); 595 | break; 596 | 597 | case 'page': 598 | foreach ( [ 'text', 'imageUrl' ] as $page_index ) { 599 | $snh->page_index = $page_index; 600 | if ( isset( $form['fields'][ $id ]['nextButton'][ $page_index ] ) ) { 601 | $form['fields'][ $id ]['nextButton'][ $page_index ] = icl_t( $st_context, $snh->get_field_page_nextButton(), $field['nextButton'][ $page_index ] ); 602 | } 603 | if ( isset( $form['fields'][ $id ]['previousButton'][ $page_index ] ) ) { 604 | $form['fields'][ $id ]['previousButton'][ $page_index ] = icl_t( $st_context, $snh->get_field_page_previousButton(), $field['previousButton'][ $page_index ] ); 605 | } 606 | } 607 | break; 608 | case 'select': 609 | case 'multiselect': 610 | case 'checkbox': 611 | case 'radio': 612 | case 'list': 613 | if ( ! empty( $field['choices'] ) ) { 614 | foreach ( $field['choices'] as $index => $choice ) { 615 | $snh->field_choice = $choice; 616 | $snh->field_choice_index = $index; 617 | $string_name = $snh->get_field_multi_input_choice_text(); 618 | $translation = icl_t( $st_context, $string_name, $choice['text'] ); 619 | $form['fields'][ $id ]['choices'][ $index ]['text'] = $translation; 620 | } 621 | } 622 | break; 623 | case 'product': 624 | case 'shipping': 625 | case 'option': 626 | if ( 627 | in_array( $field['inputType'], [ 'select', 'checkbox', 'radio', 'hiddenproduct' ], true ) && 628 | ! empty( $field['choices'] ) 629 | ) { 630 | foreach ( $field['choices'] as $index => $choice ) { 631 | $snh->field_choice = $choice; 632 | $snh->field_choice_index = $index; 633 | $translation = icl_t( $st_context, $snh->get_field_multi_input_choice_text(), $choice['text'] ); 634 | $form['fields'][ $id ]['choices'][ $index ]['text'] = $translation; 635 | } 636 | } 637 | break; 638 | 639 | case 'post_custom_field': 640 | $form['fields'][ $id ]['customFieldTemplate'] = icl_t( $st_context, $snh->get_field_post_custom_field() . '-customFieldTemplate', $field['customFieldTemplate'] ); 641 | break; 642 | case 'post_category': 643 | $form['fields'][ $id ]['categoryInitialItem'] = icl_t( $st_context, $snh->get_field_post_custom_field(), $field['categoryInitialItem'] ); 644 | break; 645 | } 646 | } 647 | 648 | if ( isset( $form['pagination']['pages'] ) ) { 649 | foreach ( $form['pagination']['pages'] as $page_index => $page_title ) { 650 | $snh->page_index = $page_index; 651 | $form['pagination']['pages'][ $page_index ] = icl_t( $st_context, $snh->get_form_pagination_page_title(), $form['pagination']['pages'][ $page_index ] ); 652 | } 653 | if ( isset( $form['pagination']['progressbar_completion_text'] ) ) { 654 | $form['pagination']['progressbar_completion_text'] = icl_t( $st_context, $snh->get_form_pagination_completion_text(), $form['pagination']['progressbar_completion_text'] ); 655 | } 656 | } 657 | 658 | if ( isset( $form['lastPageButton'] ) ) { 659 | $form['lastPageButton'] = icl_t( $st_context, $snh->get_form_pagination_last_page_button_text(), $form['lastPageButton'] ); 660 | } 661 | 662 | $this->current_forms[ $form['id'] ][ $current_lang ] = $form; 663 | 664 | return $form; 665 | } 666 | 667 | /** 668 | * Front-end form rendering. 669 | * 670 | * @global object $sitepress 671 | * 672 | * @param array $form 673 | * 674 | * @return array 675 | */ 676 | public function gform_pre_render( $form ) { 677 | 678 | global $sitepress; 679 | 680 | $st_context = $this->get_st_context( $form['id'] ); 681 | // Cache. 682 | $current_lang = $sitepress->get_current_language(); 683 | if ( isset( $this->current_forms[ $form['id'] ][ $current_lang ] ) ) { 684 | return $this->current_forms[ $form['id'] ][ $current_lang ]; 685 | } 686 | 687 | $snh = new GFML_String_Name_Helper(); 688 | 689 | $form = $this->populate_translated_values( $form, $st_context ); 690 | 691 | $this->get_global_strings( $form, $st_context ); 692 | 693 | // Pagination. 694 | if ( ! empty( $form['pagination'] ) ) { 695 | // phpcs:ignore Squiz.PHP.CommentedOutCode.Found 696 | // Paging Page Names - $form["pagination"]["pages"][i]. 697 | if ( isset( $form['pagination']['pages'] ) && is_array( $form['pagination']['pages'] ) ) { 698 | foreach ( $form['pagination']['pages'] as $page_index => $page_title ) { 699 | $snh->page_index = $page_index; 700 | $form['pagination']['pages'][ $page_index ] = icl_t( $st_context, $snh->get_form_pagination_page_title(), $page_title ); 701 | } 702 | } 703 | // Completion text. 704 | if ( ! empty( $form['pagination']['progressbar_completion_text'] ) ) { 705 | $form['pagination']['progressbar_completion_text'] = icl_t( $st_context, $snh->get_form_pagination_completion_text(), $form['pagination']['progressbar_completion_text'] ); 706 | } 707 | // Last page button text. 708 | // todo: not registered at my tests. 709 | if ( ! empty( $form['lastPageButton']['text'] ) ) { 710 | $form['lastPageButton']['text'] = icl_t( $st_context, $snh->get_form_pagination_last_page_button_text(), $form['lastPageButton']['text'] ); 711 | } 712 | } 713 | 714 | // Common field properties. 715 | $keys = $this->get_field_keys(); 716 | 717 | $conditional_logic = new GFML_Conditional_Logic(); 718 | 719 | $form = $conditional_logic->translate_conditional_logic( $form, $st_context ); 720 | 721 | // Filter form fields (array of GF_Field objects). 722 | foreach ( $form['fields'] as $id => &$field ) { 723 | 724 | $snh->field = $field; 725 | 726 | // Filter common properties. 727 | foreach ( $keys as $field_key ) { 728 | $snh->field_key = $field_key; 729 | if ( ! empty( $field->{$field_key} ) && 'page' !== $field->type ) { 730 | $field->{$field_key} = icl_t( $st_context, $snh->get_field_common(), $field->{$field_key} ); 731 | } 732 | } 733 | 734 | // Field specific code. 735 | switch ( $field->type ) { 736 | case 'html': 737 | $field->content = icl_t( $st_context, $snh->get_field_html(), $field->content ); 738 | break; 739 | case 'page': 740 | foreach ( [ 'text', 'imageUrl' ] as $page_index ) { 741 | $snh->field_key = $page_index; 742 | if ( ! empty( $field->nextButton[ $page_index ] ) ) { 743 | $field->nextButton[ $page_index ] = icl_t( $st_context, $snh->get_field_page_nextButton(), $field->nextButton[ $page_index ] ); 744 | } 745 | if ( isset( $field->previousButton[ $page_index ] ) ) { 746 | $field->previousButton[ $page_index ] = icl_t( $st_context, $snh->get_field_page_previousButton(), $field->previousButton[ $page_index ] ); 747 | } 748 | } 749 | break; 750 | case 'post_custom_field': 751 | // TODO if multi options - 'choices' (register and translate) 'inputType' => select, etc. 752 | if ( '' !== $field->customFieldTemplate ) { 753 | $field->customFieldTemplate = icl_t( $st_context, $snh->get_field_post_custom_field(), $field->customFieldTemplate ); 754 | } 755 | break; 756 | case 'post_category': 757 | // TODO if multi options - 'choices' have static values (register and translate) 'inputType' => select, etc. 758 | if ( '' !== $field->categoryInitialItem ) { 759 | $field->categoryInitialItem = icl_t( $st_context, $snh->get_field_post_category(), $field->categoryInitialItem ); 760 | } 761 | break; 762 | case 'address': 763 | if ( ! empty( $field->copyValuesOptionLabel ) ) { 764 | $field->copyValuesOptionLabel = icl_t( 765 | $st_context, 766 | $snh->get_field_address_copy_values_option(), 767 | $field->copyValuesOptionLabel 768 | ); 769 | } 770 | break; 771 | case 'name': 772 | if ( isset( $field->inputs ) ) { 773 | foreach ( $field->inputs as $input_index => $input ) { 774 | if ( isset( $input['choices'] ) ) { 775 | foreach ( $input['choices'] as $choice_index => $choice ) { 776 | if ( isset( $choice['text'] ) ) { 777 | do_action( 'wpml_register_single_string', 'gfml_prefix_name_choices', 'text_' . $choice['text'], $choice['text'] ); 778 | $field->inputs[ $input_index ]['choices'][ $choice_index ]['text'] = 779 | apply_filters( 'wpml_translate_single_string', $choice['text'], 'gfml_prefix_name_choices', 'text_' . $choice['text'] ); 780 | } 781 | if ( isset( $choice['value'] ) ) { 782 | do_action( 'wpml_register_single_string', 'gfml_prefix_name_choices', 'value_' . $choice['value'], $choice['value'] ); 783 | $field->inputs[ $input_index ]['choices'][ $choice_index ]['value'] = 784 | apply_filters( 'wpml_translate_single_string', $choice['value'], 'gfml_prefix_name_choices', 'value_' . $choice['value'] ); 785 | } 786 | } 787 | } 788 | } 789 | } 790 | break; 791 | case 'captcha': 792 | $field->captchaLanguage = apply_filters( 'wpml_current_language', null ); 793 | break; 794 | default: 795 | break; 796 | } 797 | 798 | if ( isset( $field->choices ) && is_array( $field->choices ) ) { 799 | $field = $this->handle_multi_input( $field, $st_context ); 800 | } 801 | 802 | $field = $this->maybe_translate_placeholder( $field, $st_context, $form ); 803 | $field = $this->maybe_translate_customLabels( $field, $st_context, $form ); 804 | } 805 | 806 | $this->current_forms[ $form['id'] ][ $current_lang ] = $form; 807 | 808 | return $form; 809 | } 810 | 811 | private function get_global_strings( &$form, $st_context ) { 812 | $snh = new GFML_String_Name_Helper(); 813 | 814 | if ( isset( $form['title'] ) ) { 815 | $form['title'] = icl_t( $st_context, $snh->get_form_title(), $form['title'] ); 816 | } 817 | if ( isset( $form['description'] ) ) { 818 | $form['description'] = icl_t( $st_context, $snh->get_form_description(), $form['description'] ); 819 | } 820 | if ( isset( $form['button']['text'] ) ) { 821 | $form['button']['text'] = icl_t( $st_context, $snh->get_form_submit_button(), $form['button']['text'] ); 822 | } 823 | if ( isset( $form['save']['button']['text'] ) ) { 824 | $form['save']['button']['text'] = icl_t( $st_context, $snh->get_form_save_and_continue_later_text(), $form['save']['button']['text'] ); 825 | } 826 | $this->get_notifications( $form, $st_context ); 827 | $this->get_confirmations( $form, $st_context ); 828 | } 829 | 830 | protected function get_notifications( &$form, $st_context ) { 831 | if ( isset( $form['notifications'] ) && $form['notifications'] ) { 832 | $snh = new GFML_String_Name_Helper(); 833 | foreach ( $form['notifications'] as &$notification ) { 834 | $snh->notification = $notification; 835 | $notification['subject'] = icl_t( $st_context, $snh->get_form_notification_subject(), $notification['subject'] ); 836 | $notification['message'] = icl_t( $st_context, $snh->get_form_notification_message(), $notification['message'] ); 837 | } 838 | } 839 | } 840 | 841 | protected function get_confirmations( &$form, $st_context ) { 842 | if ( isset( $form['confirmations'] ) && $form['confirmations'] ) { 843 | $snh = new GFML_String_Name_Helper(); 844 | foreach ( $form['confirmations'] as &$confirmation ) { 845 | $snh->confirmation = $confirmation; 846 | switch ( $confirmation['type'] ) { 847 | case 'message': 848 | $confirmation['message'] = icl_t( $st_context, $snh->get_form_confirmation_message(), $confirmation['message'] ); 849 | break; 850 | case 'redirect': 851 | $confirmation['url'] = icl_t( $st_context, $snh->get_form_confirmation_redirect_url(), $confirmation['url'] ); 852 | break; 853 | case 'page': 854 | $confirmation['pageId'] = icl_t( $st_context, $snh->get_form_confirmation_redirect_url(), $confirmation['pageId'] ); 855 | break; 856 | } 857 | } 858 | } 859 | } 860 | 861 | private function maybe_translate_placeholder( $field, $st_context, $form ) { 862 | $snh = new GFML_String_Name_Helper(); 863 | $snh->field = $field; 864 | 865 | $string_name = $snh->get_field_placeholder(); 866 | 867 | if ( isset( $field->placeholder ) && $field->placeholder ) { 868 | $field->placeholder = icl_t( $st_context, $string_name, $field->placeholder ); 869 | } 870 | 871 | if ( isset( $field->inputs ) && $field->inputs ) { 872 | foreach ( $field->inputs as $key => $input ) { 873 | $snh->field_input = $input; 874 | if ( isset( $input['placeholder'] ) && $input['placeholder'] ) { 875 | $string_input_name = $snh->get_field_input_placeholder(); 876 | $field->inputs[ $key ]['placeholder'] = icl_t( $st_context, $string_input_name, $field->inputs[ $key ]['placeholder'] ); 877 | } 878 | } 879 | } 880 | 881 | return $field; 882 | } 883 | 884 | private function maybe_translate_customLabels( $field, $st_context, $form ) { 885 | $snh = new GFML_String_Name_Helper(); 886 | $snh->field = $field; 887 | 888 | if ( isset( $field->inputs ) && $field->inputs ) { 889 | foreach ( $field->inputs as $key => $input ) { 890 | $snh->field_input = $input; 891 | if ( isset( $input['customLabel'] ) && $input['customLabel'] ) { 892 | $string_input_name = $snh->get_field_input_customLabel(); 893 | $field->inputs[ $key ]['customLabel'] = icl_t( $st_context, $string_input_name, $field->inputs[ $key ]['customLabel'] ); 894 | } 895 | } 896 | } 897 | 898 | return $field; 899 | } 900 | 901 | private function handle_multi_input( $field, $st_context ) { 902 | $snh = new GFML_String_Name_Helper(); 903 | $snh->field = $field; 904 | 905 | if ( is_array( $field->choices ) ) { 906 | foreach ( $field->choices as $index => $choice ) { 907 | $snh->field_choice = $choice; 908 | $snh->field_choice_index = $index; 909 | $string_name = $snh->get_field_multi_input_choice_text(); 910 | $field->choices[ $index ]['text'] = icl_t( $st_context, $string_name, $choice['text'] ); 911 | if ( isset( $choice['value'] ) ) { 912 | $string_name = $snh->get_field_multi_input_choice_value(); 913 | $field->choices[ $index ]['value'] = icl_t( $st_context, $string_name, $choice['value'] ); 914 | } 915 | } 916 | } 917 | 918 | return $field; 919 | } 920 | 921 | /** 922 | * Translate confirmations before submission. 923 | * 924 | * @param array $form 925 | * 926 | * @return array 927 | */ 928 | public function gform_pre_submission_filter( $form ) { 929 | $form = $this->gform_pre_render( $form ); 930 | if ( ! empty( $form['confirmations'] ) ) { 931 | $snh = new GFML_String_Name_Helper(); 932 | $st_context = $this->get_st_context( $form['id'] ); 933 | foreach ( $form['confirmations'] as $key => &$confirmation ) { 934 | $snh->confirmation = $confirmation; 935 | 936 | switch ( $confirmation['type'] ) { 937 | case 'message': 938 | $confirmation['message'] = icl_t( $st_context, $snh->get_form_confirmation_message(), $confirmation['message'] ); 939 | break; 940 | case 'redirect': 941 | global $sitepress; 942 | $confirmation['url'] = str_replace( '&lang=', '&lang=', $sitepress->convert_url( icl_t( $st_context, $snh->get_form_confirmation_redirect_url(), $confirmation['url'] ) ) ); 943 | break; 944 | case 'page': 945 | $page_id = icl_t( $st_context, $snh->get_form_confirmation_page_id(), $confirmation['pageId'] ); 946 | $confirmation['pageId'] = apply_filters( 'wpml_object_id', $page_id, 'page', true ); 947 | break; 948 | } 949 | } 950 | } 951 | global $sitepress; 952 | $current_lang = $sitepress->get_current_language(); 953 | $this->current_forms[ $current_lang ][ $form['id'] ] = $form; 954 | 955 | return $form; 956 | } 957 | 958 | /** 959 | * Translate notifications. 960 | * 961 | * @param array $notification 962 | * @param array $form 963 | * 964 | * @return array 965 | */ 966 | public function gform_notification( $notification, $form ) { 967 | if ( 'email' === $form['notifications'][ $notification['id'] ]['toType'] 968 | || 'field' === $form['notifications'][ $notification['id'] ]['toType'] 969 | ) { 970 | $snh = new GFML_String_Name_Helper(); 971 | $snh->notification = $notification; 972 | $st_context = $this->get_st_context( $form['id'] ); 973 | $notification['subject'] = icl_t( $st_context, $snh->get_form_notification_subject(), $notification['subject'] ); 974 | $notification['message'] = icl_t( $st_context, $snh->get_form_notification_message(), $notification['message'] ); 975 | } 976 | 977 | if ( 'hidden' === $notification['toType'] ) { 978 | // phpcs:disable WordPress.Security.NonceVerification.Missing 979 | $resume_token = isset( $_POST['gform_resume_token'] ) ? filter_var( wp_unslash( $_POST['gform_resume_token'] ), FILTER_SANITIZE_STRING ) : ''; 980 | $resume_email = isset( $_POST['gform_resume_email'] ) ? filter_var( wp_unslash( $_POST['gform_resume_email'] ), FILTER_SANITIZE_EMAIL ) : ''; 981 | // phpcs:enable WordPress.Security.NonceVerification.Missing 982 | 983 | if ( $resume_token && $resume_email ) { 984 | $st_context = 'gravity_form-' . $form['id']; 985 | $snh = new GFML_String_Name_Helper(); 986 | $snh->notification = $notification; 987 | $notification['subject'] = apply_filters( 'wpml_translate_single_string', $notification['subject'], $st_context, $snh->get_form_notification_subject() ); 988 | $notification['message'] = apply_filters( 'wpml_translate_single_string', $notification['message'], $st_context, $snh->get_form_notification_message() ); 989 | $notification['message'] = GFFormDisplay::replace_save_variables( $notification['message'], $form, $resume_token, $resume_email ); 990 | } 991 | } 992 | 993 | return $notification; 994 | } 995 | 996 | /** 997 | * Translate validation messages. 998 | * 999 | * @param array $result 1000 | * @param mixed $value 1001 | * @param array $form 1002 | * @param array $field 1003 | * 1004 | * @return array 1005 | */ 1006 | public function gform_field_validation( $result, $value, $form, $field ) { 1007 | if ( ! $result['is_valid'] ) { 1008 | $snh = new GFML_String_Name_Helper(); 1009 | $snh->field = $field; 1010 | $st_context = $this->get_st_context( $form['id'] ); 1011 | $result['message'] = icl_t( $st_context, $snh->get_field_validation_message(), $result['message'] ); 1012 | } 1013 | 1014 | return $result; 1015 | } 1016 | 1017 | /** 1018 | * Get translated form. 1019 | * 1020 | * @param string $form_id 1021 | * @param null|String $lang 1022 | * 1023 | * @return array 1024 | */ 1025 | public function get_form( $form_id, $lang = null ) { 1026 | if ( ! $lang ) { 1027 | global $sitepress; 1028 | $lang = $sitepress->get_current_language(); 1029 | } 1030 | 1031 | return isset( $this->current_forms[ $form_id ][ $lang ] ) ? $this->current_forms[ $form_id ][ $lang ] : $this->gform_pre_render( RGFormsModel::get_form_meta( $form_id ) ); 1032 | } 1033 | 1034 | /** 1035 | * Get translated field value to use with merge tags. 1036 | * 1037 | * @param string $value 1038 | * @param string $merge_tag 1039 | * @param string $options 1040 | * @param \GF_Field $field 1041 | * @param string $format 1042 | * 1043 | * @return array|string 1044 | */ 1045 | public function gform_merge_tag_filter( $value, $merge_tag, $options, $field, $format ) { 1046 | 1047 | if ( RGFormsModel::get_input_type( $field ) !== 'multiselect' ) { 1048 | return $value; 1049 | } 1050 | 1051 | $options = []; 1052 | $value = explode( ',', $value ); 1053 | foreach ( $value as $selected ) { 1054 | $options[] = GFCommon::selection_display( $selected, $field, $currency = null, $use_text = true ); 1055 | } 1056 | 1057 | return implode( ', ', $options ); 1058 | } 1059 | 1060 | /** 1061 | * Remove translations of deleted field 1062 | * 1063 | * @param int $form_id 1064 | */ 1065 | public function after_delete_field( $form_id ) { 1066 | $form_meta = RGFormsModel::get_form_meta( $form_id ); 1067 | // It is not new form (second parameter) and when deleting field do not need to update status (third parameter). 1068 | $this->update_form_translations( $form_meta, false, false ); 1069 | } 1070 | 1071 | /** 1072 | * Undocumented. 1073 | * 1074 | * @param array $notification 1075 | * @param array $form 1076 | * 1077 | * @return array 1078 | */ 1079 | public function update_notifications_translations( $notification, $form ) { 1080 | 1081 | $this->add_form_to_shutdown_list( $form ); 1082 | 1083 | return $notification; 1084 | } 1085 | 1086 | /** 1087 | * Undocumented. 1088 | * 1089 | * @param array $confirmation 1090 | * @param array $form 1091 | * 1092 | * @return array 1093 | */ 1094 | public function update_confirmation_translations( $confirmation, $form ) { 1095 | 1096 | $this->add_form_to_shutdown_list( $form ); 1097 | 1098 | return $confirmation; 1099 | } 1100 | 1101 | private function add_form_to_shutdown_list( $form ) { 1102 | if ( ! in_array( $form['id'], $this->forms_to_update_on_shutdown, true ) ) { 1103 | $this->forms_to_update_on_shutdown[] = $form['id']; 1104 | } 1105 | } 1106 | 1107 | /** 1108 | * @return string|false 1109 | */ 1110 | public function get_forms_table_name() { 1111 | global $wpdb; 1112 | 1113 | if ( null !== $this->forms_table_name ) { 1114 | return $this->forms_table_name; 1115 | } 1116 | 1117 | $this->forms_table_name = false; 1118 | 1119 | $name = self::LEGACY_FORMS_TABLE; 1120 | if ( version_compare( GFFormsModel::get_database_version(), '2.3-dev-1', '>' ) ) { 1121 | $name = self::FORMS_TABLE; 1122 | } 1123 | 1124 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery 1125 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching 1126 | // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 1127 | if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}{$name}'" ) === $wpdb->prefix . $name ) { 1128 | $this->forms_table_name = $wpdb->prefix . $name; 1129 | } 1130 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.NoCaching 1131 | // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery 1132 | 1133 | return $this->forms_table_name; 1134 | } 1135 | 1136 | /** 1137 | * @param string $text 1138 | * @param array $form 1139 | * 1140 | * @return string 1141 | */ 1142 | public function gform_pre_replace_merge_tags( $text, $form ) { 1143 | if ( isset( $form['confirmation'] ) && rgar( $form['confirmation'], 'message' ) === $text ) { 1144 | $text = $this->get_translated_confirmation_message( $form, $form['confirmation'] ); 1145 | // todo: Add nonce verification. Next line is temporary. 1146 | // phpcs:disable WordPress.Security.NonceVerification.Missing 1147 | } elseif ( isset( $_POST['gform_resume_token'] ) && isset( $_POST['gform_resume_email'] ) && isset( $form['confirmation'] ) ) { 1148 | // phpcs:enable WordPress.Security.NonceVerification.Missing 1149 | $resume_token = filter_input( INPUT_POST, 'gform_resume_token', FILTER_SANITIZE_STRING ); 1150 | $resume_email = filter_input( INPUT_POST, 'gform_resume_email', FILTER_SANITIZE_EMAIL ); 1151 | $confirmation_message = GFFormDisplay::replace_save_variables( rgar( $form['confirmation'], 'message' ), $form, $resume_token, $resume_email ); 1152 | $confirmation_message = ' '; 1153 | 1154 | if ( $text === $confirmation_message ) { 1155 | foreach ( $form['confirmations'] as $resume_token => $confirmation ) { 1156 | if ( isset( $confirmation['event'] ) && 'form_save_email_sent' === $confirmation['event'] ) { 1157 | $form['confirmations'][ $resume_token ]['message'] = $this->get_translated_confirmation_message( $form, $confirmation ); 1158 | } 1159 | } 1160 | 1161 | if ( isset( $form['confirmation'] ) && 'form_save_email_sent' === $form['confirmation']['event'] ) { 1162 | $form['confirmation']['message'] = $this->get_translated_confirmation_message( $form, $form['confirmation'] ); 1163 | } 1164 | 1165 | $text = GFFormDisplay::replace_save_variables( $form['confirmation']['message'], $form, $resume_token, $resume_email ); 1166 | $text = ' '; 1167 | 1168 | } 1169 | } 1170 | 1171 | return $text; 1172 | } 1173 | 1174 | /** 1175 | * @param array $form 1176 | * @param array $confirmation 1177 | * 1178 | * @return string 1179 | */ 1180 | private function get_translated_confirmation_message( $form, $confirmation ) { 1181 | $st_context = $this->get_st_context( $form['id'] ); 1182 | $string_name_helper = new GFML_String_Name_Helper(); 1183 | $string_name_helper->confirmation = $confirmation; 1184 | return icl_t( $st_context, $string_name_helper->get_form_confirmation_message(), $confirmation['message'] ); 1185 | } 1186 | 1187 | public function update_form_translations_on_shutdown() { 1188 | foreach ( $this->forms_to_update_on_shutdown as $form_id ) { 1189 | $form = RGFormsModel::get_form_meta( $form_id ); 1190 | $this->update_form_translations( $form, false ); 1191 | } 1192 | } 1193 | } 1194 | -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-ar.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-ar.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-de_DE.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-de_DE.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-el.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-el.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-es_ES.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-es_ES.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-fr_FR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-fr_FR.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-he_IL.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-he_IL.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-it_IT.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-it_IT.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-ja.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-ja.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-ko_KR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-ko_KR.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-nl_NL.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-nl_NL.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-pl_PL.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-pl_PL.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-pt_BR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-pt_BR.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-pt_PT.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-pt_PT.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-ru_RU.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-ru_RU.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-sv_SE.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-sv_SE.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-uk.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-uk.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-vi.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-vi.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-zh_CN.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-zh_CN.mo -------------------------------------------------------------------------------- /locale/gravityforms-multilingual-zh_TW.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wp-premium/gravityforms-multilingual/6d748bf4874a824693019e79c14b8d121c7797a7/locale/gravityforms-multilingual-zh_TW.mo -------------------------------------------------------------------------------- /locale/orig/gravityforms-multilingual.po: -------------------------------------------------------------------------------- 1 | # This file was generated by WPML 2 | # WPML is a WordPress plugin that can turn any WordPress site into a full featured multilingual content management system. 3 | # https://wpml.org 4 | msgid "" 5 | msgstr "" 6 | "Content-Type: text/plain; charset=utf-8\n" 7 | "Content-Transfer-Encoding: 8bit\n" 8 | "Project-Id-Version:WPML_EXPORT\n" 9 | "POT-Creation-Date: \n" 10 | "PO-Revision-Date: \n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "Language:en\n" 14 | "MIME-Version: 1.0\n" 15 | 16 | # $form_package = new stdClass(); 17 | # $form_package->kind = __( 'Gravity Form', 'gravity-forms-ml' ); 18 | # $form_package->kind_slug = ICL_GRAVITY_FORM_ELEMENT_TYPE; 19 | 20 | msgid "Gravity Form" 21 | msgstr "" 22 | -------------------------------------------------------------------------------- /plugin.php: -------------------------------------------------------------------------------- 1 | init(); 42 | 43 | global $sitepress; 44 | $current_language = $sitepress->get_current_language(); 45 | new WPML_GFML_Filter_Field_Meta( $current_language ); 46 | 47 | $wpml_gfml_filter_country_field = new WPML_GFML_Filter_Country_Field(); 48 | $wpml_gfml_filter_country_field->add_hooks(); 49 | 50 | do_action( 'wpml_gfml_tm_api_loaded', $GLOBALS['wpml_gfml_tm_api'] ); 51 | } 52 | } 53 | 54 | /** 55 | * Disable the normal wpml admin language switcher for gravity forms. 56 | * 57 | * @param string $state 58 | * 59 | * @return bool 60 | */ 61 | function gfml_disable_wpml_admin_lang_switcher( $state ) { 62 | global $pagenow; 63 | 64 | if ( 'admin.php' === $pagenow && 'gf_edit_forms' === filter_input( INPUT_GET, 'page' ) ) { 65 | $state = false; 66 | } 67 | 68 | return $state; 69 | } 70 | 71 | add_filter( 'wpml_show_admin_language_switcher', 'gfml_disable_wpml_admin_lang_switcher' ); 72 | 73 | /** 74 | * GFML Quiz compatibility 75 | * Instantiate the plugin after GFML 76 | * to get to inject the instance of $gfml_tm_api 77 | * 78 | * @param GFML_TM_API $gfml_tm_api 79 | */ 80 | function wpml_gf_quiz_init( $gfml_tm_api ) { 81 | if ( ! defined( 'GF_QUIZ_VERSION' ) || version_compare( ICL_SITEPRESS_VERSION, '3.2', '<' ) ) { 82 | return; 83 | } 84 | 85 | new WPML_GF_Quiz( $gfml_tm_api ); 86 | } 87 | add_action( 'wpml_gfml_tm_api_loaded', 'wpml_gf_quiz_init' ); 88 | 89 | function wpml_gf_survey_init( $gfml_tm_api ) { 90 | if ( ! defined( 'GF_SURVEY_VERSION' ) ) { 91 | return; 92 | } 93 | 94 | $gf_survey = new WPML_GF_Survey( $gfml_tm_api, new GFML_String_Name_Helper() ); 95 | $gf_survey->add_hooks(); 96 | } 97 | add_action( 'wpml_gfml_tm_api_loaded', 'wpml_gf_survey_init' ); 98 | 99 | $wpml_gfml_activation = new WPML_GFML_Plugin_Activation(); 100 | $wpml_gfml_activation->register_callback(); 101 | -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano' . implode( '
', $notice_paragraphs ) . '
'; 281 | $this->admin_notice .= '