Juozas
Juozas

Reputation: 77

Create a hierarchical list of array elements

I have a an array of products. Each product contains its category and subcategories listed in a hierarchical order:

Array
(
    [product_id_1] => Array
        (
            [0] => Men
            [1] => Sunglasses
            [2] => Luxury
            [3] => Ray-ban
        )

    [product_id_2] => Array
        (
            [0] => Women
            [1] => Lenses
            [2] => Casual
            [3] => Gucci
        )
    [product_id_3] => Array
        (
            [0] => Men
            [1] => Sunglasses
            [2] => Casual
            [3] => Prada
        )
[...]
)

I want to create an unordered hierarchical HTML menu like so:

-Men
--Sunglasses
---Luxury
----Ray-ban
---Casual
----Prada
-Women
--Lenses
---Casual
----Gucci

The function should strip out repetitive categories and subcategories. This script returns the array of products that I've posted at the top:

<?php
    function displayNestedMenu( $posts, $taxonomies ) {
        foreach ( $posts as $post ) {
            foreach ( $taxonomies as $key => $taxonomy ) {
                $push = wp_get_object_terms( $post->ID, $taxonomy );
                if ( !empty( $push ) ) {
                        $list[$post->ID][] = $push[0]->name;
                }
            }
        }
        return $list;
    }
    print_r( displayNestedMenu( $posts, $taxonomies ) );
?>

I imagine the solution should invoke the function inside the function but after trying a couple of methods I haven't succeeded yet. Any suggestions are appreciated!

Upvotes: 1

Views: 1391

Answers (3)

JC Sama
JC Sama

Reputation: 2204

Here is a simple idea :

$array = array(
    'product_id_1' => array(
        'Men',
        'Sunglasses',
        'Luxury',
        'Ray-ban'
    ),
    'product_id_2' => array(
        'Women',
        'Lenses',
        'Casual',
        'Gucci',
    ),
    'product_id_3' => array(
        'Men',
        'Sunglasses',
        'Casual',
        'Prada'
    )
);

The idea is to recreate the keys depending on the parent category, after that we sort them using ksort():

function tree($array){
    $newArray = array();
    foreach ($array as $arr) {
        foreach ($arr as $key => $row) {

            if ($key > 0) {
                $index = array();
                for ($i = 0; $i <= $key; $i++)
                    $index[] = $arr[$i];

                $index = implode('_', $index);
            } else
                $index = $row;
            $newArray[$index] = $row;
        }
    }

    ksort($newArray);

    return $newArray;
}

Then display the HTML :

$products = tree($array);
$i = 0;
    echo '<ul style="list-style-type:none">';
    foreach ($products as $key => $row) {

        if(strcmp($row, $key) == 0 && $i != 0)
            echo '</ul><br><ul style="list-style-type:none">';

        ++$i;
        $level = count(explode('_', $key));
        $padding = 15 * (--$level);

        echo
            '<li style="padding-left:' . $padding . 'px">
                <span style="border-left:1px dashed black;border-bottom:1px dashed black;">&nbsp;' . $row . '</span>
            </li>';
    }
    echo '</ul>';

Upvotes: 1

Flygenring
Flygenring

Reputation: 3848

You could transform the array in a static way, as the structure you describe always has four parts;

$hierarchy = array();
foreach($products as $product_id => $product) {
    list($gender, $category, $type, $brand) = $product;
    $hierarchy[$gender][$category][$type][$brand][] = $product_id;
}

Upvotes: 0

Matthew Slyman
Matthew Slyman

Reputation: 356

PHP has powerful array features: string-indexed arrays can help provide solutions to problems like this one.

For the array conversion step:

$hrchy=array();
foreach($products AS $product){//$products is as per your first array, at start…
    hrchy_ins($hrchy,$product);
}
function hrchy_ins(array &$hierarchy,array $product){//$hierarchy should be passed by reference…
    if(\count($product)>0){//Condition necessary to implement base case, avoiding infinite recursion
        if(!isset($hierarchy[$product[0]])){$hierarchy[$product[0]]=array();}//Conditional execution ignores duplicates…
        if(\count($product)>1){hrchy_ins($hierarchy[$product[0]],\array_slice($product,1));}//Condition may not be strictly necessary (see condition above!)
}   }

We might now use a recursive approach for a further HTML-writing step (the recursion secret sauce = a simple recursive function including a branch-on-condition for the base-case):

function prod_list(array $hierarchy){
    if(\count($hierarchy)===0){
        return '';
    }else{
        $list='';
        $list.='<ul>';
        foreach($hierarchy AS $cat => $children){
            $list.='<li>'.$cat;
            $list.=prod_list($children);//Recursive step…
            $list.='</li>';
        }
        $list.='<ul>';
        return $list;
    }
}

Finally, after defining the function, we invoke it:

echo(prod_list($hrchy));

Disclaimer: I have not tested this code.

Upvotes: 1

Related Questions