WordPress.org

Make WordPress Core

Opened 5 years ago

Closed 5 years ago

#29269 closed defect (bug) (duplicate)

save_post doesn't fire when unavailable page template saved to page

Reported by: matthewdietsche Owned by:
Milestone: Priority: normal
Severity: major Version: 2.6
Component: Posts, Post Types Keywords: 4.1-early
Focuses: Cc:

Description

When you select a page template for a page, and then switch to a theme without that page template file, the save_post action will never fire due to this logic in wp_insert_post():

	if ( !empty($page_template) && 'page' == $data['post_type'] ) {
		$post->page_template = $page_template;
		$page_templates = wp_get_theme()->get_page_templates( $post );
		if ( 'default' != $page_template && ! isset( $page_templates[ $page_template ] ) ) {
			if ( $wp_error )
				return new WP_Error('invalid_page_template', __('The page template is invalid.'));
			else
				return 0;
		}
		update_post_meta($post_ID, '_wp_page_template',  $page_template);
	}

Change History (7)

#1 @SergeyBiryukov
5 years ago

  • Component changed from Themes to Posts, Post Types
  • Version changed from 3.9.2 to 2.6

Introduced in [7900].

The post is actually updated, but if page_template value is invalid, save_post and related actions never run.

Looks like template validation should happen earlier, before updating the post, or later, after running the actions.

#2 @bobbingwide
5 years ago

  • Severity changed from normal to major

I'm sure this is a duplicate of the problem I commented on in #26809. where I added this note.

In my experience, this bug can lead to loss of data.
It prevents post meta data from being saved, with no message to the user.

In the announcement for WordPress 3.8.3 it was stated that "any loss of content is unacceptable".

I added that

While I don't believe this bug deserves its own quickfix, I'd like it to be reconsidered.

Nothing's happened on #26809. My 26809.1.patch applies directly to this bug.

A workaround is to manually delete the row from the wp_postmeta table where meta_key = 'wp_page_template'.

PS. I have just repeated the process of tracking down this bug. So I'm rather annoyed! Perhaps I should have applied the workaround 6 months ago when I first discovered the problem and developed my fix.

#3 @SergeyBiryukov
5 years ago

  • Keywords 4.1-early added
  • Milestone changed from Awaiting Review to Future Release

Indeed, #26809 mentions this, but focuses on another issue, checking the result of wp_update_post() in edit_post(), which is likely a wontfix.

Let's fix the potential data loss due to an invalid template early in 4.1.

#4 @alley-cat
5 years ago

I've just discovered the same problem. I have a theme with only one page template, therefore the Template UI drop down does not appear, and does not clear the no longer valid page_template.

My solution was to clear the invalid (i.e. no longer exists) page_template on the edit_form_top hook. This clears the value before the UI is rendered, as the invalid page_template is carried to the UI and posted back to wp_insert_post.

My code below for reference.

// Check the post data before saving
function ac_validate_post_data_page_template($post_id) {
	
	// Page
	if ( get_post_type($post_id) == 'page' ) {

		// WordPress will prevent post data saving if a page template has been selected that does not exist
		// This is especially a problem when switching to our theme, and old page templates are in the post data		
		// Unset the page template if the page doesn't exist to allow the post to save

		// Get the WP template name
		$template_file_name = get_post_meta($post_id,'_wp_page_template',TRUE);
		
		// Check the template exists
		if (! ac_page_template_exists($template_file_name) ) {

			// Template doesn't exist so remove the data to allow WP to save
			$post = get_post($post_id);
			delete_post_meta($post_id, '_wp_page_template');
		}	
		
	}
}

// Checks if a page template exists
function ac_page_template_exists($template_file_name) {
	
	// Get the templates
	$page_templates = wp_get_theme()->get_page_templates();

	// Just return if there is an index for our template
	return isset( $page_templates[ $template_file_name ] );
}


// Validate post data when the edit for is displayed
add_action('edit_form_top', 'ac_edit_form_top_hook');
function ac_edit_form_top_hook($post) {
	ac_validate_post_data_page_template($post->ID);
}

#5 @KingYes
5 years ago

I have this problem atm.
What I can to do?

#6 @crstauf
5 years ago

that this throws an error seems to be contradictory to WordPress' behavior: if the page has an invalid template, when the page is visited (on frontend), it simply reverts down to the next relevant theme template file. it doesn't keep the database clean, but is returning WP_Error the right reaction to this situation? If it is, then adding save_post and save_post_page hooks before returning WP_Error seems the best fix. perhaps clearing the post_template/_wp_page_template post metadata is cleaner, but I don't think it matches expected behavior.

#7 @wonderboymusic
5 years ago

  • Milestone Future Release deleted
  • Resolution set to duplicate
  • Status changed from new to closed

Duplicate of #25334.

Note: See TracTickets for help on using tickets.