legendary-doc-site/apps/content/lib/menu.ex

168 lines
4.4 KiB
Elixir
Raw Normal View History

2020-07-20 22:04:04 +00:00
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