ahgLandingPagePlugin - Technical Documentation
Version: 1.0.0
Category: Admin
Dependencies: ahgCorePlugin, atom-framework
Overview
Visual landing page builder with drag-and-drop blocks for creating custom archive home pages and promotional pages. Enables administrators to build responsive landing pages without coding knowledge.
Architecture
+---------------------------------------------------------------------+
| ahgLandingPagePlugin |
+---------------------------------------------------------------------+
| |
| +---------------------------------+ +--------------------------+ |
| | landingPageBuilder Module | | Block Templates | |
| | +---------------------------+ | | +--------------------+ | |
| | | actions.class.php | | | | _block_hero_banner | | |
| | | - CRUD operations | | | | _block_search_box | | |
| | | - AJAX endpoints | | | | _block_statistics | | |
| | | - Version management | | | | _block_browse_* | | |
| | +---------------------------+ | | | _block_row_2_col | | |
| +---------------------------------+ | | (20+ templates) | | |
| | | +--------------------+ | |
| v +--------------------------+ |
| +---------------------------------+ |
| | LandingPageService | |
| | +---------------------------+ | |
| | | Page management | | |
| | | Block management | | |
| | | Version control | | |
| | | Dynamic data enrichment | | |
| | +---------------------------+ | |
| +---------------------------------+ |
| | |
| v |
| +---------------------------------+ |
| | LandingPageRepository | |
| | +---------------------------+ | |
| | | Database operations | | |
| | | Query building | | |
| | | Data retrieval | | |
| | +---------------------------+ | |
| +---------------------------------+ |
| | |
| v |
| +-------------------------------------------------------------+ |
| | Database Tables | |
| | atom_landing_page | atom_landing_page_block | |
| | atom_landing_page_block_type | atom_landing_page_version | |
| +-------------------------------------------------------------+ |
| |
+---------------------------------------------------------------------+
Database Schema
ERD Diagram
+-----------------------------------+
| atom_landing_page |
+-----------------------------------+
| PK id BIGINT UNSIGNED |
| name VARCHAR(255) |
| slug VARCHAR(255) UNIQUE |
| description TEXT |
| is_default TINYINT(1) |
| is_active TINYINT(1) |
| FK user_id INT |
| created_at TIMESTAMP |
| updated_at TIMESTAMP |
+-----------------------------------+
|
| 1:N
v
+-----------------------------------+
| atom_landing_page_block |
+-----------------------------------+
| PK id BIGINT UNSIGNED |
| FK page_id BIGINT UNSIGNED |
| FK block_type_id INT |
| FK parent_block_id BIGINT NULL |
| column_slot VARCHAR(20) NULL |
| position INT |
| title VARCHAR(255) |
| config JSON |
| css_classes VARCHAR(500) |
| container_type VARCHAR(50) |
| background_color VARCHAR(20) |
| text_color VARCHAR(20) |
| padding_top TINYINT |
| padding_bottom TINYINT |
| col_span TINYINT DEFAULT 12 |
| is_visible TINYINT(1) |
| created_at TIMESTAMP |
| updated_at TIMESTAMP |
+-----------------------------------+
|
| N:1
v
+-----------------------------------+
| atom_landing_page_block_type |
+-----------------------------------+
| PK id INT UNSIGNED |
| machine_name VARCHAR(100) |
| label VARCHAR(255) |
| icon VARCHAR(100) |
| category VARCHAR(50) |
| config_schema JSON |
| default_config JSON |
| template_file VARCHAR(255) |
| is_container TINYINT(1) |
| max_children INT |
+-----------------------------------+
+-----------------------------------+
| atom_landing_page_version |
+-----------------------------------+
| PK id BIGINT UNSIGNED |
| FK page_id BIGINT UNSIGNED |
| version_number INT |
| status VARCHAR(20) |
| snapshot JSON |
| notes TEXT |
| FK user_id INT |
| created_at TIMESTAMP |
+-----------------------------------+
+-----------------------------------+
| atom_landing_page_audit |
+-----------------------------------+
| PK id BIGINT UNSIGNED |
| FK page_id BIGINT UNSIGNED |
| FK block_id BIGINT NULL |
| action VARCHAR(50) |
| details JSON |
| FK user_id INT |
| created_at TIMESTAMP |
+-----------------------------------+
SQL Schema
CREATE TABLE atom_landing_page (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
name VARCHAR ( 255 ) NOT NULL ,
slug VARCHAR ( 255 ) NOT NULL UNIQUE ,
description TEXT ,
is_default TINYINT ( 1 ) DEFAULT 0 ,
is_active TINYINT ( 1 ) DEFAULT 1 ,
user_id INT UNSIGNED ,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
INDEX idx_slug ( slug ),
INDEX idx_is_default ( is_default ),
INDEX idx_is_active ( is_active )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 ;
CREATE TABLE atom_landing_page_block_type (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
machine_name VARCHAR ( 100 ) NOT NULL UNIQUE ,
label VARCHAR ( 255 ) NOT NULL ,
icon VARCHAR ( 100 ) DEFAULT 'bi-square' ,
category VARCHAR ( 50 ) DEFAULT 'content' ,
config_schema JSON ,
default_config JSON ,
template_file VARCHAR ( 255 ),
is_container TINYINT ( 1 ) DEFAULT 0 ,
max_children INT DEFAULT 0 ,
INDEX idx_machine_name ( machine_name ),
INDEX idx_category ( category )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 ;
CREATE TABLE atom_landing_page_block (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
page_id BIGINT UNSIGNED NOT NULL ,
block_type_id INT UNSIGNED NOT NULL ,
parent_block_id BIGINT UNSIGNED NULL ,
column_slot VARCHAR ( 20 ) NULL ,
position INT DEFAULT 0 ,
title VARCHAR ( 255 ),
config JSON ,
css_classes VARCHAR ( 500 ),
container_type VARCHAR ( 50 ) DEFAULT 'container' ,
background_color VARCHAR ( 20 ) DEFAULT '#ffffff' ,
text_color VARCHAR ( 20 ) DEFAULT '#212529' ,
padding_top TINYINT DEFAULT 3 ,
padding_bottom TINYINT DEFAULT 3 ,
col_span TINYINT DEFAULT 12 ,
is_visible TINYINT ( 1 ) DEFAULT 1 ,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
FOREIGN KEY ( page_id ) REFERENCES atom_landing_page ( id ) ON DELETE CASCADE ,
FOREIGN KEY ( block_type_id ) REFERENCES atom_landing_page_block_type ( id ),
FOREIGN KEY ( parent_block_id ) REFERENCES atom_landing_page_block ( id ) ON DELETE CASCADE ,
INDEX idx_page_id ( page_id ),
INDEX idx_parent_block ( parent_block_id ),
INDEX idx_position ( position )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 ;
CREATE TABLE atom_landing_page_version (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
page_id BIGINT UNSIGNED NOT NULL ,
version_number INT NOT NULL ,
status VARCHAR ( 20 ) DEFAULT 'draft' ,
snapshot JSON NOT NULL ,
notes TEXT ,
user_id INT UNSIGNED ,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
FOREIGN KEY ( page_id ) REFERENCES atom_landing_page ( id ) ON DELETE CASCADE ,
INDEX idx_page_version ( page_id , version_number )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 ;
CREATE TABLE atom_landing_page_audit (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
page_id BIGINT UNSIGNED NOT NULL ,
block_id BIGINT UNSIGNED NULL ,
action VARCHAR ( 50 ) NOT NULL ,
details JSON ,
user_id INT UNSIGNED ,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ,
INDEX idx_page_id ( page_id ),
INDEX idx_action ( action ),
INDEX idx_created_at ( created_at )
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 ;
Block Types
Machine Name
Category
Description
Container
header_section
layout
Page header with logo and nav
No
footer_section
layout
Page footer with columns
No
row_1_col
layout
Single column container
Yes
row_2_col
layout
Two column layout
Yes
row_3_col
layout
Three column layout
Yes
divider
layout
Horizontal separator
No
spacer
layout
Vertical spacing
No
hero_banner
content
Large banner with image
No
text_content
content
Rich text with image
No
image_carousel
content
IIIF collection slideshow
No
search_box
data
Archive search field
No
browse_panels
data
Category links with counts
No
recent_items
data
Latest records
No
featured_items
data
Curated IIIF items
No
statistics
data
Entity count display
No
holdings_list
data
Top-level holdings
No
quick_links
other
Button/link collection
No
repository_spotlight
other
Featured repository
No
map_block
other
Interactive map
No
copyright_bar
other
Copyright notice
No
Routes
Admin Routes
Route Name
URL Pattern
Action
landing_page_list
/admin/landing-pages
list
landing_page_create
/admin/landing-pages/create
create
landing_page_edit
/admin/landing-pages/:id/edit
edit
landing_page_preview
/admin/landing-pages/:id/preview
preview
AJAX Endpoints
Route Name
URL Pattern
Action
landing_page_ajax_add_block
/admin/landing-pages/ajax/add-block
addBlock
landing_page_ajax_update_block
/admin/landing-pages/ajax/update-block
updateBlock
landing_page_ajax_delete_block
/admin/landing-pages/ajax/delete-block
deleteBlock
landing_page_ajax_duplicate_block
/admin/landing-pages/ajax/duplicate-block
duplicateBlock
landing_page_ajax_reorder
/admin/landing-pages/ajax/reorder
reorderBlocks
landing_page_ajax_toggle_visibility
/admin/landing-pages/ajax/toggle-visibility
toggleVisibility
landing_page_ajax_get_config
/admin/landing-pages/ajax/get-config
getBlockConfig
landing_page_ajax_update_settings
/admin/landing-pages/ajax/update-settings
updateSettings
landing_page_ajax_delete
/admin/landing-pages/ajax/delete
delete
landing_page_ajax_save_draft
/admin/landing-pages/ajax/save-draft
saveDraft
landing_page_ajax_publish
/admin/landing-pages/ajax/publish
publish
landing_page_ajax_restore_version
/admin/landing-pages/ajax/restore-version
restoreVersion
landing_page_ajax_move_to_column
/admin/landing-pages/ajax/move-to-column
moveToColumn
Public Routes
Route Name
URL Pattern
Action
landing_page_view
/landing/:slug
index
Service Methods
LandingPageService
namespace AhgLandingPage\Services;
class LandingPageService
{
// Page Management
public function getLandingPageForDisplay(?string $slug = null): ?array
public function getPageForEditor(int $pageId): ?array
public function createPage(array $data, ?int $userId = null): array
public function updatePage(int $pageId, array $data, ?int $userId = null): array
public function deletePage(int $pageId, ?int $userId = null): array
// Block Management
public function addBlock(int $pageId, int $blockTypeId, ?array $config = null,
?int $userId = null, array $options = []): array
public function updateBlock(int $blockId, array $data, ?int $userId = null): array
public function deleteBlock(int $blockId, ?int $userId = null): array
public function reorderBlocks(int $pageId, array $blockOrder, ?int $userId = null): array
public function duplicateBlock(int $blockId, ?int $userId = null): array
public function toggleBlockVisibility(int $blockId, ?int $userId = null): array
// Version Management
public function saveDraft(int $pageId, ?int $userId = null, ?string $notes = null): array
public function publish(int $pageId, ?int $userId = null): array
public function restoreVersion(int $versionId, ?int $userId = null): array
// Data Enrichment
protected function enrichBlockData(object $block): object
protected function getStatisticsData(array $config): array
protected function getRecentItemsData(array $config): array
protected function getBrowsePanelsData(array $config): array
protected function getHoldingsData(array $config): array
protected function getFeaturedItemsData(array $config): array
protected function getRepositorySpotlightData(array $config): ?array
protected function getMapData(array $config): array
// Utilities
public function getBlockTypes(): Collection
public function getAllPages(bool $activeOnly = false): Collection
}
Block Configuration Schemas
Hero Banner
{
"title" : "string" ,
"subtitle" : "string" ,
"background_image" : "string (URL)" ,
"height" : "string (CSS value)" ,
"text_align" : "left|center|right" ,
"overlay_opacity" : "number (0-1)" ,
"title_size" : "string (CSS value)" ,
"subtitle_size" : "string (CSS value)" ,
"show_button" : "boolean" ,
"cta_text" : "string" ,
"cta_url" : "string"
}
Browse Panels
{
"title" : "string" ,
"style" : "list|cards" ,
"columns" : "number (1-6)" ,
"show_counts" : "boolean" ,
"panels" : [
{
"label" : "string" ,
"icon" : "string (Bootstrap icon)" ,
"url" : "string" ,
"count_entity" : "informationobject|repository|actor|digitalobject|accession|term_subjects|term_places"
}
]
}
Statistics
{
"title" : "string" ,
"layout" : "horizontal|vertical" ,
"animate_numbers" : "boolean" ,
"stats" : [
{
"label" : "string" ,
"icon" : "string (Bootstrap icon)" ,
"entity" : "informationobject|repository|actor|digitalobject|accession|function|term_subjects|term_places"
}
]
}
Recent Items
{
"title" : "string" ,
"entity_type" : "informationobject|repository" ,
"limit" : "number (1-20)" ,
"layout" : "grid|list" ,
"columns" : "number (1-6)" ,
"show_date" : "boolean" ,
"show_thumbnail" : "boolean"
}
Search Box
{
"placeholder" : "string" ,
"show_advanced" : "boolean" ,
"style" : "default|large|minimal"
}
Text Content
{
"title" : "string" ,
"content" : "string (HTML)" ,
"image" : "string (URL)" ,
"image_position" : "none|left|right|top|bottom" ,
"image_width" : "string (percentage)"
}
Quick Links
{
"title" : "string" ,
"layout" : "inline|grid|list" ,
"style" : "buttons|links|cards" ,
"links" : [
{
"label" : "string" ,
"url" : "string" ,
"icon" : "string (Bootstrap icon)" ,
"new_window" : "boolean"
}
]
}
Holdings List
{
"title" : "string" ,
"limit" : "number (1-50)" ,
"sort" : "title|hits" ,
"repository_id" : "number (optional)" ,
"show_level" : "boolean" ,
"show_dates" : "boolean" ,
"show_extent" : "boolean" ,
"show_hits" : "boolean"
}
Map Block
{
"title" : "string" ,
"height" : "string (CSS value)" ,
"zoom" : "number (1-20)" ,
"show_all_repositories" : "boolean" ,
"repository_ids" : [ "number array" ]
}
Column Layouts (2-col, 3-col)
{
"gap" : "string (CSS value)" ,
"stack_mobile" : "boolean" ,
"col1_width" : "string (percentage)" ,
"col2_width" : "string (percentage)" ,
"col3_width" : "string (percentage, 3-col only)"
}
Dynamic Data Sources
Entity Count Mapping
Entity
Database Query
informationobject
information_object WHERE parent_id IS NULL
repository
repository
actor
actor
digitalobject
digital_object
accession
accession
function
function_object
term_subjects
term WHERE taxonomy_id = 35
term_places
term WHERE taxonomy_id = 42
Recent Items Query
SELECT io . id , i18n . title , slug . slug , obj . created_at , do . id as has_digital_object
FROM information_object io
JOIN object obj ON io . id = obj . id
JOIN information_object_i18n i18n ON io . id = i18n . id AND i18n . culture = ?
LEFT JOIN digital_object do ON io . id = do . object_id
LEFT JOIN slug ON io . id = slug . object_id
ORDER BY obj . created_at DESC
LIMIT ?
Popular This Week Query
SELECT object_id , COUNT ( object_id ) as hits
FROM access_log
WHERE access_date BETWEEN DATE_SUB ( NOW (), INTERVAL 1 WEEK ) AND NOW ()
GROUP BY object_id
ORDER BY hits DESC
LIMIT ?
JavaScript Components
landing-page-builder.js
Main builder functionality:
- Drag and drop handling (Sortable.js)
- Block CRUD operations
- Configuration forms
- Preview updates
- Auto-save
landing-page-builder-columns.js
Column layout management:
- Nested block handling
- Column drop zones
- Block movement between columns
Key JavaScript Functions
// Initialize builder
window . LandingPageBuilder . init ();
// Add block programmatically
LandingPageBuilder . addBlock ( blockTypeId , config , position );
// Update block configuration
LandingPageBuilder . updateBlock ( blockId , config );
// Reorder blocks
LandingPageBuilder . saveOrder ();
// Load block config form
LandingPageBuilder . showConfigPanel ( blockId );
// Save and publish
LandingPageBuilder . saveDraft ();
LandingPageBuilder . publish ();
Template Files
Module Templates
File
Purpose
listSuccess.php
Page list admin view
createSuccess.php
New page form
editSuccess.php
Visual builder interface
indexSuccess.php
Public page display
_blockCard.php
Block card in editor
_nestedBlock.php
Nested block display
Block Templates
Located in modules/landingPageBuilder/templates/blocks/:
File
Block Type
_block_hero_banner.php
Hero banner
_block_search_box.php
Search field
_block_browse_panels.php
Browse links
_block_statistics.php
Stats counters
_block_recent_items.php
Recent records
_block_featured_items.php
IIIF carousel
_block_text_content.php
Text with image
_block_quick_links.php
Link buttons
_block_holdings_list.php
Holdings list
_block_repository_spotlight.php
Repository feature
_block_map.php
Leaflet map
_block_header_section.php
Page header
_block_footer_section.php
Page footer
_block_row_2_col.php
2-column layout
_block_row_3_col.php
3-column layout
_block_divider.php
Separator line
_block_spacer.php
Vertical space
_block_image_carousel.php
Image slideshow
_block_copyright_bar.php
Copyright notice
Permissions
Action
Required Role
View public pages
None (public)
List all pages
Administrator
Create/Edit pages
Administrator
Delete pages
Administrator
Publish pages
Administrator
Configuration
Plugin Settings
Setting
Default
Description
landing_page_enabled
true
Enable landing pages
default_container_type
container
Default block container
max_blocks_per_page
50
Maximum blocks allowed
auto_save_interval
30000
Auto-save interval (ms)
enable_versioning
true
Enable version control
max_versions
10
Maximum versions to keep
Dependencies
PHP Dependencies
Laravel Illuminate/Database (Query Builder)
atom-framework services
JavaScript Dependencies
Sortable.js (drag and drop)
Bootstrap 5 (UI components)
Leaflet.js (map block)
CSS Dependencies
Bootstrap 5
Bootstrap Icons
Leaflet CSS (for map)
Installation
Database Setup
php bin/atom extension:enable ahgLandingPagePlugin
php bin/atom landing-page:install
Manual Installation
-- Run install.sql from plugin database/ directory
SOURCE / path / to / ahgLandingPagePlugin / database / install . sql ;
-- Insert default block types
SOURCE / path / to / ahgLandingPagePlugin / database / block_types . sql ;
Success Response
{
"success" : true ,
"page_id" : 1 ,
"block_id" : 15 ,
"version_id" : 3
}
Error Response
{
"success" : false ,
"error" : "Error message description"
}
Block Data Response
{
"success" : true ,
"block" : {
"id" : 15 ,
"type_label" : "Hero Banner" ,
"type_icon" : "bi-image" ,
"machine_name" : "hero_banner" ,
"config" : {},
"config_schema" : {},
"is_visible" : 1 ,
"position" : 0
}
}
Audit Actions
Action
Description
page_created
New page created
page_updated
Page settings changed
page_deleted
Page removed
page_published
Page made public
block_added
Block added to page
block_updated
Block configuration changed
block_deleted
Block removed
block_duplicated
Block copied
block_visibility_toggled
Block shown/hidden
blocks_reordered
Block order changed
version_restored
Previous version restored
Caching
Block type definitions are cached
Dynamic data (stats, recent items) should use short cache TTL
Page structure can be cached longer
Query Optimization
Use eager loading for block relationships
Limit dynamic data queries (max 20 items)
Index frequently queried columns
Best Practices
Avoid excessive nested columns
Limit blocks per page (recommended: 20-30)
Use specific entity types for statistics
Optimize images before upload
Part of the AtoM AHG Framework
February 4, 2026
February 4, 2026