A few arbitrary tips on Omeka-S theming.
Retain existing classes on analogous elements as far as possible, as they are sometimes referred to by internal Omeka CSS classes. Obviously you can imagine edge cases where this isn't desirable. But it's a good first rule to follow. Obviously if you omit some design-element entirely you must also omit the class associated with it.
In a similar vein, be wary of doing less than the requirements of a theme. There's no real verification or way of testing that a theme handles all paths sensibly and in a manner consistent with the expectations of the user.
For example, there are certain site settings your theme should support: "embed media on item page" is a site specific setting that you must handle within your theme, but there is no validation that your theme does in fact handle this.
Do not ever use <p></p>
elements in your module markup. Use custom divs or
spans with your own classes. Why? The Html
blocklayout generates <p>
tags,
so any attempt to style page text will often inadvertently style your
more-irregular p
tags.
Debugging
Debugging templates: a very rudimentary debugging method is to fill your partials with introductory HTML comments naming their source file.
Eg:
<!-- BEGIN view/omeka/site/item/show.phtml -->
<p>This is content this is content this is content</p>
<!-- END view/omeka/site/item/show.phtml -->
One way to modularize your CSS is to break out the per-page CSS into individual CSS files, then include them in layout.phtml
$this->headLink()->appendStylesheet($this->assetUrl('css/style.css'));
$this->headLink()->appendStylesheet($this->assetUrl('css/item-show.css'));
Here, item-show.css
contains rules associated to the item detail page.
Don't try to remove the stock JS loads shown below from your layout.phtml. These are internal Omeka files that in turn may cause the loading of more than one JS file.
$this->headScript()->prependFile($this->assetUrl('js/global.js', 'Omeka'));
$this->headScript()->prependFile($this->assetUrl('vendor/jquery/jquery.min.js', 'Omeka'));
If you need to style the 'page title' block which is available in the page editor, you don't have a lot of good options, because it's not addressable by any specific CSS style, being defined in its own PHP implementation. You just have the choice to do the following:
.my-page-content > .blocks > h2 {
background-color: var(--accent2);
text-align: center;
font-family: "Quicksand Bold";
padding: 1em 1em;
margin: 0 0;
margin-bottom: 1em;
}
Where my-page-content
is a class applied to the page content using an override
on view/omeka/site/page/show.phtml
. .blocks
is created by the framework.
You have to just assume that every h2
block is a page title -- this means your
own modules and markup can't generally use h2
; you must stick to div
and
theme-specific classes.
Module development
Which modules define new blocks? The answer, current as of 2020-11-24, is:
- FieldsAsTags
- Folksonomy
- Reference
- Collecting
- Scripto
- SimpleCarousel
- UniversalViewer
- Mapping
Conventions
Conventions for naming data values stored in blocks: use snake_case
. There is
limited precedent in the upstream source for this convention, specifically the
ListOfSites
block-layout.
When passing data items through to partials, you should translate them into
camelCase
. That will cause the .phtml
file to continue to look relatively
idiomatic.
Javascript-laden pages
There are some cases where you have some significant amount of JavaScript involved with the default theme. This JS will hardcode certain IDs and classes to identify HTML elements. This is a big problem if you plan to significantly restructure the HTML. For those pages I suggest, where possible, to stick to the default templates as closely as possible, while wrapping the whole piece in a theme-specific div in order to scope your specific styles. The goal is to stick to the original markup 100%, while applying all tweaks in CSS, a la "Zen Garden". This may not always be possible.
Creating global config values
There are many levels that configuration can exist at within Omeka-S. An incomplete list:
- Configuration can obviously exist at the level of individual blocks within a page.
- Configuration can exist specific to a theme; this is declared within the
[config]
block oftheme.ini
. - Configuration can exist that is specific to a site. An example of this is
Collecting
: this module defines its "terms of service" field as a site-specific config value. - A module can provide its own module-level configuration which is accessible via a form within the module admin page.
We are going to talk about the last one of those here. There are two points of
contact with the API surface: the first is the mandatory Module.php
file
required for a module, the second is the form-specific class, although this
second is actually not strictly necessary. The key methods are
getConfigForm()
and handleConfigForm()
, the latter using the
Omeka\Settings
service. This is stored in the setting
table in MySQL.
Note that there's a flagrant bug in the below code: we should be explicitly
fetching the setting value from the service before we render the form; as shown,
we won't show the existing value when we load up the form. This is left as an
exercise to the reader.
Note that the string-valued name of the setting, here
qhs_module_action_bubble_text
, exists in a global namespace, so should be
chosen carefully so as not to clash with any other installed modules nor those
of Omeka-S itself.
class Module extends AbstractModule {
public function getConfig() {
return include __DIR__ . '/config/module.config.php';
}
public function getConfigForm(PhpRenderer $renderer) {
$services = $this->getServiceLocator();
$form = $services->get('FormElementManager')->get(ConfigForm::class);
$html = $renderer->formCollection($form);
return $html;
}
public function handleConfigForm(AbstractController $controller) {
$settings = $this->getServiceLocator()->get('Omeka\Settings');
$form = new ConfigForm;
$form->init();
$form->setData($controller->params()->fromPost());
if ($form->isValid()) {
$formData = $form->getData();
$settings->set('qhs_module_action_bubble_text', $formData['content']);
return true;
} else {
$controller->messenger()->addErrors($form->getMessages());
return false;
}
}
}
namespace QhsModule\Form;
use Zend\Form\Form;
use Zend\Form\Element;
class ConfigForm extends Form {
public function init() {
$this->add([
'name' => 'content',
'type' => Element\Text::class,
'options' => [
'label' => 'Action bubble content',
'info' => 'This text will be displayed inside the action bubble.',
],
]);
}
}
?>
Collecting module
Collecting is one of the most complex modules available for Omeka-S; its job is to solicit contributions to the archive from outside visitors. We consider Collecting v1.3.0. Collecting has its documentation within the Omeka-S manual. It's arguably on the verge between being a core feature (it creates its own database tables, for instance).
Database tables
collecting_form
collecting_input
collecting_item
collecting_prompt
collecting_user
Collecting will automatically try to send out a confirmation email. That assumes it can actually access an MTA.
Each form is made out of prompts, which can be for a variety of things; they can be prompts for any resource value which will be stored onto the created item
You add collecting forms to pages by using the special block layout that the module creates.
User public and user private need to be added as separate prompts.
The collecting form generates its own H2, using its custom partials which appear
under the collecting
directory in the view part.
collecting/site/index/success.phtml
for example. So any page that includes a
collecting form should probably not have its own page title, which also
generates an H2 element.
Forms will receive ids like 'collecting_form' rather than any id, so you may attempt to use that to target them via CSS as below; yes, this is hacky and disgusting. If you've got a better idea, I'm all ears.
form[id^="collecting_form_"] {
}