web-dev-qa-db-fra.com

Exclure les pages privées et brouillon de la navigation principale lors de l'utilisation du menu personnalisé

Je cherche des moyens d'empêcher les pages "privées" et "brouillon" d'apparaître (pour les administrateurs non connectés) dans le menu de navigation principale d'un site, basé sur un menu personnalisé - autre que la suppression manuelle de telles pages du WP menu personnalisé, puis faites-les glisser lorsque vous les publiez, c’est-à-dire.

FWIW, je suis surpris que le comportement que je recherche ne soit pas le comportement par défaut.

Utiliser: WP 3.4.2

2
Jeff Cohan

J'ai eu un problème similaire et voici la meilleure solution que je pourrais trouver. La raison (je pense) que les éléments privés ou non publiés apparaissent dans les menus est que les éléments de menu sont eux-mêmes des publications et ont leur propre post_status. Cela signifie que dans une situation où une page est marquée comme privée, l'élément de menu de cette page peut toujours être défini pour publier et s'affiche. J'ai écrit un rappel de filtre pour le hook wp_nav_menu_objects qui examine l'objet post_status pour l'objet représenté par l'élément de menu et le supprime du menu si cet objet est privé. Dans mon cas, le problème concernait les pages privées, mais on peut facilement l’adapter aux brouillons. J'autorise également l'affichage des éléments de menu si l'utilisateur est connecté, quelles que soient ses capacités, alors que WP limite par défaut l'accès aux administrateurs à une page privée. Cela peut aussi être facilement adapté.

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); 

Il m'a semblé plus facile et plus approprié de filtrer les éléments de menu que de les masquer avec CSS, votre kilométrage peut varier.

Pour limiter les éléments de menu des pages privées aux administrateurs et aux éditeurs, vous devez pouvoir remplacer current_user_can ('read_private_pages') par !is_user_logged_in ().

5
jjaderberg

J'ai utilisé cela comme une solution pour cacher les brouillons. Vous pouvez masquer les éléments de menu (page brouillon) avec la classe 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: Je ressens la même chose ;-)

4
sinds78

La solution la plus simple consiste à ajouter une classe spécifique aux éléments de menu que vous souhaitez masquer. Et puis les cacher par le biais de CSS.

custom nav menu classes
^ cliquez pour agrandir ^

Les classes CSS ne sont pas visibles par défaut, vous devez l'activer dans l'onglet supérieur Screen Options.

Si votre thème n'imprime pas les classes appropriées dans la balise <body>, ceci aura les conséquences suivantes:

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;
}

Enfin, dans votre style.css, ajoutez cette règle:

body.not-logged-menu .menu-logged-in {display:none}

Autre option , utilisez le filtre suivant:

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;
}

"Manipuler la sortie" semble simple mais se révèle délicat:

3
brasofilo

Les cacher avec CSS est problématique, car ils sont toujours envoyés sur le réseau et exposent ce qui pourrait être des informations sensibles à quiconque regarde la source, à ceux qui désactivent CSS pour une raison quelconque (, par exemple utilisateurs non-voyants - CSS les ralentit sans aucun avantage réel), ainsi que pour les scripts de hacker, etc.

Non, nous avons besoin d’un moyen d’autoriser l’ajout d’éléments de menu à un menu faisant référence à une page ou à un article, mais uniquement afficher ou même envoyez ces éléments de menu par le fil si la page ou le message auquel ils font référence a été entièrement et publiquement Publié. Pas brouillon, pas en attente, pas privé, pas programmé (jusqu'à ce que l'heure prévue soit passée), et certainement pas mis à la corbeille.

Voici une solution que j'ai trouvée ailleurs et que j'ai légèrement modifiée (ajouter au functions.php du thème):

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 );
2
Joel MMCC

Il serait bien préférable d’appeler la base de données au lieu de plusieurs requêtes, surtout si le menu contient plusieurs éléments. Sur la base de certaines des autres réponses, vous pouvez créer une liste d'identifiants approuvés et filtrer les éléments avec cette information. Veuillez noter que les déclarations de tableau sont 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 );
1
p_leo