কাস্টম ওয়াকারের সাথে wp_nav_menu বিভক্ত করুন


16

আমি এমন একটি মেনু তৈরির চেষ্টা করছি যা সর্বাধিক 5 টি আইটেম দেখায়। যদি আরও আইটেম থাকে তবে এগুলি <ul>একটি ড্রপডাউন তৈরি করতে অন্য এলিমেন্টে মোড়ানো উচিত ।

5 বা তার কম আইটেম:

ড্রপডাউন

6 আইটেম বা আরও বেশি

ড্রপডাউন

আমি জানি যে এই ধরণের কার্যকারিতাটি সহজেই এমন একটি ওয়াকারের সাথে তৈরি করা যেতে পারে যা মেনু আইটেমগুলি গণনা করে এবং মোড়ানো হয় যদি সেখানে আরও 5 টি পৃথক পৃথক অংশে থাকে <ul>। তবে আমি জানি না কীভাবে এই ওয়াকার তৈরি করতে হয়।

এই মুহুর্তে আমার মেনুটি দেখায় এমন কোডটি নিম্নলিখিত:

<?php wp_nav_menu( array( 'theme_location' => 'navigation', 'fallback_cb' => 'custom_menu', 'walker' =>new Custom_Walker_Nav_Menu ) ); ?>

আমি লক্ষ্য করেছি যে যদি মেনুটি ব্যবহারকারী দ্বারা সংজ্ঞায়িত না করা হয় এবং এটি ফলব্যাক ফাংশন ব্যবহার করে তবে ওয়াকারটির কোনও প্রভাব নেই। উভয় ক্ষেত্রেই এটি কাজ করা আমার দরকার।


1
কাস্টম মেনু ওয়াকার একটি শ্রেণি যা প্রসারিত Walker_Nav_Menuএবং কোডেক্সে একটি উদাহরণ রয়েছে । "আমি কিভাবে ওয়াকার তৈরি করতে জানি না" এর অর্থ কী?
সাইবমেটা

বিটিডব্লিউ, +1 কারণ ধারণাটি আসলে বেশ দুর্দান্ত। কীভাবে আপনি এতে হোঁচট খেয়েছেন? আপনার কি সোর্স পোস্ট বা কিছু আছে? যদি তা হয় তবে আমি তা পড়ে খুশি হব। আগাম ধন্যবাদ.
কায়সার

@ কেজার কেবল একটি বাজে ডিজাইনের ধারণা :) কোনও উত্স পোস্ট নেই, কেন আমি জিজ্ঞাসা করছি।
স্নোবল

@cybmeta আমি ওয়াকার তৈরি করতে জানি এবং পাশাপাশি কোডেক্সে একটি উদাহরণ রয়েছে তবে এই নির্দিষ্ট সমস্যার কোনও উদাহরণ নেই। সুতরাং আমি কীভাবে একটি কাস্টম ওয়াকার তৈরি করতে পারি যা আমাকে একটি সমাধান দেয়
স্নোবল

আপনার ইউএক্স.এসই ছেলেদের এই ধারণাটি সম্পর্কে জিজ্ঞাসা করা উচিত এবং ব্যবহারকারীর সাথে সমস্যা আছে কিনা তা যাচাই করা উচিত। ইউএক্স হ'ল একটি দারুণ একটি সাইট যা ব্যবহারযোগ্যতা / অভিজ্ঞতা এবং নিয়মিত সুচিন্তিত উত্তর এবং সমস্যাগুলির জন্য যথেষ্ট ভাল বাস্তবতা পরীক্ষা করে তোলে। আপনি পাশাপাশি ফিরে আসতে পারেন এবং আমরা সবাই একসাথে সেই ধারণাটি পরিমার্জন করি। (এটি সত্যিই দুর্দান্ত হবে!)।
কায়সার

উত্তর:


9

একটি কাস্টম ওয়াকার ব্যবহার করে, start_el()পদ্ধতিটিতে প্যারামের অ্যাক্সেস রয়েছে $depth: যখন 0এগারটি হয় তখন শীর্ষস্থানীয় হয় এবং আমরা অভ্যন্তরীণ কাউন্টার বজায় রাখতে এই তথ্যটি ব্যবহার করতে পারি।

যখন কাউন্টারটি একটি সীমাতে পৌঁছে যায় তখন আমরা DOMDocumentসম্পূর্ণ HTML আউটপুট থেকে কেবলমাত্র সর্বশেষ উপাদানটি যুক্ত করতে ব্যবহার করতে পারি, এটি একটি সাবমেনুতে মুড়ে এবং এটি আবার HTML এ যুক্ত করতে পারি add


সম্পাদন করা

যখন উপাদানগুলির সংখ্যা হ'ল আমাদের প্রয়োজনীয় 1 + সংখ্যা, যেমন আমাদের প্রয়োজনীয় 5 টি উপাদান দৃশ্যমান এবং মেনুতে 6 থাকে, এটি মেনুটিকে বিভক্ত করার কোনও মানে হয় না, কারণ উপাদানগুলি যে কোনও উপায়ে 6 হবে। কোডটি সম্বোধন করার জন্য সম্পাদনা করা হয়েছিল।


কোডটি এখানে:

class SplitMenuWalker extends Walker_Nav_Menu {

  private $split_at;
  private $button;
  private $count = 0;
  private $wrappedOutput;
  private $replaceTarget;
  private $wrapped = false;
  private $toSplit = false;

  public function __construct($split_at = 5, $button = '<a href="#">&hellip;</a>') {
      $this->split_at = $split_at;
      $this->button = $button;
  }

  public function walk($elements, $max_depth) {
      $args = array_slice(func_get_args(), 2);
      $output = parent::walk($elements, $max_depth, reset($args));
      return $this->toSplit ? $output.'</ul></li>' : $output;
  }

  public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0 ) {
      $this->count += $depth === 0 ? 1 : 0;
      parent::start_el($output, $item, $depth, $args, $id);
      if (($this->count === $this->split_at) && ! $this->wrapped) {
          // split at number has been reached generate and store wrapped output
          $this->wrapped = true;
          $this->replaceTarget = $output;
          $this->wrappedOutput = $this->wrappedOutput($output);
      } elseif(($this->count === $this->split_at + 1) && ! $this->toSplit) {
          // split at number has been exceeded, replace regular with wrapped output
          $this->toSplit = true;
          $output = str_replace($this->replaceTarget, $this->wrappedOutput, $output);
      }
   }

   private function wrappedOutput($output) {
       $dom = new DOMDocument;
       $dom->loadHTML($output.'</li>');
       $lis = $dom->getElementsByTagName('li');
       $last = trim(substr($dom->saveHTML($lis->item($lis->length-1)), 0, -5));
       // remove last li
       $wrappedOutput = substr(trim($output), 0, -1 * strlen($last));
       $classes = array(
         'menu-item',
         'menu-item-type-custom',
         'menu-item-object-custom',
         'menu-item-has-children',
         'menu-item-split-wrapper'
       );
       // add wrap li element
       $wrappedOutput .= '<li class="'.implode(' ', $classes).'">';
       // add the "more" link
       $wrappedOutput .= $this->button;
       // add the last item wrapped in a submenu and return
       return $wrappedOutput . '<ul class="sub-menu">'. $last;
   }
}

ব্যবহার খুব সহজ:

// by default make visible 5 elements
wp_nav_menu(array('menu' => 'my_menu', 'walker' => new SplitMenuWalker()));

// let's make visible 2 elements
wp_nav_menu(array('menu' => 'another_menu', 'walker' => new SplitMenuWalker(2)));

// customize the link to click/over to see wrapped items
wp_nav_menu(array(
  'menu' => 'another_menu',
  'walker' => new SplitMenuWalker(5, '<a href="#">more...</a>')
));

দুর্দান্ত কাজ! অসাধারণ কাজ জিউসেপ্পে। এটি সম্পর্কে দুর্দান্ত জিনিসটি হ'ল এটি যদি প্রথম 5 মেনু উপাদানের সাবমেনু থাকে তবে তা কাজ করে। এবং এটির প্রয়োজন নেই যদি এটি কেবল একটি মেনু পয়েন্টটি একটি সাবমেনুতে আবৃত করে না। কেবল একটি ছোট্ট বিষয়: ডিফল্টরূপে এটি 6 টি উপাদান দেখায় $split_at = 5তবে $countসূচক 0 থেকে শুরু হয়
স্নোবল

ধন্যবাদ @ স্নোবল আমি সেই ছোটখাট সমস্যাটি স্থির করেছি, এখন মেনুটি $split_atডিফল্টরূপে 5 টি আর্গুমেন্ট হিসাবে পাস করা সঠিক সংখ্যা দেখায় ।
গাজাজ্যাপ

10

এমনকি সিএসএস দিয়ে এটি সম্ভব করার একটি উপায়ও রয়েছে is এর কিছু সীমাবদ্ধতা রয়েছে তবে আমি এখনও ভেবেছিলাম এটি একটি আকর্ষণীয় পদ্ধতির হতে পারে:

সীমাবদ্ধতা

  • ড্রপডাউনটির প্রস্থকে আপনার হার্ডকোড করতে হবে
  • ব্রাউজার সমর্থন। আপনার মূলত CSS3 নির্বাচক প্রয়োজন । তবে IE8 পর্যন্ত সমস্ত কিছু কাজ করা উচিত, যদিও আমি এটি পরীক্ষা করে দেখিনি।
  • এটি ধারণার চেয়ে বেশি প্রমাণ- সাব-আইটেম না থাকলে কেবল কাজ করার মতো বেশ কয়েকটি ত্রুটি রয়েছে।

অভিগমন

যদিও আমি সত্যই "কোয়ান্টিটি কোয়েরিজ" ব্যবহার করছি না সৃজনশীল ব্যবহার :nth-childএবং ~আমি সিএসএসের সাম্প্রতিক কোয়ান্টিটি কোয়েরিতে পড়েছি যা আমাকে এই সমাধানের দিকে নিয়ে গিয়েছিল।

পদ্ধতির মূলত এটি:

  1. ৪ র্থ পরে সমস্ত আইটেম লুকান
  2. ছদ্ম-উপাদান ...ব্যবহার করে বিন্দু যুক্ত করুন Addbefore
  3. বিন্দুগুলি ঘোরাতে গিয়ে (বা কোনও লুকানো উপাদান রয়েছে) অতিরিক্ত আইটেম ওরফে সাবমেনু দেখায়।

ডিফল্ট ওয়ার্ডপ্রেস মেনু মার্কআপের জন্য এখানে সিএসএস কোড দেওয়া আছে। আমি ইনলাইন মন্তব্য করেছি।

/* Optional: Center the navigation */
.main-navigation {
    text-align: center;
}

.menu-main-menu-container {
    display: inline-block;
}

/* Float menu items */
.nav-menu li {
    float:left;
    list-style-type: none;
}

/* Pull the 5th menu item to the left a bit so that there isn't too
   much space between item 4 and ... */
.nav-menu li:nth-child(4) {
    margin-right: -60px;
}

/* Create a pseudo element for ... and force line break afterwards
   (Hint: Use a symbol font to improve styling) */
.nav-menu li:nth-child(5):before {
    content: "...\A";
    white-space: pre;
}

/* Give the first 4 items some padding and push them in front of the submenu */
.nav-menu li:nth-child(-n+4) {
    padding-right: 15px;
    position: relative;
    z-index: 1;
}

/* Float dropdown-items to the right. Hardcode width of dropdown. */
.nav-menu li:nth-child(n+5) {
    float:right;
    clear: right;
    width: 150px;
}

/* Float Links in dropdown to the right and hide by default */
.nav-menu li:nth-child(n+5) a{
    display: none;      
    float: right;
    clear: right;
}   

/* When hovering the menu, show all menu items from the 5th on */
.nav-menu:hover li:nth-child(n+5) a,
.nav-menu:hover li:nth-child(n+5) ~ li a{
    display: inherit;
}

/* When hovering one of the first 4 items, hide all items after it 
   so we do not activate the dropdown on the first 4 items */
.nav-menu li:nth-child(-n+4):hover ~ li:nth-child(n+5) a{
    display: none;
}

এটি কার্যকরভাবে দেখানোর জন্য আমি একটি জ্যাসফিল্ডও তৈরি করেছি: http://jsfiddle.net/jg6pLfd1/

এটি কীভাবে কাজ করে আপনার যদি আরও কিছু প্রশ্ন থাকে তবে দয়া করে একটি মন্তব্য দিন, আমি কোডটি আরও পরিষ্কার করে খুশি হতে পারব।


আপনার পদ্ধতির জন্য ধন্যবাদ। আমি ইতিমধ্যে সিএসএস দিয়ে এটি করার মধ্যে ভেবেছিলাম তবে আমি মনে করি এটি পরিষ্কার করার জন্য পিএইচপি-র মধ্যে সরাসরি এটি করা যায়। অতিরিক্ত এই সমাধানটি 5 তম মেনু পয়েন্টটিকে একটি সাবমেনুতে রাখে, এমনকি সেখানে কেবল পাঁচটি মেনু আইটেম থাকলে প্রয়োজন নেই।
স্নোবল

কেবলমাত্র 5+ আইটেমের জন্য এটি সক্ষম করা সম্ভবত স্থির করা যেতে পারে। যাইহোক আমি সচেতন যে এটি নিখুঁত নয় এবং একটি পিএইচপি পদ্ধতিটি আরও পরিষ্কার হতে পারে। তবে আমি এখনও এটি সম্পূর্ণরূপে জন্য অন্তর্ভুক্ত যথেষ্ট আকর্ষণীয় মনে হয়েছে। অন্য একটি বিকল্প সবসময় দুর্দান্ত। :)
ক্র্যাফটনার

2
অবশ্যই. BTW। আপনি যদি এটিতে আরও একটি সাবমেনু যুক্ত করেন তবে এটিও ভেঙে যায়
স্নোবল 10

1
অবশ্যই। এটি এখন পর্যন্ত ধারণার প্রমাণ হিসাবে আরও বেশি। একটি সতর্কতা যুক্ত করা হয়েছে।
ক্র্যাফটনার

8

আপনি wp_nav_menu_itemsফিল্টার ব্যবহার করতে পারেন । এটি মেনু আউটপুট এবং আর্গুমেন্ট গ্রহণ করে যা মেনু বৈশিষ্ট্যগুলি মেনু স্লাগ, ধারক ইত্যাদি রাখে hold

add_filter('wp_nav_menu_items', 'wpse_180221_nav_menu_items', 20, 2);

function wpse_180221_nav_menu_items($items, $args) {
    if ($args->menu != 'my-menu-slug') {
        return $items;
    }

    // extract all <li></li> elements from menu output
    preg_match_all('/<li[^>]*>.*?<\/li>/iU', $items, $matches);

    // if menu has less the 5 items, just do nothing
    if (! isset($matches[0][5])) {
        return $items;
    }

    // add <ul> after 5th item (can be any number - can use e.g. site-wide variable)
    $matches[0][5] = '<li class="menu-item menu-item-type-custom">&hellip;<ul>'
          . $matches[0][5];

    // $matches contain multidimensional array
    // first (and only) item is found matches array
    return implode('', $matches[0]) . '</ul></li>';
}

1
আমি বেশ কয়েকটি ছোটখাটো সমস্যা সম্পাদনা করেছি, তবে সমস্ত মেনু আইটেমগুলিতে সাব আইটেম না থাকলে কেবল এটিই কাজ করে। কারণ রেজেক্স হায়ারার্কি চিনতে পারে না। এটি পরীক্ষা করুন: প্রথম 4 টি মেনু আইটেমে যদি কোনও শিশু আইটেম থাকে তবে মেনুটি বেশ নষ্ট হয়ে যায়।
gmazzap

1
সেটা সত্য. সেক্ষেত্রে DOMDocumentব্যবহার করা যেতে পারে। তবে, এই প্রশ্নে কোনও উপ-মেনু নেই, সুতরাং এই নির্দিষ্ট ক্ষেত্রে উত্তরটি সঠিক correct ডোমডোকামেন্টটি "সার্বজনীন" সমাধান হবে তবে আমার এখনই সময় নেই। আপনি তদন্ত করতে পারেন;) এলআই আইটেমগুলির মধ্যে লুপিং, যদি কোনও আল-শিশু থাকে তবে এটি সমাধান হবে তবে লিখিত সংস্করণ দরকার :)
এমজাকিক

1
(ক) ওপিতে সাবমেনু আছে কিনা তা আপনি জানেন না। মাউস শেষ হয়ে গেলে সাবমেনাস উপস্থিত হয়, সুতরাং ... (খ) হ্যাঁ, ডমডকুমেন্ট কাজ করতে পারে তবে সেই ক্ষেত্রে আপনাকে অভ্যন্তরের জন্য চেক করতে পুনরাবৃত্তভাবে আইটেমগুলি লুপ করতে হবে ul। ওয়ার্ডপ্রেস ইতিমধ্যে মেনু ওয়াকারে মেনু আইটেমগুলি লুপ করে। এটি ইতিমধ্যে সে প্রতি ধীর গতিতে চলছে , যোগ করা এবং অতিরিক্ত লুপ আমার মনে হয় সঠিক সমাধান নয়, গণনার ক্ষেত্রে, একটি কাস্টম ওয়াকার অনেক বেশি ক্লিনার এবং দক্ষ সমাধান হতে পারে।
গাজাজ্যাপ

ধন্যবাদ ছেলেরা, তবে @ গাজাজাপ সত্য, অন্যান্য মেনু পয়েন্টগুলিতে (প্রথম 4 বা অন্যান্য দুটি ক্ষেত্রেই) অন্য সাবমেনু রয়েছে এমন সম্ভাবনা রয়েছে। সুতরাং এই আত্মা কাজ করবে না।
স্নোবল

আপনি দুটি মেনু রাখতে পারেন, একটি প্রধান এবং "লুকানো" একটি। তিনটি বিন্দু "..." সহ স্টাইলযুক্ত বোতাম যুক্ত করুন এবং ক্লিক করুন বা হোভার শোতে দ্বিতীয় মেনুতে ক্লিক করুন। খুব সহজ হতে হবে।
mjakic

5

একটি কার্যকরী ফাংশন পেয়েছেন, তবে এটি সর্বোত্তম সমাধান কিনা তা নিশ্চিত নন।

আমি একটি কাস্টম ওয়াকার ব্যবহার করেছি:

class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
function start_el(  &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    global $wp_query;
    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;

    $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
    $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

    $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
    $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

    /**
     * This counts the $menu_items and wraps if there are more then 5 items the
     * remaining items into an extra <ul>
     */
    global $menu_items;
    $menu_items = substr_count($output,'<li');
    if ($menu_items == 4) {
      $output .= '<li class="tooltip"><span>...</span><ul class="tooltip-menu">';
    }

    $output .= $indent . '<li' . $id . $class_names .'>';

    $atts = array();
    $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
    $atts['target'] = ! empty( $item->target )     ? $item->target     : '';
    $atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
    $atts['href']   = ! empty( $item->url )        ? $item->url        : '';

    $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

    $attributes = '';
    foreach ( $atts as $attr => $value ) {
      if ( ! empty( $value ) ) {
        $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
        $attributes .= ' ' . $attr . '="' . $value . '"';
      }
    }

    $item_output = $args->before;
    $item_output .= '<a'. $attributes .'>';
    $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
    $item_output .= '</a>';
    $item_output .= $args->after;

    $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );

  }
}

আসল মেনুটি দেখায় এমন ফাংশনটি হ'ল:

        <?php
        wp_nav_menu( array( 'container' => false, 'theme_location' => 'navigation', 'fallback_cb' => 'custom_menu', 'walker' =>new Custom_Walker_Nav_Menu ) );
        global $menu_items;
        // This adds the closing </li> and </ul> if there are more then 4 items in the menu
        if ($menu_items > 4) {
            echo "</li></ul>";
        }
        ?>

আমি গ্লোবাল ভেরিয়েবল $ মেনু_সাইটগুলি ঘোষণা করে এবং এটি ক্লোজিং <li>এবং- ট্যাগগুলি দেখানোর জন্য ব্যবহার করেছি <ul>। কাস্টম ওয়াকারের অভ্যন্তরে এটি করা সম্ভবত সম্ভব, তবে কোথায় এবং কীভাবে খুঁজে পেলাম না।

দুটি সমস্যা: ১. যদি মেনুতে মাত্র ৫ টি আইটেম থাকে তবে এটি সর্বশেষ আইটেমটি গুটিয়ে রাখে এবং এটির কোনও প্রয়োজন নেই al

  1. এটি কেবল তখনই কাজ করে যদি ব্যবহারকারী প্রকৃতপক্ষে থিম_লোকেশনে একটি মেনু বরাদ্দ করে থাকে, wp_nav_menu ফ্যালব্যাক ফাংশনটি দেখায় যদি ওয়াকারটি গুলি চালায় না

আপনি কি চেষ্টা করেছেন যদি প্রথম 4 টি আইটেমের কিছু সাবমিনাস থাকে তবে কী ঘটবে? টিপ: substr_count($output,'<li')হতে হবে == 4ভুল জায়গায় ...
gmazzap
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.