Custom Extensions
Middleman extensions are Ruby classes which can hook into various points of the Middleman system, add new features and manipulate content. This guide explains some of what's available, but you should read the Middleman source and the source of plugins like middleman-blog to discover all the hooks and extension points.
Bootstrapping a new extension
To bootstrap a new extension you can use the extension
-command. This will
create all needed files.
middleman extension middleman-my_extension
# create middleman-my_extension/.gitignore
# create middleman-my_extension/Rakefile
# create middleman-my_extension/middleman-my_extension.gemspec
# create middleman-my_extension/Gemfile
# create middleman-my_extension/lib/middleman-my_extension/extension.rb
# create middleman-my_extension/lib/middleman-my_extension.rb
# create middleman-my_extension/features/support/env.rb
# create middleman-my_extension/fixtures
Basic Extension
The most basic extension looks like:
class MyFeature < Middleman::Extension
def initialize(app, options_hash={}, &block)
super
end
alias :included :registered
end
::Middleman::Extensions.register(:my_feature, MyFeature)
This module must be accessible to your config.rb
file. Either define it
directly in that file, or define it in another Ruby file and require
it in
config.rb
Finally, once your module is included, you must activate it in config.rb
:
activate :my_feature
The register
method lets you choose the name your
extension is activated with. It can also take a block if you want to require
files only when your extension is activated.
In the MyFeature
extension, the initialize
method will be called as soon as
the activate
command is run. The app
variable is an instance of
Middleman::Application
class.
activate
can also take an options hash (which are passed to register
) or a
block which can be used to configure your extension. You define options with the
options
class method and then access them with options
:
class MyFeature < Middleman::Extension
# All the options for this extension
option :foo, false, 'Controls whether we foo'
def initialize(app, options_hash={}, &block)
super
puts options.foo
end
end
# Two ways to configure this extension
activate :my_feature, foo: 'whatever'
activate :my_feature do |f|
f.foo = 'whatever'
f.bar = 'something else'
end
Passing options to activate
is preferred to setting global or singleton
variables.
Adding Methods to config.rb
Methods within your extension can be made available to config.rb
with the
expose_to_config
method.
class MyFeature < Middleman::Extension
expose_to_config :say_hello
def say_hello
puts "Hello"
end
end
Adding Methods to templates
Similar to config, methods can be exposed to the template context:
class MyFeature < Middleman::Extension
expose_to_template :say_hello
def say_hello
"Hello Template"
end
end
Adding Helpers
Another way to add methods to templates are as helpers. Unlike "exposed methods" above, helpers do not have access to the rest of your extension. These are good for large packages of "pure" methods grouped into a module. In most cases, the above "exposed methods" are preferred.
class MyFeature < Middleman::Extension
def initialize(app, options_hash={}, &block)
super
end
helpers do
def make_a_link(url, text)
"<a href='#{url}'>#{text}</a>"
end
end
end
Now, inside your templates, you will have access to a make_a_link
method.
Here's an example using an ERB template:
<h1><%= make_a_link("http://example.com", "Click me") %></h1>
Sitemap Manipulators
You can modify or add pages in the sitemap by creating a Sitemap extension.
The directory_indexes
extension uses this feature to
reroute normal pages to their directory-index version, and the blog extension
uses several plugins to generate tag and calendar pages. See the
Sitemap::Store
class for more details.
Note: manipulate_resource_list
is a "reducer". It is required to return
the full set of resources to be passed to the next step of the pipeline.
class MyFeature < Middleman::Extension
def manipulate_resource_list(resources)
resources.each do |resource|
resource.destination_path.gsub!("original", "new")
end
resources
end
end
Callbacks
There are many parts of the Middleman life-cycle that can be hooked into by extensions. These are some examples, but there are many more.
after_configuration
Sometimes you will want to wait until the config.rb
has been executed to run
code. For example, if you rely on the :css_dir
variable, you should wait until
it has been set. For this, we'll use a callback:
class MyFeature < Middleman::Extension
def after_configuration
puts app.config[:css_dir]
end
end
after_build
This callback is used to execute code after the build process has finished. The middleman-smusher extension uses this feature to compress all the images in the build folder after it has been built. It's also conceivable to integrate a deployment script after build.
class MyFeature < Middleman::Extension
def after_build(builder)
builder.thor.run './my_deploy_script.sh'
end
end
The builder.thor
parameter is the class that runs the build CLI, and
you can use Thor actions from it.
Additional Available Callbacks
initialized
: called before config is parsed, and before extensions are registeredconfigure
: called to run anyconfigure
blocks (once for current environment, again for the current mode)before_extensions
: called before theExtensionManager
is instantiatedbefore_instance_block
: called before any blocks are passed to the configuration contextbefore_sitemap
: called before theSiteMap::Store
is instantiated, which initializes the sitemapbefore_configuration
: called before configuration is parsed, mostly used for extensionsafter_configuration_eval
: called after the configuration is parsed, before the pre-extension callbackready
: called when everything is stablebefore_build
: called before the site build process runsbefore_shutdown
: called in theshutdown!
method, which lets users know the application is shutting downbefore
: called before Rack requestsbefore_server
: called before thePreviewServer
is createdreload
: called before the new application is initialized on a reload event