手動で_からそのようなページを削除する以外に、カスタムメニューに基づくサイトの[Primary Navigation]メニューに "非公開"や "下書き"ページが表示されないようにする方法を探しています。WPカスタムメニューを開き、公開されたらドラッグします。
FWIW、探している動作がデフォルトではないことに驚きました。
使用方法:WP 3.4.2
私は同じような問題を抱えていて、これが私が思い付くことができる最も良い解決策です。非公開アイテムや非公開アイテムがメニューに表示されるのは、そのメニューアイテム自体が投稿であり、独自のpost_status
を持っているからです。つまり、ページが非公開に設定されている状況でも、そのページのメニュー項目は公開するように設定でき、表示されます。私はwp_nav_menu_objects
フックのためのフィルタコールバックを書きました。それはメニューアイテムが表すオブジェクトのためにpost_status
を見て、そのオブジェクトがプライベートであるならばそれをメニューから取り除きます。私の場合は、プライベートページが問題でしたが、ドラフト用にこれを簡単に調整することができます。ユーザーがログインしている場合でも、メニュー項目を表示できるようにします。ただし、WPは、デフォルトで、プライベートページへのアクセスを管理者および編集者に制限します。これもまた容易に適合させることができる。
function jj_filter_private_pages_from_menu ($items, $args) {
foreach ($items as $ix => $obj) {
if (!is_user_logged_in () && 'private' == get_post_status ($obj->object_id)) {
unset ($items[$ix]);
}
}
return $items;
}
add_filter ('wp_nav_menu_objects', 'jj_filter_private_pages_from_menu', 10, 2);
メニュー項目をCSSで非表示にするよりも、メニュー項目をフィルタリングする方が簡単かつ適切であるように思われます。
プライベートページのメニュー項目を管理者や編集者に限定するには、current_user_can ('read_private_pages')
を!is_user_logged_in ()
に置き換えることができるはずです。
ドラフトページを非表示にするためのソリューションとしてこれを使用しました。 li.draftクラスを使用して、(ドラフトページ)メニュー項目を非表示にすることができます。
add_filter('nav_menu_css_class' , 'nav_menu_add_post_status_class' , 10 , 2);
function nav_menu_add_post_status_class($classes, $item){
$post_status = get_post_status($item->object_id);
$classes[] = $post_status;
return $classes;
}
FWIW:私は同じように感じます;-)
最も簡単な解決策は、隠したいメニュー項目に特定のクラスを追加することです。そしてCSSを通してそれらを隠します。
CSSクラスはデフォルトでは表示されません。上部のScreen Options
タブで有効にする必要があります。
あなたのテーマが<body>
タグの中の関連するクラスを印刷しないならば、これはそうするでしょう:
add_filter( 'body_class', 'wpse_67929_body_class' );
function wpse_67929_body_class( $classes )
{
if( !is_user_logged_in() )
$classes[] = 'not-logged-menu';
return $classes;
}
最後に、あなたのstyle.css
に、このルールを追加してください:
body.not-logged-menu .menu-logged-in {display:none}
他のオプション、次のフィルタを使用します。
add_filter('wp_nav_menu_items', 'wpse_67929_nav_menu_items', 10, 2 );
function wpse_67929_nav_menu_items( $nav_menu, $args )
{
// Manipulate the output
// $nav_menu contains a single string with the menu Html structure
// more or less like this:
// <li id class><a href>Menu Item</a></li> <ul><li><a>Submenu Item</li></ul> <etc>
return $nav_menu;
}
「出力の操作」は簡単に思えますが、注意が必要です。
それらをCSSで隠すことは問題があります、彼らはまだネットワークを介して送信され、ソースを見る人、CSSを何らかの理由で無効にする人(eg blind users — CSSは、実際のメリットが得られないまで速度を落とすだけです)、ハッカースクリプトなどに。
いいえ、ページまたは投稿を参照するメニューにメニュー項目を追加できるようにする方法が必要です。ただし、showまたはsendを介してそれらのメニュー項目のみを追加できます。参照先のページまたは投稿が完全であり、かつpublicly公開されている場合。ドラフト、保留、プライベート、スケジュール、スケジュールされた時間が経過するまで、および確かにゴミ箱ではありません。
別の場所で見つけた解決策を少し修正しました(テーマのfunctions.php
に追加):
function exclude_draft_nav_items( $items, $menu, $args )
{
global $wpdb;
//add your custom posttypes to this array
$allowed_posttypes = array( 'post', 'page' );
$sql = "SELECT ID FROM {$wpdb->prefix}posts WHERE (post_status!='publish') AND ID=%d && post_type=%s";
foreach ( $items as $k => $item )
{
if( in_array($item->object, $allowed_posttypes) )
{
$query = $wpdb->prepare( $sql, $item->object_id, $item->object );
$result = $wpdb->get_var( $query );
if( $result ) unset($items[$k]);
}
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'exclude_draft_nav_items', 10, 3 );
特にメニューに複数の項目がある場合は、複数のクエリではなくデータベースを1回呼び出す方がはるかに良いでしょう。他のいくつかの回答に基づいて、承認済みIDのリストを作成し、それを使用して項目をフィルタリングできます。配列宣言はPHP7.0以降です。
function exclude_draft_nav_items( $items, $menu, $args ){
global $wpdb;
$ids = [];
$out = [];
foreach( $items as $k=>$v ){
$ids[] = $v->object_id;
}
$ids = join( ',', $ids );
$res = $wpdb->get_results("SELECT ID FROM $wpdb->posts WHERE ID IN ($ids) AND post_status = 'publish'");
$ids = [];
foreach( $res as $v ){
$ids[ $v->ID ] = true;
}
foreach( $items as $v ){
if( !isset( $ids[$v->object_id] ) ){
continue;
}
$out[] = $v;
}
return $out;
}
add_filter( 'wp_get_nav_menu_items', 'exclude_draft_nav_items', 10, 3 );