167 lines
4.4 KiB
Elixir
167 lines
4.4 KiB
Elixir
defmodule Content.Menu do
|
|
@moduledoc """
|
|
Module for retrieving, manipulating, and processing navigation menus.
|
|
"""
|
|
alias Content.{Option, Post, Repo, Term, TermRelationship}
|
|
import Ecto.Query
|
|
|
|
def put_menu_option(option_name, location_name, menu_id) do
|
|
option =
|
|
Option
|
|
|> where(option_name: ^option_name)
|
|
|> Repo.one()
|
|
|> Kernel.||(%Option{option_name: option_name, option_value: "a:0:{}"})
|
|
|
|
value =
|
|
option
|
|
|> Option.parse_option_value
|
|
|
|
nav_menu_locations =
|
|
value
|
|
|> Enum.find(fn {key, _value} -> key == "nav_menu_locations" end)
|
|
|> Kernel.||({"nav_menu_locations", []})
|
|
|> elem(1)
|
|
|
|
new_nav_menu_locations =
|
|
nav_menu_locations
|
|
|> Enum.filter(fn {key, _value} -> key != location_name end)
|
|
|> Kernel.++([{location_name, menu_id}])
|
|
|
|
new_value =
|
|
value
|
|
|> Enum.filter(fn {key, _value} -> key != "nav_menu_locations" end)
|
|
|> Kernel.++([{"nav_menu_locations", new_nav_menu_locations}])
|
|
|
|
option
|
|
|> Option.put_new_value(new_value)
|
|
end
|
|
|
|
def get_menu_from_option_and_location(option_name, location_name) do
|
|
option =
|
|
Option
|
|
|> where(option_name: ^option_name)
|
|
|> Repo.one()
|
|
|> Kernel.||(%Option{option_name: option_name, option_value: "a:0:{}"})
|
|
|
|
value =
|
|
option
|
|
|> Option.parse_option_value
|
|
|
|
menu_pair =
|
|
value
|
|
|> Enum.find(fn {key, _value} -> key == "nav_menu_locations" end)
|
|
|> Kernel.||({"nav_menu_locations", []})
|
|
|> elem(1)
|
|
|> Enum.find(fn {key, _value} -> key == location_name end)
|
|
|
|
case menu_pair do
|
|
{^location_name, menu_id} ->
|
|
menu_id |> get_menu_from_id()
|
|
nil ->
|
|
nil
|
|
end
|
|
end
|
|
|
|
def get_menu_from_id(menu_id) do
|
|
menu_id
|
|
|> nav_menu_items_for_id()
|
|
|> arrange_menu_item_posts()
|
|
end
|
|
|
|
def nav_menu_items_for_id(menu_id) do
|
|
Post
|
|
|> join(
|
|
:inner,
|
|
[p],
|
|
tr in TermRelationship,
|
|
on: p."ID" == tr.object_id
|
|
)
|
|
|> order_by(:menu_order)
|
|
|> preload(:metas)
|
|
|> where([p, tr], tr.term_taxonomy_id == ^menu_id)
|
|
|> Repo.all()
|
|
end
|
|
|
|
defp arrange_menu_item_posts(nav_posts, parent_id \\ "0", nav_to_post_map \\ nil) do
|
|
nav_to_post_map = nav_to_post_map || make_nav_to_post_map(nav_posts)
|
|
|
|
nav_posts
|
|
|> Enum.filter(fn post ->
|
|
meta_map = post |> Post.metas_map
|
|
meta_map["_menu_item_menu_item_parent"] == parent_id
|
|
end)
|
|
|> Enum.map(fn post ->
|
|
meta_map = post |> Post.metas_map
|
|
related_item =
|
|
if meta_map["_menu_item_object"] == "category" do
|
|
item = nav_to_post_map["category/#{meta_map["_menu_item_object_id"]}"] || %Term{}
|
|
|
|
%{
|
|
title: item.name,
|
|
slug: item.slug,
|
|
resource: "category",
|
|
}
|
|
else
|
|
item = nav_to_post_map["post/#{meta_map["_menu_item_object_id"]}"] || %Post{}
|
|
|
|
%{
|
|
title: item.post_title,
|
|
slug: item.post_name,
|
|
resource: "posts",
|
|
}
|
|
end
|
|
|
|
%{
|
|
post_id: post."ID",
|
|
type: meta_map["_menu_item_object"],
|
|
target_id: meta_map["_menu_item_object_id"],
|
|
parent_id: meta_map["_menu_item_menu_item_parent"],
|
|
url: meta_map["_menu_item_url"],
|
|
related_item: related_item,
|
|
children: arrange_menu_item_posts(nav_posts, Integer.to_string(post."ID"), nav_to_post_map),
|
|
}
|
|
end)
|
|
end
|
|
|
|
defp make_nav_to_post_map(nav_posts) do
|
|
nav_post_meta_map = nav_posts |> Post.metas_map()
|
|
|
|
linked_post_ids =
|
|
nav_post_meta_map
|
|
|> Enum.filter(fn {_key, value} ->
|
|
value["_menu_item_object"] != "category"
|
|
end)
|
|
|> Enum.map(fn {_key, value} ->
|
|
value["_menu_item_object_id"]
|
|
end)
|
|
|
|
nav_to_post_map =
|
|
Post
|
|
|> where([p], p."ID" in ^linked_post_ids)
|
|
|> Repo.all()
|
|
|> Enum.map(fn post ->
|
|
{"post/#{post."ID"}", post}
|
|
end)
|
|
|> Map.new
|
|
|
|
linked_category_ids =
|
|
nav_post_meta_map
|
|
|> Enum.filter(fn {_key, value} ->
|
|
value["_menu_item_object"] == "category"
|
|
end)
|
|
|> Enum.map(fn {_key, value} ->
|
|
value["_menu_item_object_id"]
|
|
end)
|
|
|
|
nav_to_category_map =
|
|
Term
|
|
|> where([t], t.term_id in ^linked_category_ids)
|
|
|> Repo.all()
|
|
|> Enum.map(fn category ->
|
|
{"category/#{category.term_id}", category}
|
|
end)
|
|
|> Map.new
|
|
|
|
nav_to_post_map |> Map.merge(nav_to_category_map)
|
|
end
|
|
end
|