How to create dynamic meta tag in phoenix

Hello,

I want to create dynamic meta tag in each controller and view, for example :

in show action function

<meta name="keywords" content="...." />
<meta name="description" content="...." />
<meta property="og:image" content="...." />
<meta property="og:image:width" content="1074" />
<meta property="og:image:height" content="506" />
<meta property="og:title" content="...." />

in index function

<meta name="keywords" content="...." />
<meta name="description" content="...." />
<meta property="og:image" content="...." />

in these functions, meta tags are different, it should be noted I need to add custom code in head like this:

.... In summary, I need to have full head access to import something which I will be able to edit in controller , because I read these property with database

What do you have a suggestion for me? I don’t need fix meta !!

I read these:

https://www.brainarama.com/thought/dbfe9020-b431-11e7-ae34-3f710d564c96/Elixir-Phoenix-framework-pass-data-from-controller-action-to-layout-view-app-html-eex

Sure, just provide a list of keys/values for each meta tag and then map those to Phoenix.HTML.Tag.tag/2. You’d put this in your layout view or a shared view:

  def meta_tags(attrs_list) do
    Enum.map(attrs_list, &meta_tag/1)
  end

  def meta_tag(attrs) do
    tag(:meta, Enum.into(attrs, []))
  end

Assuming your data fits into this shape:

  attrs_list = [%{name: "keywords", content: "........"},
                %{name: "description", content: "........."},
                %{property: "og:image", content: "......"}]

Then you can use it like this in your layout:

<%= if @meta_attrs, do: meta_tags(@meta_attrs) %>

Of course, you’ll need to provide meta_attrs in the assigns for each controller. You could also do it with a plug if that gets tedious.

Hello, Thank you very much, I have a problem when I decade to start Phoenix server

== Compilation error in file lib/trangell_html_site_web/views/layout_view.ex ==
** (CompileError) lib/trangell_html_site_web/templates/layout/app.html.eex:9: undefined function meta_tags/1

Step 1

in templates/layout/app.html.eex path I write

<%= if @meta_attrs, do: meta_tags(@meta_attrs) %>

Step 2

in controllers/page_controller.ex path :

  def index(conn, _params) do
    attrs_list = [%{name: "keywords", content: "........"},
                %{name: "description", content: "........."},
                %{property: "og:image", content: "......"}]
    render(conn, "index.html", meta_attrs: attrs_list)
  end

Step 3

in views/page_view.ex path :

def meta_tags(attrs_list) do
    Enum.map(attrs_list, &meta_tag/1)
  end

  def meta_tag(attrs) do
    tag(:meta, Enum.into(attrs, []))
  end

where did I make a mistake?

Try defining them in views/layout_view.ex instead of views/page_view.ex

it works for me , but I think it has some problems

see please :

<meta content="test1" name="keywords"><meta content="test2" name="description"><meta content="......" property="og:image"> 

at frist it loads content and after loads name , I saw https://hexdocs.pm/phoenix_html/Phoenix.HTML.Tag.html#tag/2 , but it doesn’t have any example :frowning:

can some body help me?

I’m not sure I understand what the problem is. If you’re concerned about the order of attributes (content before name), then I’m pretty sure it doesn’t matter.

if you want exact order, instead of map you can use list

attrs_list = [
[name: "keywords", content: "........"],
[name: "description", content: "........."], 
[property: "og:image", content: "......"]
]

Not in my example, though. Phoenix.HTML alphabetizes the attrs.

Here -> http://cloudless.studio/articles/27-implementing-page-specific-titles-in-phoenix you can find a very nice and simple example for implementing dynamic page specific titles.

Awesome stuff, I just had to change the heex part to the Phoenix 1.6.6:

  <head>
    ...
    <!-- METAs -->
    <%= if assigns[:meta_tags], do: meta_tags(@meta_tags) %>