サポート » 使い方全般 » 存在しないページテンプレートを設定中の固定ページで save_postアクション

  • 解決済 mizube

    (@mizube)


    お世話になります。不具合なのか作り方が悪いのか判別出来ませんので、不具合報告でなく使い方全般に投稿します。

    表題のとおりなのですが、存在しないページテンプレートを設定中の固定ページでは、save_postアクションフックが動作しないようです。

    作成中のテーマをテスト中に遭遇したのですが、

    1. 固定ページのテンプレートファイルを作成
    2. 管理画面で固定ページにテンプレートを設定
    3. テンプレートファイルを削除

    という手順を踏んだあと、固定ページの編集画面からページテンプレートを選択するドロップダウンボックスが表示されなくなりますが、この状態では save_post アクションフックが動作しません。

    save_post にフックしている関数内の処理中に細かく update_option( '__debug', '処理の内容' ); と記述して、別の場所で var_dump( get_option( '__debug' ) ); で止まったところを確認しようと試みましたが、そもそもこのフック自体が動作していないようでした。

    対処法は既に見つけており、再度テンプレートファイルを作成し、ドロップダウンボックスを表示させると、再び動作するようになります。また、存在しないページテンプレートを設定した固定ページでこの不具合が発生している状態でも、デフォルトテンプレートに設定されている固定ページでは、この save_post アクションフックが動作することも確認しました。つまり、ページテンプレートのファイルを削除する前に、管理画面から手動で固定ページのテンプレートをデフォルトのテンプレートに戻しておけばよいということです。

    また、複数テンプレートファイルが存在し、途中で一部のテンプレートファイルを削除した場合についてですが、削除したページテンプレートを設定した固定ページを保存するとデフォルトテンプレートに戻りますが、その際の1回についても save_post アクションフックが動作しません。

    こうしたケースを想定した対策などありましたら教えてください。

10件の返信を表示中 - 1 - 10件目 (全10件中)
  • @mizubeさん

    私が、WordPressを始めたころ、このフォーラムで、いろいろと教えていただいた事、今でも鮮明に覚えています。今私は、Raindropsというテーマを作っていますが、あの頃教えていただいた カスタムフィールドのスタイルを、ヘッダーに埋め込む方法など、テーマで今でも使わさせていただいています。

    改めて、お礼申し上げます。

    さて、

    add_action('save_post','my_save_post',10,2);
    function my_save_post($id,$post){
    	add_post_meta($id, 'hello', 'world', true);
    }

    フィルタを追加して、ご指摘の動作を確認してみましたが、

    という手順を踏んだあと、固定ページの編集画面からページテンプレートを選択するドロップダウンボックスが表示されなくなりますが、この状態では save_post アクションフックが動作しません。

    の部分なのですが、私の環境では、ドロップダウンボックスが消えることはなく、デフォルトテンプレートに戻っているようです。

    1. 固定ページのテンプレートファイルを作成
    2. 管理画面で固定ページにテンプレートを設定
    3. テンプレートファイルを削除
    4. ページをリロード

    という手順でやってみましたが、手順が間違っていますか?

    $wp_version = ‘4.0’;

    トピック投稿者 mizube

    (@mizube)

    nobita さん、丁寧なご返信ありがとうございます。

    公式にテーマを登録されているんですね! 素晴らしい! いつか私もプラグインやテーマの登録をやってみたいと思っています。いつかその時が来ましたら、ご相談に乗って頂けると嬉しいです。

    私の環境では、ドロップダウンボックスが消えることはなく、デフォルトテンプレートに戻っているようです。

    そうですね、私の環境でも、ページテンプレートを削除し、リロードすると、ページテンプレート自体はデフォルトに戻ります。問題は、それとは別の内容で、この時、設定したはずの save_post アクションフックが効かなくなってしまった(以後 update_post_meta 出来ない)、という状況なのです。

    うまく説明できておらず申し訳ありません。

    複数のページテンプレートが存在する場合は、ページをリロードすることでこの問題は解消しますが、ページテンプレートが1つのみ存在し、その1つを固定ページに設定した状態で、テンプレートファイルを削除した場合(ページ属性のメタボックスにページテンプレートのドロップダウンが表示されなくなった状態)に、削除したそのページテンプレートを設定している固定ページにおいてのみ、この状況が発生します。

    なお、見かけ上はデフォルトテンプレートに戻っているのですが、カスタムフィールドに格納されたページテンプレートの情報(_wp_page_template の値)は、削除したページテンプレートファイルのままになっており、その状態にあると(?)、save_post アクションフックを使ってのメタ情報の更新が出来ないように思います。

    一応私の書いたコードの一部を。だいたいこんな感じでテーマやプラグインを作っています。
    固定ページごとに、個別にナビゲーションメニューを設定するメタボックスを追加しようとしています。(ページテンプレートを設定していない固定ページでは動作します)

    class My_Theme_Core {
    	public $textdomain = 'my-theme';
    
    	// for silent call
    	public static function __boot() {
    		$class = __CLASS__;
    		new $class();
    	}
    
    	public function __construct() {
    		$langs_dir = basename( dirname(__FILE__) ) . '/languages/';
    		load_plugin_textdomain( $this->textdomain, false, $langs_dir );
    		$this->add_actions();
    		// ...
    	}
    
    	/*
    	 * Actions
    	 */
    	protected function add_actions() {
    		$this->add_action( 'admin_init' );
    		$this->add_action( 'save_post', 10, 2 );
    		// ...
    	}
    
    	protected function add_action( $hook, $priority=10, $num_args=1 ) {
    		$method = 'action_' . $hook;
    		$this->add_action_with_callback( $hook, $method, $priority, $num_args );
    	}
    
    	protected function add_action_with_callback( $hook, $method, $priority=10, $num_args=1 ) {
    		if ( method_exists( $this, $method ) && is_callable( array( $this, $method ) ) ) {
    			add_action( $hook, array( $this, $method ), $priority, $num_args );
    		}
    	}
    
    	public function action_admin_init() {
    		// add_meta_box();
    		// ...
    	}
    
    	public function action_save_post( $post_id, $post ) {
    		if ( !isset( $_POST['post_nav_menu_nonce'] ) )
    			return;
    
    		if ( !wp_verify_nonce( $_POST['post_nav_menu_nonce'] , 'post_nav_menu' ) )
    			return;
    
    		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
    			return;
    
    		if ( !isset( $_POST['post_type'] ) || !post_type_exists( $_POST['post_type'] ) )
    			return;
    
    		// retrieve 'edit_post' meta-cap and check capability
    		$edit_post_cap = get_post_type_object( $_POST['post_type'] )->cap->edit_post;
    		if ( !current_user_can( $edit_post_cap, $post_id ) )
    			return;
    
    		// update post_meta value
    		if ( isset( $_POST['post_nav_menu'] ) ) {
    			$post_nav_menu = intval( $_POST['post_nav_menu'] );
    			update_post_meta( $post_id, '_post_nav_menu', $post_nav_menu );
    		}
    	}
    }
    トピック投稿者 mizube

    (@mizube)

    もう一つ、対処方法のメモ。どこかのタイミングで以下を実行。

    delete_post_meta( $post_id, '_wp_page_template' );
    // or update_post_meta( $post_id '_wp_page_template', 'default' );

    トピック投稿者 mizube

    (@mizube)

    再々投稿すみません。

    ドロップダウンボックスが消えることはなく

    の重要性を読み飛ばしていました。うーん、私の環境ですと、ページテンプレートが1つもない場合には、「ページテンプレート」のドロップダウンボックスは表示されないのです。以前からそういう仕様だと記憶していたのですが・・・・・・。

    その1つを固定ページに設定した状態で、テンプレートファイルを削除した場合(ページ属性のメタボックスにページテンプレートのドロップダウンが表示されなくなった状態)に、削除したそのページテンプレートを設定している固定ページにおいてのみ、この状況が発生します。

    すみません、複数のテンプレートがある状態で見てみただけでした。

    index.php(fallback template)だけで作成したテーマで(enough ver 0.56 ここにありますindexしか使っていないのは、0.56までなのでご注意ください)、save_post アクションが動作するかどうかを調べてみました。

    ページ属性:テンプレートのセレクトボックスはありません。

    add_action( 'save_post', 'my_save_post', 10, 2 );
    
    function my_save_post( $id, $post ) {
    	add_post_meta( $id, __FUNCTION__, $post->ID, true );
    }
    
    add_action( 'wp_insert_post', 'my_save_post2', 10, 2 );
    
    function my_save_post2( $id, $post ) {
    	add_post_meta( $id, __FUNCTION__, $post->ID, true );
    }

    新規固定ページを、作成すると、作成した時点で、カスタムフィールド my_save_post postid ありで、作成されてしまいました。

    デフォルト(Twentyfourteen)で同じテストを実施
    contributors.php,full-width.php,page.phpを削除して、ページテンプレート同様のテストを行いました

    得られた結果は、同じでした

    次に、投稿保存ごとに、カスタムフィールドが書き換わるかをテストするために、関数を若干変更

    add_action( 'save_post', 'my_save_post', 10, 2 );
    
    function my_save_post( $id, $post ) {
    	add_post_meta( $id, __FUNCTION__, $post->post_content, true );
    }
    
    add_action( 'wp_insert_post', 'my_save_post2', 10, 2 );
    
    function my_save_post2( $id, $post ) {
    	add_post_meta( $id, __FUNCTION__, $post->post_content, true );
    }

    新規投稿ボタンを押したときに、作成された my_save_post postid, my_save_post2 postidがそのまま維持され、投稿内容の変更は行われませんでした。

    いったんカスタムフィールドを削除し保存すると、カスタムフィールドにコンテンツが保存されました。

    Twentyfourteen, enough(ver0.56) 両方が同じ結果でした。

    更新ごとに、フィールドが更新されるように、更にテストコードを変更しました

    update_post_meta( $id, __FUNCTION__, $post->post_content, true );

    でも、同様の結果でした。

    なので、delete_post_metaを追加

    次に、投稿保存ごとに、カスタムフィールドが書き換わるかをテストするために、関数を若干変更

    add_action( 'save_post', 'my_save_post', 10, 2 );
    
    function my_save_post( $id, $post ) {
    	delete_post_meta( $id, __FUNCTION__, $post->post_content, true );
    	add_post_meta( $id, __FUNCTION__, $post->post_content, true );
    }
    
    add_action( 'wp_insert_post', 'my_save_post2', 10, 2 );
    
    function my_save_post2( $id, $post ) {
    	delete_post_meta( $id, __FUNCTION__, $post->post_content, true );
    	add_post_meta( $id, __FUNCTION__, $post->post_content, true );
    }

    delete_post_metaを追加する事で、投稿の更新ごとにフィールドが変更されるようになりました。

    Twentyfourteen のページテンプレートホルダを削除したものを用意して、同様のテストを行いました。

    pageテンプレートだけなのでページ属性メタボックスには、テンプレート選択ダイヤログは表示されません

    結果は、更新ごとに変更されました。

    enough テーマでは、空のpage.phpを用意してテストしました。

    結果は、更新ごとに変更されました。

    最後に、デフォルトテーマで、固定ページを作成後、テンプレートを削除し、再度編集し、保存したところ、フィールドのレコードも正常に変更されました。

    以上のことから、_post_nav_menuを、いったん post_nav_menuに変更していただいて、
    新規作成時にフィールドがすでに生成されていないかどうかをチェックしてみられるといいかもしれません。

    $wp_version = ‘4.1-alpha-30041’;

    ページなしで、old valueを明示すれば、以下でも動くみたいです

    add_action( 'save_post', 'my_save_post', 10, 2 );
    
    function my_save_post( $id, $post ) {
    	//delete_post_meta( $id, __FUNCTION__ );
    	$old_val = get_post_meta($id, __FUNCTION__, true);
    	update_post_meta( $id, __FUNCTION__, $post->post_content, $old_val );
    }
    
    add_action( 'wp_insert_post', 'my_save_post2', 10, 2 );
    
    function my_save_post2( $id, $post ) {
    	//delete_post_meta( $id, __FUNCTION__);
    	$old_val = get_post_meta($id, __FUNCTION__, true);
    	update_post_meta( $id, __FUNCTION__, $post->post_content, $old_val );
    }

    もうすでに、そのように書かれているんですけど、、、

    動かないという点、結局再現できず ごめんなさい

    $post_nav_menu = intval( $_POST['post_nav_menu'] );

    既存の値を $_POSTで渡してみえますが、そのあたりは、どうですか?

    新規投稿を開いた時点で、フィールドが作成されているとすると、フィールドの値は空ですよね。
    intvalで0になり、その値が、old valueと異なるので、更新が行われないといった事は、考えられませんか?

    トピック投稿者 mizube

    (@mizube)

    nobitaさん、お忙しいなか丁寧に検証して頂きありがとうございます。

    対応策として検証して頂いた以下について、

    以上のことから、_post_nav_menuを、いったん post_nav_menuに変更していただいて、
    新規作成時にフィールドがすでに生成されていないかどうかをチェックしてみられるといいかもしれません。

    カスタムフィールドのメタボックスに表示される、キー名の頭にアンダースコアのないメタデータは、一度保存されるとカスタムフィールドの項目として取り扱われるためきちんと動作するのではと思いました。カスタムフィールドのメタボックスにて追加・変更した値は、問題の起きているページでもきちんと反映されているからです。

    でも、対応方法としては十分ですよね。ユーザーが間違った値を入力しないよう、あくまで隠しパラメータとしておきたかったのですが、これ以上ご迷惑をお掛けするわけにはいきません。

    また、私はもう少し post_meta の扱いに対する理解を深める必要がありそうです(笑)

    動かないという点、結局再現できず ごめんなさい

    nobitaさんの検証を追ってみる必要がありますが、やはり私のコードに問題がありそうですね。そして、私もここに投稿する前に、デフォルトの環境で同じ動作が起こるものなのか、まず確かめるべきでした。その上で検証を進めていきたいと思います。

    状況が判明次第、ここに投稿させて頂きます。
    この度は本当にありがとうございました。

    モデレーター jim912

    (@jim912)

    更新の際の挙動ですが、

    1. wp-admin/post.php で edt_post を実行
    2. edt_posit から wp_update_post を実行
    3. wp_update_post から wp_insert_post を実行
    4. wp_insert_post の最後で save_post アクションを実行

    となります。

    このとき、wp_insert_post の実行処理、wp-includes/post.php の 3417-3428行(Ver 4.0)において、ページテンプレートの更新処理を行っていますが、指定されたテンプレートが実在しない場合、エラー処理で return されてしまい、これ以降の処理が行われません。
    つまり、save_post アクションも実行されなくなります。

    ドロップダウンでテンプレートも選らんでいないのに、ページテンプレートの値が入ってくるのは、wp_update_post 内で現在のデータを取得する処理(wp-includes/post.php 3541行目)で、ページテンプレートの値も合わせて取得しているためです。

    トピック投稿者 mizube

    (@mizube)

    jim912 さん、回答ありがとうございます。

    教えて頂いたコードを確認しました、確かに return されていました。コードを遡ってみましたが、 $postarr がフィルタを通過しないデータなので、POST 後にこの部分のチェックを安全かつ適切に回避する手段はなさそうですね。とにかくスッキリしました!

    これは編集ページのどこかのフックで、ページテンプレートが存在しないのに _wp_page_template が設定されている場合に page_template の隠しフィールドで default 値を送ってやるようにすればよさそう?

    ところで、本家 Codex の wp_insert_post() のページにも、

    ‘page_template’: If post_type is ‘page’, will attempt to set the page template. On failure, the function will return either a WP_Error or 0, and stop before the final actions are called.

    とありました。ちゃんと読めよって話ですね…。
    nobitaさん、gim912さん、ありがとうございました。
    解決済みと致します。

    トピック投稿者 mizube

    (@mizube)

    jim912さん、最後の最後でお名前を間違えてしまっていました、申し訳ございません……。

10件の返信を表示中 - 1 - 10件目 (全10件中)
  • トピック「存在しないページテンプレートを設定中の固定ページで save_postアクション」には新たに返信することはできません。