Make WordPress Core

Opened 3 years ago

Closed 3 years ago

#20921 closed defect (bug) (fixed)

Customizer should check theme errors(), not just exists()

Reported by: nacin Owned by: nacin
Milestone: 3.4 Priority: normal
Severity: normal Version:
Component: Themes Keywords: has-patch commit
Focuses: Cc:


wp-admin/customize.php checks that a theme exists. It should actually check that the theme is error-free.

Note that we need to make a determination for what happens when the current theme has errors. In some cases, this will cause a reversion to the default theme, but not always (search for 'theme_parent_invalid' in class-wp-theme.php).

Attachments (4)

20921.diff (5.8 KB) - added by nacin 3 years ago.
20921.2.diff (6.7 KB) - added by nacin 3 years ago.
20921.3.diff (9.6 KB) - added by nacin 3 years ago.
20921.4.diff (9.7 KB) - added by nacin 3 years ago.
Moves send_origin_headers() above the edit_theme_options cap check.

Download all attachments as: .zip

Change History (12)

3 years ago

#1 @nacin
3 years ago

  • Keywords has-patch commit added

20921.diff does a number of distinct things, so listen up:

What it does and why:

  1. Preview filters are added/removed in start/stop_previewing_theme() only if we are not previewing the active theme.

A theme can have an "error" but still be valid enough to pass validate_current_theme(). The single error that can cause this is "theme_parent_invalid". Per the comment in WP_Theme->get_page_templates(), "If you screw up your current theme and we invalidate your parent, most things still work. Let it slide." How to make this occur: Activate a child theme. Rename the "Template:" header in the style.css to a theme that does not exist. The database still holds the correct 'template'. The theme itself is broken, but WordPress otherwise operates normally.

But, if we add all of the preview filters (which are unnecessary for the active theme), we are pulling the 'template' data from WP_Theme and overwriting what is in the database. This results in a problem. Simply not adding preview filters in this situation allows the DB to win.

  1. If we are previewing the active theme, it validates the active theme before continuing. If the theme is invalid, validate_current_theme() does the switch_theme() to the default theme, so we redirect back to themes.php?broken=true, which is the cause of the diff in themes.php. We can get away with a wp_redirect() here as this can only happen when customize.php is accessed directly, rather than being loaded from within a frame on themes.php. This is because themes.php calls validate_current_theme(), which will revert us back to the default theme before we even show a Customize link.

There is one "bug" related to this, but it is so edge that I actually laughed. If you have themes.php open in one tab, then invalidate your theme, then open customize.php directly, you will get the inner frame redirecting to wp_redirect(). This, I do not care. wontfix, punt, whatever.

  1. $theme->errors() is also checked, but only for the non-active theme. Why? Because validate_current_theme() will handle "fatal" errors for the active theme, and the one non-fatal error, theme_parent_invalid, should be ignored.
  1. wp_die() becomes a protected method (in anticipating of removing the final keyword in 3.5), and $message becomes optional, defaulting to 'Cheatin'. This makes the code a bit less repetitive.

#2 @nacin
3 years ago

20921.2.diff moves the validate_current_theme() check to after_setup_theme, as validate_current_theme() requires both TEMPLATEPATH and STYLESHEETPATH to be set. setup_theme()'s branching and procedural flow is now pretty much completely re-organized, and I think it's much more clean now.

3 years ago

#3 @ryan
3 years ago

Looks good.

#4 @koopersmith
3 years ago

Looks good.

#5 @nacin
3 years ago

_save_feedback() is not implemented correctly, which means this string is lost to the abyss. Also, if you have a lot of themes, then the code that moves div.updated's to below h2's doesn't fire for a while, causing it to jump. In some situations (such as when the admin_notices hook isn't used) there isn't a good workaround, but in this case, we can simply move that code block.

The diff within the code block won't show up easily, but you can see that this was added:

if ( isset( $_GET['previewed'] ) ) { ?>
		<div id="message2" class="updated"><p><?php printf( __( 'Settings saved and theme activated. <a href="%s">Visit site</a>.' ), home_url( '/' ) ); ?></p></div>
		<?php } elseif

So much nicer than the "this theme has widgets" string with the comma splice.

3 years ago

#6 @koopersmith
3 years ago

Still looks good.

#7 @ryan
3 years ago

Looks good.

3 years ago

Moves send_origin_headers() above the edit_theme_options cap check.

#8 @nacin
3 years ago

  • Owner set to nacin
  • Resolution set to fixed
  • Status changed from new to closed

In [21069]:

Theme Customizer: Validate themes with more than just an existence check.

  • The current theme goes through validate_current_theme().
  • If doing a preview of a different theme, we check theme->errors().


  • Don't attach previewing hooks when previewing the current theme.

Aside from being unnecessary, this prevents issues with a theme with
the error of theme_parent_invalid.

  • Call send_origin_headers() earlier, to allow wp_die( '0' ) to properly

be returned in a domain mapping situation.

  • Fix the 'Save & Activate' message on themes.php.

fixes #20921.

Note: See TracTickets for help on using tickets.