Omeka S Development Skill
Expert guidance for Docker-based Omeka S development - from simple CSS tweaks to advanced module development.
Quick Start
Installation Context
Docker-based installation - All operations use Docker commands:
- •Container:
omeka-s-app(application),omeka-s-db(database) - •Base path:
/var/www/html/inside container - •Version check:
docker exec omeka-s-app cat /var/www/html/application/Module.php | grep VERSION
Essential Docker Patterns
# Read files docker exec omeka-s-app cat /var/www/html/path/to/file # List directories docker exec omeka-s-app ls -la /var/www/html/themes/ # Copy files into container docker cp local-file omeka-s-app:/var/www/html/path/ # Fix permissions after copying docker exec omeka-s-app chown -R www-data:www-data /var/www/html/themes/ # Database access docker exec -it omeka-s-db mysql -u omeka -p omeka
When to Use This Skill
- •Theme Development: Custom layouts, SCSS/CSS styling, template overrides
- •Module Development: PHP modules, event listeners, forms, database entities
- •Configuration: Site setup, content visibility, database relationships
- •Troubleshooting: Media issues, permission problems, build failures
Development Workflow Decision Tree
User Request → What type of work?
├─ Theme Customization
│ ├─ Simple CSS change?
│ │ └─ Edit theme/asset/css/style.css directly
│ │ (see references/theme-development.md → Quick CSS Editing)
│ │
│ ├─ Need SCSS/variables?
│ │ └─ Use SCSS build process
│ │ 1. Edit theme/asset/sass/*.scss
│ │ 2. Run: docker exec omeka-s-app bash -c "cd /var/www/html/themes/THEME && npm run build"
│ │ (see references/theme-development.md → SCSS Build Process)
│ │
│ └─ Template override?
│ └─ Copy from application/view/ to theme/view/
│ (see references/theme-development.md → Template Structure)
│
├─ Module Development
│ ├─ Creating new module?
│ │ └─ Follow module structure pattern
│ │ (see references/module-development.md → Module Structure)
│ │
│ ├─ Adding event listener?
│ │ └─ Register in Module.php attachListeners()
│ │ (see references/module-development.md → Event System)
│ │
│ └─ Database entities?
│ └─ Create Entity, update module.ini
│ (see references/module-development.md → Database Entities)
│
├─ Content Visibility Issues
│ └─ Items not showing?
│ 1. Check database relationships
│ 2. Verify is_public flags
│ 3. Confirm site assignments
│ (see references/database.md → Content Visibility)
│
└─ Configuration/Setup
└─ See references/troubleshooting.md
Directory Structure
/var/www/html/
├── application/ # Core (DON'T MODIFY)
│ ├── view/ # Default templates (COPY to theme to override)
│ └── src/ # PHP source
├── config/
│ ├── database.ini
│ └── local.config.php
├── modules/ # Custom modules here
│ └── MyModule/
│ ├── Module.php
│ ├── module.ini
│ ├── src/
│ └── view/
├── themes/ # Custom themes here
│ └── MyTheme/
│ ├── theme.ini
│ ├── asset/
│ │ ├── css/
│ │ └── sass/
│ └── view/
└── volume/
└── files/ # Uploaded media
Quick Reference
Common File Operations
# Read theme file docker exec omeka-s-app cat /var/www/html/themes/THEME/theme.ini # Copy theme into container docker cp ./my-theme omeka-s-app:/var/www/html/themes/ docker exec omeka-s-app chown -R www-data:www-data /var/www/html/themes/my-theme # View logs docker logs omeka-s-app docker logs omeka-s-db # Restart services docker restart omeka-s-app
Common Database Queries
-- Make all items public UPDATE resource SET is_public = 1 WHERE resource_type = 'Omeka\\Entity\\Item'; -- Assign all items to site 1 INSERT INTO item_site (item_id, site_id) SELECT id, 1 FROM item ON DUPLICATE KEY UPDATE site_id = VALUES(site_id); -- Check item visibility SELECT r.id, r.title, r.is_public, COUNT(is_i.item_id) as in_site FROM resource r LEFT JOIN item_site is_i ON r.id = is_i.item_id WHERE r.resource_type = 'Omeka\\Entity\\Item' GROUP BY r.id;
For complete database operations, see references/database.md
Theme Development Quick Start
- •Create theme directory:
mkdir -p my-theme/{asset/{css,js,sass},view/common}
- •Required theme.ini:
[info] name = "My Theme" version = "1.0" author = "Your Name" theme_link = "" author_link = "" description = "Custom theme"
- •Override templates: Copy from
application/view/totheme/view/
For complete theme guide, see references/theme-development.md
Module Development Quick Start
- •Basic Module.php:
<?php
namespace MyModule;
use Omeka\Module\AbstractModule;
use Laminas\EventManager\SharedEventManagerInterface;
class Module extends AbstractModule
{
public function attachListeners(SharedEventManagerInterface $sharedEventManager)
{
// Add event listeners here
}
}
- •Required module.ini:
[info] name = "My Module" version = "1.0.0" author = "Your Name" description = "Module description"
For complete module guide, see references/module-development.md
Common Workflows
Workflow 1: Change Theme Colors
- •Edit
theme/asset/sass/_base.scssvariables - •Run build:
docker exec omeka-s-app bash -c "cd /var/www/html/themes/THEME && npm run build" - •Clear cache if needed
- •Reload page
Workflow 2: Override Item Display Template
- •Find template:
application/view/omeka/site/item/show.phtml - •Copy to theme:
theme/view/omeka/site/item/show.phtml - •Edit theme copy
- •Upload to container if needed
- •Test changes
Workflow 3: Fix Items Not Showing
- •Check database relationships (see references/database.md)
- •Run visibility queries
- •Verify site assignments
- •Check item set linkage
- •Clear cache
Workflow 4: Add Custom Module
- •Create module structure
- •Write Module.php and module.ini
- •Copy to
/var/www/html/modules/ - •Fix permissions
- •Install via admin interface
- •Test functionality
Best Practices
✅ DO
- •Always fix permissions after copying files:
chown -R www-data:www-data - •Use SCSS build process for maintainable styling
- •Copy templates to theme - never modify
application/directly - •Test database queries on copies before production
- •Version control your custom themes and modules
- •Document custom code - future you will thank you
❌ DON'T
- •Don't modify core files in
application/ - •Don't skip permission fixes - causes mysterious errors
- •Don't edit compiled CSS - changes will be overwritten by SCSS build
- •Don't forget site assignments - items won't show without them
- •Don't skip backups before database changes
Troubleshooting
Items Not Visible
→ See references/database.md (Content Visibility section)
CSS Changes Not Appearing
- •Check if SCSS is being compiled
- •Clear browser cache
- •Verify file permissions
- •Check theme is active
→ See references/theme-development.md (Troubleshooting Build Issues)
Module Not Loading
- •Check module.ini format
- •Verify Module.php namespace
- •Check file permissions
- •View error logs
→ See references/troubleshooting.md
Media/Thumbnail Issues
- •Check file permissions in
volume/files/ - •Verify Imagemagick is installed
- •Check thumbnail generation settings
→ See references/database.md (Media & Thumbnails)
Reference Files
Detailed documentation for each area:
- •references/database.md - Site configuration, content visibility, database relationships, media system, SQL queries
- •references/theme-development.md - Complete theme structure, SCSS build process, template overrides, view helpers
- •references/module-development.md - Module structure, event system, forms, database entities, API integration
- •references/troubleshooting.md - Common issues, error messages, debugging techniques
- •examples/workflows.md - Step-by-step examples for common tasks
Key Concepts
Content Visibility (Critical!)
Items need 4 conditions to be visible:
- •Item is public (
is_public = 1) - •Item is assigned to site (
item_sitetable) - •Item set is open (
is_open = 1) - •Item set is linked to site (
site_item_settable)
See references/database.md for complete details
Theme Inheritance
Themes inherit from default theme:
- •Your theme only contains overrides
- •Missing templates fall back to
application/view/ - •CSS builds from SCSS in
asset/sass/
See references/theme-development.md for template patterns
Module Event System
Modules extend Omeka via events:
- •
api.search.query- Modify search - •
view.show.after- Add to page display - •
form.add_elements- Add form fields
See references/module-development.md for event list
Getting Started Checklist
For new Omeka S projects:
- •☐ Verify Docker containers running
- •☐ Check Omeka version
- •☐ Create/activate custom theme
- •☐ Configure site settings
- •☐ Set up content visibility (database queries)
- •☐ Test theme customizations
- •☐ Install required modules
- •☐ Configure media handling
Resources
- •Official Docs: https://omeka.org/s/docs/
- •Developer Docs: https://omeka.org/s/docs/developer/
- •Docker Hub: https://hub.docker.com/r/dodeeric/omeka-s
- •Forums: https://forum.omeka.org/
For detailed guidance on any topic, see the appropriate reference file above.
Critical Lessons Learned
Modern MariaDB Commands (2024+)
Newer MariaDB Docker images use different command names:
# OLD (deprecated) docker exec omeka-s-db mysqladmin ping docker exec omeka-s-db mysql -u user -p database # NEW (current) docker exec omeka-s-db mariadb-admin ping docker exec omeka-s-db mariadb -u user -p database
Always use mariadb and mariadb-admin commands for compatibility.
Block Layouts: Two Types
Omeka S has two distinct types of block layouts that are registered differently:
1. Site Page Blocks (block_layouts)
Used for site pages (like Time Periods, About, etc.)
// In module.config.php
'block_layouts' => [
'invokables' => [
'timePeriodsGrid' => MyModule\Site\BlockLayout\TimePeriodsGrid::class,
],
],
2. Resource Page Blocks (resource_page_block_layouts)
Used for item/media/item-set display pages
// In module.config.php
'resource_page_block_layouts' => [
'invokables' => [
'relatedItems' => MyModule\Site\ResourcePageBlockLayout\RelatedItems::class,
],
],
Key Difference: Site page blocks go in regular pages; resource page blocks appear when viewing an item.
Using the API in Block Layouts
NEVER use direct database connections in blocks. Use the API instead:
// ❌ WRONG - Will fail
$connection = $view->getHelperPluginManager()->get('api')->getManager()->getConnection();
// ✅ CORRECT - Use the API
$view->api()->search('items', [
'site_id' => $site->id(),
'property' => [[
'joiner' => 'and',
'property' => 'dcterms:coverage',
'type' => 'eq',
'text' => 'some value',
]],
]);
Getting unique property values dynamically:
// Get property first
$coverageProperty = $view->api()->searchOne('properties', [
'term' => 'dcterms:coverage',
])->getContent();
// Get all items with that property
$allItems = $view->api()->search('items', [
'site_id' => $site->id(),
'has_property' => [$coverageProperty->id()],
])->getContent();
// Extract unique values
$uniqueValues = [];
foreach ($allItems as $item) {
$values = $item->value('dcterms:coverage', ['all' => true]);
foreach ($values as $val) {
$textValue = (string)$val;
if (!in_array($textValue, $uniqueValues)) {
$uniqueValues[] = $textValue;
}
}
}
Module Version Mismatches
Symptoms:
- •Blocks render empty
- •"Unknown block layout" errors
- •Features not working despite module being active
Diagnosis:
# Check file version docker exec omeka-s-app cat /var/www/html/modules/ModuleName/config/module.ini | grep version # Check database version docker exec omeka-s-db mariadb -u omekas -pomekas omekas -e "SELECT id, version FROM module WHERE id = 'ModuleName';"
Solution: Download the correct version from GitHub releases to match database expectations.
Custom Block Layout Template
Full working example of a site page block:
<?php
namespace MyModule\Site\BlockLayout;
use Omeka\Api\Representation\SiteRepresentation;
use Omeka\Api\Representation\SitePageRepresentation;
use Omeka\Api\Representation\SitePageBlockRepresentation;
use Omeka\Site\BlockLayout\AbstractBlockLayout;
use Laminas\View\Renderer\PhpRenderer;
class MyCustomBlock extends AbstractBlockLayout
{
public function getLabel()
{
return 'My Custom Block'; // @translate
}
public function form(
PhpRenderer $view,
SiteRepresentation $site,
SitePageRepresentation $page = null,
SitePageBlockRepresentation $block = null
) {
// Get saved data
$data = $block ? $block->data() : [];
$myValue = $data['myValue'] ?? '';
// Return HTML form for admin
return sprintf(
'<div class="field"><label>My Setting</label><input type="text" name="o:block[__blockIndex__][o:data][myValue]" value="%s"></div>',
htmlspecialchars($myValue, ENT_QUOTES)
);
}
public function render(PhpRenderer $view, SitePageBlockRepresentation $block)
{
$site = $view->currentSite();
$data = $block->data();
// Query items dynamically
$items = $view->api()->search('items', [
'site_id' => $site->id(),
'limit' => 10,
])->getContent();
// Render template
return $view->partial('common/block-layout/my-custom-block', [
'items' => $items,
'data' => $data,
]);
}
}
Block Data Storage
Block configuration is stored as JSON in site_page_block.data:
-- View block data
SELECT id, layout, data FROM site_page_block WHERE page_id = 10;
-- Update block data (be careful with escaping!)
UPDATE site_page_block
SET data = '{"key": "value"}'
WHERE id = 54;
Important: Data must be valid JSON. Use proper escaping when updating via SQL.
Querying with Property Filters
// Search items by property value
$response = $view->api()->search('items', [
'site_id' => $site->id(),
'property' => [[
'joiner' => 'and', // 'and' or 'or'
'property' => 'dcterms:title', // property term
'type' => 'eq', // 'eq', 'neq', 'in', 'nin', 'ex', 'nex'
'text' => 'search term',
]],
]);
$count = $response->getTotalResults();
$items = $response->getContent();
CSS Loading System (CSSEditor Module)
Omeka S uses the CSSEditor module for custom CSS. It provides two methods:
- •Inline CSS (
css_editor_css) - Written directly in admin interface - •External CSS (
css_editor_external_css) - URLs to external CSS files
Database Storage:
-- Check current CSS configuration SELECT id, value FROM site_setting WHERE id LIKE '%css%'; -- Example output: css_editor_css (empty or contains CSS code) css_editor_external_css ["/themes/foundation/asset/css/cdha-custom.css"]
CSS Loading Order (Cascade):
1. Core CSS (iconfonts.css, resource-page-blocks.css) 2. Module CSS (from installed modules) 3. Theme base CSS (default.css, inkwell.css, etc.) 4. Inline CSS from css_editor_css (via /s/SITE/css-editor endpoint) 5. External CSS from css_editor_external_css 6. Additional module CSS
Key Points:
- •Inline CSS loads BEFORE external CSS - External files can override inline styles
- •Both are added by CSSEditor module, accessible via Admin → Sites → [Site] → Theme
- •External CSS URLs can be theme-relative paths or full CDN URLs
- •Inline CSS is stored directly in database; external CSS is just a reference
Common Issue: CSS Conflicts
If CSS changes don't appear:
-- Clear conflicting inline CSS UPDATE site_setting SET value = '' WHERE id = 'css_editor_css'; -- Check what external files are referenced SELECT value FROM site_setting WHERE id = 'css_editor_external_css';
Best Practice:
- •Use external CSS files for maintainable, version-controlled styles
- •Use inline CSS only for quick tweaks or site-specific overrides
- •Reference external files via CSSEditor rather than hardcoding in templates
Real-World Example:
css_editor_external_css: ["/themes/foundation/asset/css/cdha-custom.css"]
This tells Omeka to load cdha-custom.css after the base theme CSS but load it as a separate file (not copied into the inline editor).
Template Precedence Order (CRITICAL!)
Omeka S loads templates in this order (highest to lowest priority):
- •Theme templates (
themes/THEME/view/) - HIGHEST PRIORITY - •Module templates (
modules/MODULE/view/) - •Core templates (
application/view/) - LOWEST PRIORITY
⚠️ This means theme templates override EVERYTHING, including module templates.
Real-World Example:
# You edit this module template: modules/CdhaBlocks/view/common/resource-page-block-layout/filtered-values-main.phtml # But Omeka actually uses this theme template (if it exists): themes/foundation/view/common/resource-page-block-layout/filtered-values-main.phtml # Result: Your module changes don't appear, causing confusion!
Debugging Template Issues:
When template changes don't appear:
# 1. Check if theme has override
find themes/ACTIVE_THEME -name "template-name.phtml"
# 2. If found, edit the THEME template, not the module template
# 3. Use error logging to confirm which file loads:
# Add to top of both templates:
<?php error_log('TEMPLATE: ' . __FILE__); ?>
Best Practice:
- •Always check theme directory first before editing module templates
- •Use
grep -rto find ALL instances of a template name - •Remember: even resource page block templates can be overridden by themes
Common Symptoms:
- •"I changed the module template but nothing happens"
- •"My debug logs in the module template don't appear"
- •"The module is being called but using old code"
Common Pitfalls
- •Don't hardcode values - Query database dynamically
- •Don't use direct SQL - Use API methods
- •Don't forget permissions -
chown -R www-data:www-dataafter file changes - •Don't skip version checks - Module version mismatches cause silent failures
- •Don't forget to restart -
docker-compose restart omeka-safter code changes - •Don't edit module templates without checking for theme overrides - Theme templates take precedence