Recreate an object from an array of objects in Javascript

I could use some help with the following:

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

Read More

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

Related posts

2 comments

  1. 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);
  2. 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 are closed.