PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/controllers/FrmStylesController.php +118 -24 6.29 → trunk View file →
@@ -20,8 +20,17 @@
20 20 */
21 21 private static $message;
22 22
23 23 /**
24 + * Cache of the active style object keyed by form ID.
25 + *
26 + * @since 6.32
27 + *
28 + * @var array
29 + */
30 + private static $active_style = array();
31 +
32 + /**
24 33 * @return void
25 34 */
26 35 public static function load_pro_hooks() {
27 36 if ( FrmAppHelper::pro_is_installed() ) {
@@ -134,9 +143,9 @@
134 143 if ( FrmAppHelper::is_style_editor_page( 'edit' ) ) {
135 144 wp_enqueue_style( 'wp-color-picker' );
136 145 }
137 146
138 - wp_enqueue_style( 'frm-custom-theme', admin_url( 'admin-ajax.php?action=frmpro_css' ), array(), $version );
147 + wp_enqueue_style( 'frm-custom-theme', admin_url( 'admin-ajax.php?action=frmpro_css&frm_scope_custom_css=1' ), array(), $version );
139 148
140 149 $style = apply_filters( 'frm_style_head', false );
141 150
142 151 if ( $style ) {
@@ -237,17 +246,18 @@
237 246 *
238 247 * @return void
239 248 */
240 249 private static function get_url_to_custom_style( &$stylesheet_urls ) {
241 - $file_name = '/css/' . self::get_file_name();
250 + $add_css_to_uploads_dir = FrmStyle::add_css_to_uploads_dir();
251 + $file_path = FrmStyle::get_generated_css_file_path( $add_css_to_uploads_dir ) . '/' . self::get_file_name();
242 252
243 - if ( is_readable( FrmAppHelper::plugin_path() . $file_name ) ) {
244 - $url = FrmAppHelper::plugin_url() . $file_name;
245 - } else {
246 - $url = admin_url( 'admin-ajax.php?action=frmpro_css' );
253 + if ( ! is_readable( $file_path ) ) {
254 + $stylesheet_urls['formidable'] = admin_url( 'admin-ajax.php?action=frmpro_css' );
255 + return;
247 256 }
248 257
249 - $stylesheet_urls['formidable'] = $url;
258 + $base_url = $add_css_to_uploads_dir ? wp_upload_dir()['baseurl'] . '/formidable/css/' : FrmAppHelper::plugin_url() . '/css/';
259 + $stylesheet_urls['formidable'] = $base_url . self::get_file_name();
250 260 }
251 261
252 262 /**
253 263 * Use a different stylesheet per site in a multisite install
@@ -257,10 +267,9 @@
257 267 * @return string
258 268 */
259 269 public static function get_file_name() {
260 270 if ( is_multisite() ) {
261 - $blog_id = get_current_blog_id();
262 - return 'formidableforms' . absint( $blog_id ) . '.css';
271 + return 'formidableforms' . absint( get_current_blog_id() ) . '.css';
263 272 }
264 273
265 274 return 'formidableforms.css';
266 275 }
@@ -367,11 +376,10 @@
367 376 FrmAppController::show_error_modal( $error_args );
368 377 return;
369 378 }
370 379
371 - $frm_style = new FrmStyle( $style_id );
372 - $active_style = $frm_style->get_one();
373 - $default_style = self::get_default_style();
380 + $frm_style = new FrmStyle( $style_id );
381 + $active_style = $frm_style->get_one();
374 382
375 383 self::disable_admin_page_styling_on_submit_buttons();
376 384
377 385 /**
@@ -380,9 +388,9 @@
380 388 * @param array{form:\stdClass} $data
381 389 */
382 390 do_action( 'frm_before_render_style_page', compact( 'form' ) );
383 391
384 - self::render_style_page( $active_style, $form, $default_style );
392 + self::render_style_page( $active_style, $form, self::get_default_style() );
385 393 }
386 394
387 395 /**
388 396 * @since 6.0
@@ -525,11 +533,10 @@
525 533
526 534 // If the default style is selected, use the "Always use default" legacy option instead of the default style.
527 535 // There's also a check here for conversational forms.
528 536 // Without the check it isn't possible to select "Default" because "Always use default" will convert to "Lines" dynamically.
529 - $default_style = self::get_default_style();
530 537
531 - if ( $style_id === $default_style->ID && empty( $form->options['chat'] ) ) {
538 + if ( $style_id === self::get_default_style()->ID && empty( $form->options['chat'] ) ) {
532 539 $style_id = 1;
533 540 }
534 541
535 542 // We want to save a string for consistency. FrmStylesHelper::get_form_count_for_style expects the custom style ID is a string.
@@ -626,22 +633,44 @@
626 633 $style = $active_style;
627 634 break;
628 635
629 636 case 'duplicate':
630 - $style = clone $active_style;
631 - $new_style = $frm_style->get_new();
637 + $style = clone $active_style;
638 + $new_style = $frm_style->get_new();
639 + $new_name = self::get_new_style_post_name( $new_style->post_name );
640 +
641 + // The single style custom CSS is nested under the old style's scope. Re-scope it to the
642 + // new style's scope so it unnests correctly for display and re-nests correctly on save.
643 + if ( ! empty( $style->post_content['single_style_custom_css'] ) ) {
644 + $css_scope_helper = new FrmCssScopeHelper();
645 + $unnested_css = $css_scope_helper->unnest( $style->post_content['single_style_custom_css'], 'frm_style_' . $style->post_name ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
646 + $style->post_content['single_style_custom_css'] = $css_scope_helper->nest( $unnested_css, 'frm_style_' . $new_name );
647 + }
648 +
632 649 $style->ID = $new_style->ID;
633 - $style->post_name = $new_style->post_name;
634 - unset( $new_style );
650 + $style->post_name = $new_name;
651 + unset( $new_style, $new_name );
635 652 break;
636 653
637 654 case 'new_style':
638 - $style = $frm_style->get_new();
655 + $style = $frm_style->get_new();
656 + $style->post_name = self::get_new_style_post_name( $style->post_name );
639 657 break;
640 - }
658 + }//end switch
641 659
642 660 if ( in_array( $view, array( 'duplicate', 'new_style' ), true ) ) {
643 - $style->post_title = FrmAppHelper::simple_get( 'style_name' );
661 + // A new or duplicated style has no ID yet, so the Rename modal updates the post_title input
662 + // instead of calling an endpoint. Prefer that posted title over $_GET['style_name'] when present.
663 + $posted_title = '';
664 +
665 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
666 + if ( isset( $_POST['frm_style_setting']['post_title'] ) ) {
667 + // The nonce is verified in FrmStylesController::save_style before this renders.
668 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
669 + $posted_title = sanitize_text_field( wp_unslash( $_POST['frm_style_setting']['post_title'] ) );
670 + }
671 +
672 + $style->post_title = '' !== $posted_title ? $posted_title : FrmAppHelper::simple_get( 'style_name' );
644 673 $style->menu_order = 0;
645 674 }
646 675
647 676 if ( ! isset( $style ) ) {
@@ -665,8 +694,27 @@
665 694 include $style_views_path . 'show.php';
666 695 }
667 696
668 697 /**
698 + * Derive the temporary post_name (CSS scope slug) for a new or duplicated style from the chosen
699 + * style name so the displayed scope matches the slug WordPress will store on save.
700 + *
701 + * Falls back to the auto-generated key when no style name was provided so the scope is never empty.
702 + *
703 + * @since 6.32
704 + *
705 + * @param string $fallback The auto-generated post_name to use when no style name is chosen.
706 + *
707 + * @return string
708 + */
709 + private static function get_new_style_post_name( $fallback ) {
710 + $style_name = FrmAppHelper::simple_get( 'style_name' );
711 + $slug = $style_name ? sanitize_title( $style_name ) : '';
712 +
713 + return $slug ? $slug : $fallback;
714 + }
715 +
716 + /**
669 717 * @since 6.0
670 718 *
671 719 * @return string
672 720 */
@@ -986,10 +1034,9 @@
986 1034 if ( ! $style_id ) {
987 1035 // A style ID is not sent when resetting on the edit page.
988 1036 // Instead of resetting the style, send the defaults back so the inputs can be updated with JavaScript.
989 1037 $frm_style = new FrmStyle();
990 - $defaults = $frm_style->get_defaults();
991 - echo json_encode( $defaults );
1038 + echo json_encode( $frm_style->get_defaults() );
992 1039 wp_die();
993 1040 }
994 1041
995 1042 $frm_style = new FrmStyle();
@@ -1235,8 +1282,52 @@
1235 1282 return $frm_style->get_one();
1236 1283 }
1237 1284
1238 1285 /**
1286 + * Get the active style object for a field's form.
1287 + *
1288 + * @since 6.32
1289 + *
1290 + * @param array|int $field The 'field' array.
1291 + *
1292 + * @return object
1293 + */
1294 + public static function get_active_style( $field ) {
1295 + if ( ! is_array( $field ) ) {
1296 + return new stdClass();
1297 + }
1298 +
1299 + $form_id = $field['parent_form_id'] ?? $field['form_id'];
1300 +
1301 + if ( isset( self::$active_style[ $form_id ] ) ) {
1302 + return self::$active_style[ $form_id ];
1303 + }
1304 +
1305 + $active_style = self::get_form_style( $form_id );
1306 +
1307 + if ( ! is_object( $active_style ) ) {
1308 + $active_style = new stdClass();
1309 + }
1310 +
1311 + self::$active_style[ $form_id ] = $active_style;
1312 +
1313 + return self::$active_style[ $form_id ];
1314 + }
1315 +
1316 + /**
1317 + * Get the style setting key that stores the alignment for a field type.
1318 + *
1319 + * @since 6.32
1320 + *
1321 + * @param string $field_type
1322 + *
1323 + * @return string
1324 + */
1325 + public static function get_align_key_for_style_settings( $field_type ) {
1326 + return 'checkbox' === $field_type ? 'check_align' : 'radio_align';
1327 + }
1328 +
1329 + /**
1239 1330 * @param string $class
1240 1331 * @param string $style
1241 1332 *
1242 1333 * @return string
@@ -1445,8 +1536,11 @@
1445 1536 wp_send_json_error( $data, 400 );
1446 1537 die();
1447 1538 }
1448 1539
1540 + /**
1541 + * @var WP_Post|null $post
1542 + */
1449 1543 $post = get_post( $style_id );
1450 1544
1451 1545 if ( ! $post || $post->post_type !== self::$post_type ) {
1452 1546 $data = array(