Programmatic HTML Structures for Modern REDAXO Websites
MFragment is a REDAXO addon for structured HTML generation with component-oriented architecture. It enables programmatic creation of HTML structures, responsive media management and Bootstrap 5 integration.
- Programmatic HTML Creation - Create HTML structures with PHP code
- Direct HTML Rendering - No template engine required
- Bootstrap 5 Integration - Includes standard Bootstrap components
- Method Chaining - Fluent API design for improved developer experience
- Extensible Architecture - Custom components through AbstractComponent inheritance
- MFragment Integration - All MFragment tools available
- HTML Element Creation - Create arbitrary HTML structures with MFragment methods
- Modular Structure - Components can be used in all contexts
As MForm is for forms, MFragment is for HTML structures - create HTML layouts programmatically:
- Complete HTML Coverage - Generation of arbitrary HTML elements, attributes and structures
- Nested Components - Complex layouts with unlimited nesting depth
- Dynamic Content Generation - Generate HTML programmatically based on data
- Layout Systems - From simple divs to complex grid systems and components
- Template Alternative - Replace static templates with dynamic PHP structures
- 360 Media Manager Types - Complete responsive image system
- 4 Image Series -
small,half,full,herofor every use case - Automatic WebP Conversion - 25-35% smaller files for better performance
- Bootstrap 5 Breakpoints - Perfect integration with modern grid systems
- Hero Series - Full-screen images up to 1920px for modern websites
- Direct HTML Rendering - No template engine required
- Performance Monitoring - Render times measurable
- Database Query Optimization - Request-local caching for Media Manager Types
- Memory Efficient - Low resource consumption
- Documented APIs - Well-documented interfaces with type hints
- Debug Mode - Detailed development information
- IDE Support - Complete type hints and documentation
- Extensible - Easy creation of custom components
- Go to System → Packages
- Search for "MFragment"
- Click Install
- Download the latest version from GitHub
- Extract to
redaxo/src/addons/mfragment/ - Install via REDAXO backend
Install the comprehensive responsive media system:
-- Import via REDAXO SQL Import
source install/responsive_complete_system.sqlThis adds 360 responsive Media Manager types with automatic WebP conversion.
<?php
use FriendsOfRedaxo\MFragment\Components\Bootstrap\Card;
use FriendsOfRedaxo\MFragment\Components\Default\Figure;
// Create a Bootstrap Card with responsive image
$card = Card::factory()
->setHeader('Welcome to MFragment')
->setBody('Build modern websites with component architecture.')
->setImage('hero-image.jpg', 'full_16x9')
->addClass('shadow-sm');
echo $card->show();<?php
use FriendsOfRedaxo\MFragment\Components\Default\Figure;
// Generate responsive picture element
$responsiveImage = Figure::factory()
->setMedia('hero-background.jpg')
->setMediaManagerType('hero_16x9') // Use Hero series for fullscreen
->enableAutoResponsive()
->addClass('hero-bg');
echo $responsiveImage->show();<?php
use FriendsOfRedaxo\MFragment\Components\Bootstrap\Carousel;
use FriendsOfRedaxo\MFragment\Components\Default\Figure;
$carousel = Carousel::factory('hero-carousel')
->addSlide(
Figure::factory()
->setMedia('slide1.jpg')
->setMediaManagerType('hero_21x9')
->setCaption('Modern Web Development')
->addClass('carousel-image')
)
->addSlide(
Figure::factory()
->setMedia('slide2.jpg')
->setMediaManagerType('hero_21x9')
->setCaption('Responsive Design')
)
->setControls(true)
->setIndicators(true)
->setAutoplay(5000);
echo $carousel->show();- Card - Content cards with images, headers and actions
- Carousel - Image and content sliders
- Modal - Overlay dialogs and lightboxes
- Accordion - Collapsible content sections
- Tabs - Tab navigation for content
- Alert - Notifications and messages
- Badge - Status indicators and labels
- Progress - Progress bars and loading indicators
- Collapse - Expandable content areas
- Figure - Images with captions and responsive behavior
- HTMLElement - Generic HTML elements with attribute management
- ListElement - Ordered and unordered lists
- Table - Data tables with responsive features
| Series | Breakpoints | Usage | Examples |
|---|---|---|---|
| small | 320-768px | Thumbnails, Icons | Avatars, small previews |
| half | 320-1400px | Content images | Article images, galleries |
| full | 320-1400px | Large content | Hero areas, main images |
| hero | 768-1920px | Fullscreen areas | Headers, landing pages |
- 1:1 - Square images (avatars, thumbnails)
- 4:3 - Standard photos (content images)
- 16:9 - Video format (hero areas, media)
- 21:9 - Cinema format (fullscreen headers)
- 3:2 - Photography standard
- 5:2 - Wide banners
// Hero header with video aspect ratio
rex_media_manager::getUrl('hero_16x9_max_1920', 'header-bg.jpg')
// Content image for articles
rex_media_manager::getUrl('half_4x3_768', 'article-image.jpg')
// Small thumbnail
rex_media_manager::getUrl('small_1x1_320', 'avatar.jpg')
// Fullscreen cinema format
rex_media_manager::getUrl('hero_21x9_max_1920', 'cinema-bg.jpg')MFragment allows you to create arbitrary HTML structures using the built-in tools. You can develop custom components that integrate seamlessly into the system and use all MFragment features.
<?php
namespace App\Components;
use FriendsOfRedaxo\MFragment\Components\AbstractComponent;
class MyComponent extends AbstractComponent
{
protected string $title = '';
protected string $content = '';
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
protected function renderHtml(): string
{
return '<div' . $this->buildAttributesString() . '>
<h2>' . htmlspecialchars($this->title) . '</h2>
<div class="content">' . $this->content . '</div>
</div>';
}
}<?php
namespace App\Components;
use FriendsOfRedaxo\MFragment\Components\AbstractComponent;
use FriendsOfRedaxo\MFragment\Components\Default\HTMLElement;
use FriendsOfRedaxo\MFragment\Components\Default\Figure;
class ProductCard extends AbstractComponent
{
private string $productName = '';
private string $price = '';
private string $imageUrl = '';
private array $features = [];
public function setProductName(string $name): self
{
$this->productName = $name;
return $this;
}
public function setPrice(string $price): self
{
$this->price = $price;
return $this;
}
public function setImage(string $imageUrl): self
{
$this->imageUrl = $imageUrl;
return $this;
}
public function addFeature(string $label, string $value): self
{
$this->features[] = ['label' => $label, 'value' => $value];
return $this;
}
protected function renderHtml(): string
{
// Use other MFragment components
$image = Figure::factory()
->setMedia($this->imageUrl)
->setMediaManagerType('half_4x3')
->enableLazyLoading()
->addClass('product-image');
$features = '';
foreach ($this->features as $feature) {
$features .= '<li><strong>' . htmlspecialchars($feature['label']) . ':</strong> ' . htmlspecialchars($feature['value']) . '</li>';
}
return '<div' . $this->buildAttributesString() . '>
' . $image->show() . '
<div class="product-info">
<h3>' . htmlspecialchars($this->productName) . '</h3>
<div class="price">' . htmlspecialchars($this->price) . '</div>
' . ($features ? '<ul class="features">' . $features . '</ul>' : '') . '
</div>
</div>';
}
}<?php
namespace App\Components;
use FriendsOfRedaxo\MFragment;
use FriendsOfRedaxo\MFragment\Components\AbstractComponent;
use FriendsOfRedaxo\MFragment\Components\Bootstrap\Card;
use FriendsOfRedaxo\MFragment\Components\Default\HTMLElement;
class Dashboard extends AbstractComponent
{
private array $cards = [];
public function addCard(string $title, string $content, string $icon = ''): self
{
$this->cards[] = [
'title' => $title,
'content' => $content,
'icon' => $icon
];
return $this;
}
protected function renderHtml(): string
{
$mfragment = MFragment::factory();
// Container for dashboard
$container = HTMLElement::factory('div')
->addClass('dashboard-grid');
// Add each card as Bootstrap Card
foreach ($this->cards as $card) {
$cardComponent = Card::factory()
->setHeader($card['title'])
->setBody($card['content'])
->addClass('dashboard-card');
if ($card['icon']) {
$cardComponent->prependContent('<i class="' . $card['icon'] . '"></i>');
}
$mfragment->addComponent($cardComponent);
}
$container->setContent($mfragment->show());
return '<div' . $this->buildAttributesString() . '>' .
$container->show() .
'</div>';
}
}// Simple usage
$myComponent = MyComponent::factory()
->setTitle('My Title')
->setContent('My Content')
->addClass('custom-style');
echo $myComponent->show();
// Advanced product card
$productCard = ProductCard::factory()
->setProductName('Gaming Laptop')
->setPrice('€ 1,299.00')
->setImage('laptop.jpg')
->addFeature('Processor', 'Intel Core i7')
->addFeature('RAM', '16 GB DDR4')
->addFeature('Graphics', 'NVIDIA RTX 3060')
->addClass('product-card shadow');
echo $productCard->show();
// Dashboard with multiple cards
$dashboard = Dashboard::factory()
->addCard('Users', '1,234 active users', 'fas fa-users')
->addCard('Revenue', '€ 45,678.90', 'fas fa-chart-line')
->addCard('Orders', '89 new orders', 'fas fa-shopping-cart')
->addClass('admin-dashboard');
echo $dashboard->show();Custom components can be used in all MFragment contexts:
$mfragment = MFragment::factory()
->addComponent($myComponent)
->addCard(Card::factory()->setHeader('Standard Card'))
->addComponent($productCard)
->addDiv('Additional content');
echo $mfragment->show();MFragment is for HTML what MForm is for forms - create HTML layouts programmatically:
// Create a complete article layout
$article = MFragment::factory()
->addDiv(
MFragment::factory()
->addHeading(1, 'Article Title', ['class' => 'display-4'])
->addParagraph('Published on ' . date('F j, Y'), ['class' => 'text-muted'])
->addClass('article-header'),
['class' => 'container mb-4']
)
->addDiv(
MFragment::factory()
->addDiv(
MFragment::factory()
->addParagraph('Article introduction...')
->addImage('/media/hero-image.jpg', 'Hero Image', ['class' => 'img-fluid rounded'])
->addParagraph('Main article content...'),
['class' => 'col-lg-8']
)
->addDiv(
MFragment::factory()
->addHeading(3, 'Related Articles')
->addList(['Article 1', 'Article 2', 'Article 3'], 'ul', ['class' => 'list-unstyled'])
->addButton('Subscribe', 'button', ['class' => 'btn btn-primary']),
['class' => 'col-lg-4']
),
['class' => 'container']
);
echo $article->show();// Create navigation from database data
$navigation = MFragment::factory()->addClass('navbar-nav');
foreach ($menuItems as $item) {
$link = MFragment::factory()
->addLink($item['title'], $item['url'], [
'class' => 'nav-link' . ($item['active'] ? ' active' : ''),
'aria-current' => $item['active'] ? 'page' : null
]);
$navigation->addDiv($link, ['class' => 'nav-item']);
}
echo $navigation->show();// Complex form structure with dynamic error handling
$form = MFragment::factory()
->addTagElement('form',
MFragment::factory()
->addDiv(
MFragment::factory()
->addTagElement('label', 'Email Address', ['for' => 'email', 'class' => 'form-label'])
->addTagElement('input', null, [
'type' => 'email',
'class' => 'form-control' . ($hasEmailError ? ' is-invalid' : ''),
'id' => 'email',
'name' => 'email'
])
->addDiv($emailError ?? '', ['class' => 'invalid-feedback']),
['class' => 'mb-3']
)
->addDiv(
MFragment::factory()
->addButton('Submit', 'submit', ['class' => 'btn btn-primary'])
->addButton('Cancel', 'button', ['class' => 'btn btn-secondary ms-2']),
['class' => 'd-flex justify-content-end']
),
['method' => 'post', 'action' => '/submit']
);
echo $form->show();// Generate structures based on data
$productGrid = MFragment::factory()->addClass('row g-4');
foreach ($products as $product) {
$card = MFragment::factory()
->addDiv(
MFragment::factory()
->addDiv(
MFragment::factory()
->addImage($product['image'], $product['title'], ['class' => 'card-img-top'])
->addDiv(
MFragment::factory()
->addHeading(5, $product['title'], ['class' => 'card-title'])
->addParagraph($product['description'], ['class' => 'card-text'])
->addDiv(
MFragment::factory()
->addSpan($product['price'], ['class' => 'h5 text-primary'])
->addButton('Add to Cart', 'button', [
'class' => 'btn btn-outline-primary btn-sm ms-2',
'data-product-id' => $product['id']
]),
['class' => 'd-flex justify-content-between align-items-center']
),
['class' => 'card-body']
),
['class' => 'card h-100']
),
['class' => 'col-md-6 col-lg-4']
);
$productGrid->addComponent($card);
}
echo $productGrid->show();All components inherit these methods:
All components inherit these methods:
// Attribute Management
->setAttribute(string $name, mixed $value)
->addClass(string $class)
->setId(string $id)
->setData(string $key, mixed $value)
// Content Management
->setContent(string $content)
->appendContent(string $content)
->prependContent(string $content)
// Rendering
->show(): string
->__toString(): string// Generate srcset for responsive images
generateSrcset(string $mediaFile, string $baseType): string
// Generate sizes attribute
generateSizesForType(string $baseType): string
// Generate complete picture element
generateResponsivePicture(string $mediaFile, array $options): stringMFragment offers several ways to organize custom components:
Directory: src/components/
Namespace: Free choice (e.g., App\Components\, MyProject\Components\)
src/components/
├── Cards/
│ ├── ProductCard.php -> App\Components\Cards\ProductCard
│ └── NewsCard.php -> MyProject\Components\Cards\NewsCard
├── Navigation/
│ ├── MainMenu.php -> App\Components\Navigation\MainMenu
│ └── Breadcrumb.php -> YourNamespace\Components\Navigation\Breadcrumb
└── Layout/
├── Hero.php -> App\Components\Layout\Hero
└── Footer.php -> CustomNamespace\Components\Layout\Footer
Directory: src/addons/theme/components/ or src/addons/theme/private/components/
Namespace: Free choice (e.g., Theme\Components\, MyTheme\Components\)
src/addons/theme/components/
├── Sections/
│ └── HeroSection.php -> Theme\Components\Sections\HeroSection
└── Widgets/
└── ContactWidget.php -> MyTheme\Components\Widgets\ContactWidget
Directory: src/addons/{addon_name}/components/
Namespace: Free choice according to your addon namespace
src/addons/myproject/components/
├── Custom/
│ └── SpecialComponent.php -> MyProject\Components\Custom\SpecialComponent
<?php
// File: src/components/Cards/ProductCard.php
namespace YourNamespace\Components\Cards;
use FriendsOfRedaxo\MFragment\Components\AbstractComponent;
class ProductCard extends AbstractComponent
{
private string $title = '';
private string $price = '';
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function setPrice(string $price): self
{
$this->price = $price;
return $this;
}
protected function renderHtml(): string
{
return '<div' . $this->buildAttributesString() . '>
<h3>' . htmlspecialchars($this->title) . '</h3>
<span class="price">' . htmlspecialchars($this->price) . '</span>
</div>';
}
}<?php
use YourNamespace\Components\Cards\ProductCard;
// Direct usage
$card = ProductCard::factory()
->setTitle('Gaming Laptop')
->setPrice('€ 1,299.00')
->addClass('product-card');
echo $card->show();
// In MFragment Container
$container = MFragment::factory()
->addComponent($card)
->addClass('product-grid');MFragment automatically loads components when properly placed:
// These directories are automatically scanned:
src/components/ -> Your chosen namespace
theme_addon_path/components/ -> Your theme namespace
theme_addon_path/private/components/ -> Your theme namespace
src/addons/mfragment/components/ -> FriendsOfRedaxo\MFragment\Components\*Important:
- The namespace is freely selectable
- Namespace structure must match directory structure
- Composer autoload or corresponding configuration required
Enable debug output for development:
// In development environment
\FriendsOfRedaxo\MFragment\Core\RenderEngine::enableDebug();
// Components output debug information
$card = Card::factory()->setHeader('Debug Card')->show();
// Output: <!-- MFragment Debug: Card rendered in 0.5ms -->// Enable performance monitoring in development
if (rex::isDebugMode()) {
\FriendsOfRedaxo\MFragment\Core\RenderEngine::enableDebug();
}
// Retrieve performance statistics
$stats = \FriendsOfRedaxo\MFragment\Core\RenderEngine::getStats();
echo "Render calls: " . $stats['renderCalls'];
echo "Total time: " . $stats['processingTime'] . "ms";// Retrieve detailed performance statistics
$engine = \FriendsOfRedaxo\MFragment\Core\RenderEngine::getInstance();
$stats = $engine->getDetailedStats();
foreach ($stats['components'] as $component => $data) {
echo "{$component}: {$data['count']} renders, {$data['time']}ms total\n";
}// Test responsive image generation
$srcset = generateSrcset('test.jpg', 'hero_16x9');
assertNotEmpty($srcset);
assertStringContains('hero_16x9_768', $srcset);- FOR Html - Extended HTML generation (automatically detected)
- Media Manager - For responsive image functionality
This project is licensed under the MIT License - see the LICENSE file for details.
- Documentation: https://github.com/FriendsOfREDAXO/mfragment/wiki
- Issues: https://github.com/FriendsOfREDAXO/mfragment/issues
- Community: REDAXO Slack
MFragment is developed and maintained by Friends Of REDAXO.