How to build a Phoenix App with Themes Customer added Layouts

Hello - I’m looking into a open source project for our company and we would like to have a phoenix app for users to install/host them self and also to load custom themes and or modify themes on the go.

The Idea was, to have a folder in the app root for like layouts where the customer can download like Wordpress themes and just link it into this folder. I noticed that those files are not copied over with the release. So I was putting them into /priv/layouts/base/ and referenced it directly like this:

defmodule AppWeb.ViewHTML do
  use AppWeb, :html

  theme_name = Application.get_env(:app, :theme)
  # embed_templates "../../../layouts/#{theme_name}/view_html/*"  # works in dev but not in release
  embed_templates "../../../priv/layouts/#{theme_name}/view_html/*" # works in dev but not in release
  # embed_templates Application.app_dir(:app, "/priv/layouts/#{theme_name}/view_html/*") # does not work at all
  # embed_templates "view_html/*" # standard

this works in development, but if I use
embed_templates Application.app_dir(:app, "/priv/layouts/#{theme_name}/view_html/*") the template is not found. The path is a static path not relative one and if I do:! Application.app_dir(:app, "/priv/layouts/#{theme_name}/view_html/view.html.heex") the content is read by iex … what I am missing?

the StackTrace is:

11:35:56.191 [error] #PID<0.2358.0> running AppWeb.Endpoint (connection #PID<0.2357.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /view
** (exit) an exception was raised:
    ** (ArgumentError) no "view" html template defined for AppWeb.ViewHTML
        (phoenix_template 1.0.1) lib/phoenix/template.ex:241: Phoenix.Template.render_with_fallback/4
        (phoenix_template 1.0.1) lib/phoenix/template.ex:197: Phoenix.Template.render_within_layout/4
        (phoenix 1.7.6) lib/phoenix/controller.ex:1000: anonymous fn/5 in Phoenix.Controller.template_render/4
        (telemetry 1.2.1) /app/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
        (phoenix 1.7.6) lib/phoenix/controller.ex:987: Phoenix.Controller.render_with_layouts/4
        (phoenix 1.7.6) lib/phoenix/controller.ex:974: Phoenix.Controller.render_and_send/4
        (blogex 0.1.0) lib/app_web/controllers/view_controller.ex:1: AppWeb.BlogController.action/2
        (blogex 0.1.0) lib/app_web/controllers/view_controller.ex:1: AppWeb.BlogController.phoenix_controller_pipeline/2

I think this is a compile time/run-time issue.

I don’t have a solution off-hand but you can check out the following for more reading:


@StorageCluster do you have your themes on github? I’m doing something similar right now and curious on how you’ve implemented it.

currently only one template - but still struggling with the compile context in release environment. How have you tried to solve this?
happy to share my template :blush:

How did the use of :code.priv_dir(:my_app) at runtime mentioned by JohnnyCurran work for you?

Not an answer to your question, but I would recommend considering context-based styling. It’s practical and simple.