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

1 Like

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.

5 Likes

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

1 Like

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.

1 Like

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

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

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

2 Likes

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.

2 Likes

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) %>
1 Like