Create a reusable module
Create apps_user/zotonic_mod_garden with the following files. This example adds a discoverable module without starting an extra process.
Create apps_user/zotonic_mod_garden with the following files. This example adds a discoverable module without starting an extra process.
rebar.config:
{erl_opts, [debug_info]}.
src/zotonic_mod_garden.app.src:
{application, zotonic_mod_garden, [
{description, "Community garden features"},
{vsn, "0.1.0"},
{registered, []},
{applications, [kernel, stdlib, zotonic_core]},
{env, []},
{modules, []}
]}.
src/mod_garden.erl:
-module(mod_garden).
-mod_title("Garden").
-mod_description("Community garden features.").
-mod_prio(500).
Run make from the Zotonic workspace root. On the running development node, use bin/zotonic update to refresh discovery. Open module management in the site's admin and activate Garden.
Check that the module is active. Add the model from Expose data through a model for a first data lookup, and put templates in priv/templates. Keep installation hooks and observers in the main module; move domain logic into models or support modules.
Erlang applications, Zotonic modules, and sites
These terms describe different parts of the system.
An Erlang application is a package described by a .app file, normally generated from src/<name>.app.src. It can provide modules and an OTP application callback.
A Zotonic module is functionality that can be activated for a site. Its main Erlang module declares attributes such as -mod_title and -mod_depends.
A site is a named website with its own configuration and runtime context. Several sites share the same Erlang VM and loaded code, while module activation and site data are site-specific.
Upgrade a module's data schema
Version schema changes through the module's installation and upgrade mechanism. Inspect a module using -mod_schema and manage_schema/2 before adding your own versioned step.
Make each step safe for the state it may encounter after a partial attempt. Separate database structure changes from long-running data conversion when a single startup transaction would be too costly.
Test a fresh install and an upgrade from the previously released schema. Keep a database backup for the upgrade test and verify application behavior after migration, not just the table definitions.
If version 1 installed the Garden fixture, change the declaration to -mod_schema(2). for the next release. Keep the fresh-install clause and add a manage_schema({upgrade, 2}, Context) clause for the version-1-to-2 change. Erlang function clauses are separated with semicolons. Do not return success for an upgrade you have not implemented.
The manager calls upgrades in sequence, within a database transaction per schema step, then applies any returned datamodel and records the version. A code reload alone is not an upgrade test: run the module activation/startup lifecycle on the test site. Use manage_data/2 for a deliberate follow-up after schema work, or queue longer conversions. Compare fresh-install and upgraded data before release.
Dependencies, capabilities, and module priority
The main site or module can declare:
-mod_depends([mod_base]).
-mod_prio(500).
Dependencies express requirements for activation. Modules can also declare provided capabilities with -mod_provides; depend on an established capability when your feature requires that service rather than one particular implementation.
Priority determines ordering when modules supply competing resources such as templates. Lower numerical priorities take precedence. Sites commonly use a low priority so their templates override generic module templates.
Do not use priority to hide a missing dependency or duplicate Erlang module name. Check which modules are active, inspect the selected template, and make one intentional override at a time.