// Expert Omeka S developer assistant for Docker-based installations. Covers theme development (SCSS/CSS, templates), module creation (PHP, events, database), configuration management, and troubleshooting. Use for Omeka S customization from simple CSS tweaks to advanced module development.
| name | omeka-s |
| description | Expert Omeka S developer assistant for Docker-based installations. Covers theme development (SCSS/CSS, templates), module creation (PHP, events, database), configuration management, and troubleshooting. Use for Omeka S customization from simple CSS tweaks to advanced module development. |
| license | MIT |
| category | api-integration |
Expert guidance for Docker-based Omeka S development - from simple CSS tweaks to advanced module development.
Docker-based installation - All operations use Docker commands:
omeka-s-app (application), omeka-s-db (database)/var/www/html/ inside containerdocker exec omeka-s-app cat /var/www/html/application/Module.php | grep VERSION# 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
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
/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
# 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
-- 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
mkdir -p my-theme/{asset/{css,js,sass},view/common}
[info]
name = "My Theme"
version = "1.0"
author = "Your Name"
theme_link = ""
author_link = ""
description = "Custom theme"
application/view/ to theme/view/For complete theme guide, see references/theme-development.md
<?php
namespace MyModule;
use Omeka\Module\AbstractModule;
use Laminas\EventManager\SharedEventManagerInterface;
class Module extends AbstractModule
{
public function attachListeners(SharedEventManagerInterface $sharedEventManager)
{
// Add event listeners here
}
}
[info]
name = "My Module"
version = "1.0.0"
author = "Your Name"
description = "Module description"
For complete module guide, see references/module-development.md
theme/asset/sass/_base.scss variablesdocker exec omeka-s-app bash -c "cd /var/www/html/themes/THEME && npm run build"application/view/omeka/site/item/show.phtmltheme/view/omeka/site/item/show.phtml/var/www/html/modules/chown -R www-data:www-dataapplication/ directlyapplication/โ See references/database.md (Content Visibility section)
โ See references/theme-development.md (Troubleshooting Build Issues)
โ See references/troubleshooting.md
volume/files/โ See references/database.md (Media & Thumbnails)
Detailed documentation for each area:
Items need 4 conditions to be visible:
is_public = 1)item_site table)is_open = 1)site_item_set table)See references/database.md for complete details
Themes inherit from default theme:
application/view/asset/sass/See references/theme-development.md for template patterns
Modules extend Omeka via events:
api.search.query - Modify searchview.show.after - Add to page displayform.add_elements - Add form fieldsSee references/module-development.md for event list
For new Omeka S projects:
For detailed guidance on any topic, see the appropriate reference file above.
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.
Omeka S has two distinct types of block layouts that are registered differently:
block_layouts)Used for site pages (like Time Periods, About, etc.)
// In module.config.php
'block_layouts' => [
'invokables' => [
'timePeriodsGrid' => MyModule\Site\BlockLayout\TimePeriodsGrid::class,
],
],
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.
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;
}
}
}
Symptoms:
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.
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 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.
// 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();
Omeka S uses the CSSEditor module for custom CSS. It provides two methods:
css_editor_css) - Written directly in admin interfacecss_editor_external_css) - URLs to external CSS filesDatabase 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:
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:
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).
Omeka S loads templates in this order (highest to lowest priority):
themes/THEME/view/) - HIGHEST PRIORITYmodules/MODULE/view/)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:
grep -r to find ALL instances of a template nameCommon Symptoms:
chown -R www-data:www-data after file changesdocker-compose restart omeka-s after code changes