2

I could use some help with the following:

I'm trying to create a filterable wordpress nav menu using React Tree Menu.

The Tree Menu component requires the following data structure:

{
    "Home" : {
      checkbox: false,
      ID: 1,
      children: {
        "Getting Started" : {
          checkbox: false,
          ID: 47,
          slug: 'getting-started',
        },
        "Interaction Design Principles": {
          checkbox: false,
          children: {
            "Design Principle the First" : {
              selected: false,
              checkbox: false,
              ID: 67
            }
          }
        }
      }
    },
    "UPS Mobile (iOs, Android)" : {
      checkbox: false,
      children: {
        "Overview" : {
          checkbox: false,
          ID: 22
        },
        "Reference" : {
          checkbox: false,
          ID: 14
        }
      }
    },
    "mDot" : {
      checkbox: false,
      children: {
        "Elements" : {
          checkbox: false,
          ID: 19,
          children: {
            "Navigation" : {
              checkbox: false,
              ID: 90
            }
          }
        },
      }
    }
  }

I have set up parent and child pages of the above in wordpress and have also created a hierarchical wordpress menu. I am using the wordpress menu api

which returns the following data structure:

[
  {
    "ID": 46,
    "order": 1,
    "parent": 0,
    "title": "Home",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 2,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 47,
        "order": 2,
        "parent": 46,
        "title": "Getting Started",
        "url": "http://mobilestyle.ups.dev/home/getting-started/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 15,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 48,
        "order": 3,
        "parent": 46,
        "title": "Interaction Design Principles",
        "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 22,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 49,
            "order": 4,
            "parent": 48,
            "title": "Design Principle the First",
            "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/design-principle-the-first/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 24,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 50,
    "order": 5,
    "parent": 0,
    "title": "mDot",
    "url": "http://mobilestyle.ups.dev/mdot/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 8,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 51,
        "order": 6,
        "parent": 50,
        "title": "Elements",
        "url": "http://mobilestyle.ups.dev/mdot/elements/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 30,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 52,
            "order": 7,
            "parent": 51,
            "title": "Navigation",
            "url": "http://mobilestyle.ups.dev/mdot/elements/navigation/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 32,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 54,
    "order": 8,
    "parent": 0,
    "title": "UPS Mobile (iOS, Android)",
    "url": "http://mobilestyle.ups.dev/ups-mobile/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 13,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 55,
        "order": 9,
        "parent": 54,
        "title": "Overview",
        "url": "http://mobilestyle.ups.dev/ups-mobile/overview/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 26,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 56,
        "order": 10,
        "parent": 54,
        "title": "Reference",
        "url": "http://mobilestyle.ups.dev/ups-mobile/reference/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 28,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      }
    ]
  }
]

Can someone please help me turn what I receive from the wordpress menu api into what the Tree Menu component expects?

Thanks in advance for any help. -Ian

2 Answers 2

3

I'd use a recursive function to build the object you want. Something like the following:

function buildMenu(source, result) {
  //build a return value if one wasn't passed in
  result = result || {};
  
  if (source && source.length) {
    
    var item = source.shift(); //take first item from the array
    result[item.title] = { ID : item.ID }; //make a new property in the result

    //if there are children, build them recursively
    if (item.children && item.children.length) {
      result[item.title].children = buildMenu(item.children);
    }
    
    //build additional items recursively, based on the remaining items in the array
    return buildMenu(source, result);
    
  } else {
    //none left, done
    return result;
  }
}

Call that function on your source array and it should work. There's a running example below if you want to try it out.

function buildMenu(source, result) {
  result = result || {};
  
  if (source && source.length) {
    
    var item = source.shift();
    result[item.title] = { ID : item.ID };
    
    if (item.children && item.children.length) {
      result[item.title].children = buildMenu(item.children);
    }
    
    return buildMenu(source, result);
    
  } else {
    return result;  
  }
}

var source = [
  {
    "ID": 46,
    "order": 1,
    "parent": 0,
    "title": "Home",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 2,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 47,
        "order": 2,
        "parent": 46,
        "title": "Getting Started",
        "url": "http://mobilestyle.ups.dev/home/getting-started/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 15,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 48,
        "order": 3,
        "parent": 46,
        "title": "Interaction Design Principles",
        "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 22,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 49,
            "order": 4,
            "parent": 48,
            "title": "Design Principle the First",
            "url": "http://mobilestyle.ups.dev/home/interaction-design-principles/design-principle-the-first/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 24,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 50,
    "order": 5,
    "parent": 0,
    "title": "mDot",
    "url": "http://mobilestyle.ups.dev/mdot/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 8,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 51,
        "order": 6,
        "parent": 50,
        "title": "Elements",
        "url": "http://mobilestyle.ups.dev/mdot/elements/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 30,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": [
          {
            "ID": 52,
            "order": 7,
            "parent": 51,
            "title": "Navigation",
            "url": "http://mobilestyle.ups.dev/mdot/elements/navigation/",
            "attr": "",
            "target": "",
            "classes": "",
            "xfn": "",
            "description": "",
            "object_id": 32,
            "object": "page",
            "type": "post_type",
            "type_label": "Page",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "ID": 54,
    "order": 8,
    "parent": 0,
    "title": "UPS Mobile (iOS, Android)",
    "url": "http://mobilestyle.ups.dev/ups-mobile/",
    "attr": "",
    "target": "",
    "classes": "",
    "xfn": "",
    "description": "",
    "object_id": 13,
    "object": "page",
    "type": "post_type",
    "type_label": "Page",
    "children": [
      {
        "ID": 55,
        "order": 9,
        "parent": 54,
        "title": "Overview",
        "url": "http://mobilestyle.ups.dev/ups-mobile/overview/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 26,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      },
      {
        "ID": 56,
        "order": 10,
        "parent": 54,
        "title": "Reference",
        "url": "http://mobilestyle.ups.dev/ups-mobile/reference/",
        "attr": "",
        "target": "",
        "classes": "",
        "xfn": "",
        "description": "",
        "object_id": 28,
        "object": "page",
        "type": "post_type",
        "type_label": "Page",
        "children": []
      }
    ]
  }
];

var dest = buildMenu(source);
console.log(dest);

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you Dave! Just plugged that into my application and it works beautifully : )
0

Here's a pretty simple recursive version:

const buildMenu = (xs) =>
  xs .reduce ((a, {title, ID, children}) => ((a [title] = {
    checkbox: false, ID, ... (children .length ? {children: buildMenu (children)} : {})
  }), a), {})

const source = [{ID: 46, order: 1, parent: 0, title: "Home", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 2, object: "page", type: "post_type", type_label: "Page", children: [{ID: 47, order: 2, parent: 46, title: "Getting Started", url: "http://mobilestyle.ups.dev/home/getting-started/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 15, object: "page", type: "post_type", type_label: "Page", children: []}, {ID: 48, order: 3, parent: 46, title: "Interaction Design Principles", url: "http://mobilestyle.ups.dev/home/interaction-design-principles/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 22, object: "page", type: "post_type", type_label: "Page", children: [{ID: 49, order: 4, parent: 48, title: "Design Principle the First", url: "http://mobilestyle.ups.dev/home/interaction-design-principles/design-principle-the-first/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 24, object: "page", type: "post_type", type_label: "Page", children: []}]}]}, {ID: 50, order: 5, parent: 0, title: "mDot", url: "http://mobilestyle.ups.dev/mdot/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 8, object: "page", type: "post_type", type_label: "Page", children: [{ID: 51, order: 6, parent: 50, title: "Elements", url: "http://mobilestyle.ups.dev/mdot/elements/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 30, object: "page", type: "post_type", type_label: "Page", children: [{ID: 52, order: 7, parent: 51, title: "Navigation", url: "http://mobilestyle.ups.dev/mdot/elements/navigation/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 32, object: "page", type: "post_type", type_label: "Page", children: []}]}]}, {ID: 54, order: 8, parent: 0, title: "UPS Mobile (iOS,  Android)", url: "http://mobilestyle.ups.dev/ups-mobile/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 13, object: "page", type: "post_type", type_label: "Page", children: [{ID: 55, order: 9, parent: 54, title: "Overview", url: "http://mobilestyle.ups.dev/ups-mobile/overview/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 26, object: "page", type: "post_type", type_label: "Page", children: []}, {ID: 56, order: 10, parent: 54, title: "Reference", url: "http://mobilestyle.ups.dev/ups-mobile/reference/", attr: "", target: "", classes: "", xfn: "", description: "", object_id: 28, object: "page", type: "post_type", type_label: "Page", children: []}]}]

console .log (buildMenu (source))
.as-console-wrapper {max-height: 100% !important; top: 0}

We fold our array into an object, adding the property of the current title with a simple value consisting of the ID, an arbitrarily false checkbox attribute (is this actually derivable from the input?) and -- if our node has children -- the result of recurring on those children.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.