Views: 1
Welcome to Episode 5 of building the Versana Companion plugin! In Episode 4, we integrated our settings into the theme’s options page. Now it’s time to show users what demos are available for import. In this episode, you’ll learn how to create a WordPress plugin demo library – a simple list of available demos that users can browse and import. No database needed! We’ll define our demos directly in PHP and display them in a new “Demo Import” tab.
By the end of this tutorial, you’ll have a professional demo library showing three demos (Business, Blog, Portfolio) with descriptions, preview links, and import buttons.
What We’ll Cover
- Why we don’t need a database for static demos
- Defining demos in PHP arrays
- Adding a Demo Import tab
- Displaying demo information
- Creating import buttons
- Styling the demo grid
- Testing the demo library
Prerequisites
- Completed Episodes 2-4
- Versana theme and plugin active
- Text editor open
- Demo XML files created (from Episode 6)
Part 1: Why No Database?
Understanding Data Storage Needs
When to use database:
- ✅ User-generated content
- ✅ Frequently changing data
- ✅ Need to track statistics
- ✅ Lots of items (100+)
- ✅ Need to query/filter/search
When to use PHP arrays:
- ✅ Fixed, static data
- ✅ Developer-defined content
- ✅ Small number of items
- ✅ Doesn’t change often
- ✅ Simple structure
Our Demo Library
What we have:
- 3 fixed demos (Business, Blog, Portfolio)
- Defined by theme developer (you)
- Never changes unless you update plugin
- Simple structure (name, description, preview)
- No user interaction needed
Perfect for PHP array!
Benefits:
- ✅ No database queries (faster)
- ✅ No activation setup needed
- ✅ Easy to update (edit PHP)
- ✅ Version controlled (in code)
- ✅ Simple to understand
- ✅ No extra tables
Example:
// ❌ Database approach (unnecessary complexity)
CREATE TABLE demos...
INSERT INTO demos...
SELECT * FROM demos...
// ✅ Simple array (perfect for our needs)
$demos = array(
'business' => array(
'name' => 'Business',
'description' => 'Professional business site',
),
);
Part 2: Defining Our Demos
Step 1: Create Demo Definitions Function
Add this function to your plugin file:
/**
* Get available demos
*
* Returns array of available demo configurations
*
* @return array Demos array
*/
function versana_companion_get_available_demos() {
$demos = array(
'business' => array(
'name' => __( 'Business Website', 'versana-companion' ),
'description' => __( 'Professional business website with services and portfolio sections. Perfect for corporate sites, agencies, and consultancies.', 'versana-companion' ),
'preview_url' => 'https://demos.codoplex.com/versana/business/',
'thumbnail' => VERSANA_COMPANION_URL . 'assets/images/demos/business.jpg',
'xml_file' => VERSANA_COMPANION_PATH . 'demos/business/content.xml',
'category' => 'business',
'tags' => array( 'business', 'corporate', 'professional' ),
),
'blog' => array(
'name' => __( 'Personal Blog', 'versana-companion' ),
'description' => __( 'Clean and minimal blog layout perfect for writers and content creators. Focus on readability and content.', 'versana-companion' ),
'preview_url' => 'https://demos.codoplex.com/versana/blog/',
'thumbnail' => VERSANA_COMPANION_URL . 'assets/images/demos/blog.jpg',
'xml_file' => VERSANA_COMPANION_PATH . 'demos/blog/content.xml',
'category' => 'blog',
'tags' => array( 'blog', 'minimal', 'writer' ),
),
'portfolio' => array(
'name' => __( 'Creative Portfolio', 'versana-companion' ),
'description' => __( 'Showcase your work with a beautiful portfolio layout. Ideal for designers, photographers, and creative professionals.', 'versana-companion' ),
'preview_url' => 'https://demos.codoplex.com/versana/portfolio/',
'thumbnail' => VERSANA_COMPANION_URL . 'assets/images/demos/portfolio.jpg',
'xml_file' => VERSANA_COMPANION_PATH . 'demos/portfolio/content.xml',
'category' => 'portfolio',
'tags' => array( 'portfolio', 'creative', 'showcase' ),
),
);
/**
* Filter available demos
*
* Allows adding custom demos via child theme or plugin
*
* @param array $demos Array of demo configurations
*/
return apply_filters( 'versana_companion_available_demos', $demos );
}
Understanding the structure:
'business' => array( /* ... */ ),
- Key:
'business'(unique identifier) - Value: Array of demo information
- Key must match XML folder name
'name' => __( 'Business Website', 'versana-companion' ),
- Display name shown to users
__()= Translation function- Shows in demo grid
'description' => __( 'Professional business...', 'versana-companion' ),
- Short description (1-2 sentences)
- Explains what demo is for
- Helps users choose
'preview_url' => 'https://demos.codoplex.com/versana/business/',
- Link to live demo
- Users can preview before importing
- Opens in new tab
'thumbnail' => VERSANA_COMPANION_URL . 'assets/images/demos/business.jpg',
- Screenshot of demo
- Shows visual preview
- Using plugin URL constant
'xml_file' => VERSANA_COMPANION_PATH . 'demos/business/content.xml',
- Path to XML content file
- Using plugin path constant
- For import functionality
'category' => 'business',
- Demo category
- For future filtering
- Optional metadata
'tags' => array( 'business', 'corporate', 'professional' ),
- Demo tags/keywords
- For future search/filter
- Optional metadata
Part 3: Adding Demo Import Tab
Step 2: Add Demo Import Tab
Update your tab registration to add a Demo Import tab:
/**
* Add Companion tabs to theme options
*
* @param array $tabs Existing tabs
* @return array Modified tabs
*/
function versana_companion_add_settings_tabs( $tabs ) {
// Demo Import tab (priority 5 - very first)
$tabs['demo_import'] = array(
'title' => __( 'Demo Import', 'versana-companion' ),
'icon' => 'dashicons-download',
'callback' => 'versana_companion_render_demo_import_tab',
'priority' => 5,
);
// Companion settings tab (priority 10 - second)
$tabs['companion'] = array(
'title' => __( 'Companion', 'versana-companion' ),
'icon' => 'dashicons-admin-plugins',
'callback' => 'versana_companion_render_settings_tab',
'priority' => 10,
);
return $tabs;
}
add_filter( 'versana_option_tabs', 'versana_companion_add_settings_tabs' );
Why two tabs?
- Demo Import (priority 5) – Shows available demos, import buttons
- Companion (priority 10) – Plugin settings from Episode 4
Tab order:
[Demo Import] [Companion] [Header] [Footer] [Blog] [...]
↑ ↑
First Second
Part 4: Displaying the Demo Library
Step 3: Create Demo Library Display
Add this function to render the demo library:
/**
* Render Demo Import tab
*
* Displays available demos with import functionality
*/
function versana_companion_render_demo_import_tab() {
// Check if demo import is enabled
if ( ! versana_companion_get_setting( 'enable_demo_import', true ) ) {
?>
<div class="versana-tab-content">
<div class="notice notice-warning">
<p>
<?php esc_html_e( 'Demo import is currently disabled. Enable it in the Companion tab.', 'versana-companion' ); ?>
</p>
</div>
</div>
<?php
return;
}
// Get available demos
$demos = versana_companion_get_available_demos();
?>
<div class="versana-tab-content">
<h2><?php esc_html_e( 'Import Demo Content', 'versana-companion' ); ?></h2>
<p class="description">
<?php esc_html_e( 'Choose a demo to import. This will add sample posts, pages, and content to your site.', 'versana-companion' ); ?>
</p>
<div class="versana-demo-library">
<?php foreach ( $demos as $demo_key => $demo ) : ?>
<div class="versana-demo-item">
<!-- Demo Thumbnail -->
<div class="demo-thumbnail">
<?php if ( ! empty( $demo['thumbnail'] ) && file_exists( str_replace( VERSANA_COMPANION_URL, VERSANA_COMPANION_PATH, $demo['thumbnail'] ) ) ) : ?>
<img src="<?php echo esc_url( $demo['thumbnail'] ); ?>"
alt="<?php echo esc_attr( $demo['name'] ); ?>">
<?php else : ?>
<div class="demo-thumbnail-placeholder">
<span class="dashicons dashicons-admin-appearance"></span>
</div>
<?php endif; ?>
</div>
<!-- Demo Info -->
<div class="demo-info">
<h3 class="demo-name"><?php echo esc_html( $demo['name'] ); ?></h3>
<p class="demo-description"><?php echo esc_html( $demo['description'] ); ?></p>
</div>
<!-- Demo Actions -->
<div class="demo-actions">
<?php if ( ! empty( $demo['preview_url'] ) ) : ?>
<a href="<?php echo esc_url( $demo['preview_url'] ); ?>"
class="button"
target="_blank"
rel="noopener noreferrer">
<span class="dashicons dashicons-visibility"></span>
<?php esc_html_e( 'Preview', 'versana-companion' ); ?>
</a>
<?php endif; ?>
<?php if ( file_exists( $demo['xml_file'] ) ) : ?>
<button type="button"
class="button button-primary versana-import-demo"
data-demo="<?php echo esc_attr( $demo_key ); ?>">
<span class="dashicons dashicons-download"></span>
<?php esc_html_e( 'Import', 'versana-companion' ); ?>
</button>
<?php else : ?>
<button type="button" class="button" disabled>
<?php esc_html_e( 'File Missing', 'versana-companion' ); ?>
</button>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php if ( empty( $demos ) ) : ?>
<div class="notice notice-info">
<p><?php esc_html_e( 'No demos available at this time.', 'versana-companion' ); ?></p>
</div>
<?php endif; ?>
</div>
<?php
}
Understanding the display:
if ( ! versana_companion_get_setting( 'enable_demo_import', true ) ) {
- Check if demo import is enabled (from Episode 4 settings)
- If disabled, show message
- Respects user’s settings
$demos = versana_companion_get_available_demos();
- Get demo definitions
- Returns array we created earlier
foreach ( $demos as $demo_key => $demo ) :
- Loop through each demo
$demo_key= ‘business’, ‘blog’, or ‘portfolio’$demo= Array of demo info
<div class="versana-demo-item">
- Container for one demo
- We’ll style this with CSS
<?php if ( ! empty( $demo['thumbnail'] ) && file_exists( ... ) ) : ?>
- Check if thumbnail exists
file_exists()verifies file is actually there- Shows placeholder if missing
<img src="<?php echo esc_url( $demo['thumbnail'] ); ?>"
- Display thumbnail image
esc_url()= Security (escape URL)
data-demo="<?php echo esc_attr( $demo_key ); ?>"
- Store demo key in data attribute
- Used by JavaScript for import
- We’ll add JavaScript in Episode 7
<?php if ( file_exists( $demo['xml_file'] ) ) : ?>
- Check if XML file actually exists
- Only show Import button if file is there
- Shows “File Missing” if not found
Part 5: Adding Basic Styling
Step 4: Create Demo Library CSS
Create file: versana-companion/assets/css/demo-library.css
/**
* Demo Library Styles
*/
.versana-demo-library {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 30px;
margin-top: 30px;
}
.versana-demo-item {
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
}
.versana-demo-item:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.demo-thumbnail {
position: relative;
width: 100%;
padding-bottom: 66.67%; /* 3:2 aspect ratio */
overflow: hidden;
background: #f5f5f5;
}
.demo-thumbnail img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.demo-thumbnail-placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
}
.demo-thumbnail-placeholder .dashicons {
font-size: 60px;
width: 60px;
height: 60px;
color: #ccc;
}
.demo-info {
padding: 20px;
}
.demo-name {
margin: 0 0 10px;
font-size: 18px;
font-weight: 600;
}
.demo-description {
margin: 0;
color: #666;
font-size: 14px;
line-height: 1.6;
}
.demo-actions {
padding: 0 20px 20px;
display: flex;
gap: 10px;
}
.demo-actions .button {
flex: 1;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
}
.demo-actions .button .dashicons {
font-size: 16px;
width: 16px;
height: 16px;
}
/* Responsive */
@media screen and (max-width: 782px) {
.versana-demo-library {
grid-template-columns: 1fr;
}
}
Step 5: Enqueue CSS
Add this function to load the CSS:
/**
* Enqueue demo library assets
*
* @param string $hook Current admin page
*/
function versana_companion_enqueue_demo_library_assets( $hook ) {
// Only on theme options page
if ( 'appearance_page_versana-options' !== $hook ) {
return;
}
// Only if on demo import tab
$active_tab = isset( $_GET['tab'] ) ? sanitize_text_field( $_GET['tab'] ) : '';
if ( 'demo_import' !== $active_tab ) {
return;
}
// Enqueue CSS
wp_enqueue_style(
'versana-companion-demo-library',
VERSANA_COMPANION_URL . 'assets/css/demo-library.css',
array(),
VERSANA_COMPANION_VERSION
);
}
add_action( 'admin_enqueue_scripts', 'versana_companion_enqueue_demo_library_assets' );
Understanding enqueue:
if ( 'appearance_page_versana-options' !== $hook ) {
- Only load on theme options page
$hook= Current page identifier- Saves resources (doesn’t load everywhere)
$active_tab = isset( $_GET['tab'] ) ? sanitize_text_field( $_GET['tab'] ) : '';
- Get active tab from URL
sanitize_text_field()= Security- Only load CSS on Demo Import tab
wp_enqueue_style(
'versana-companion-demo-library', // Handle (unique ID)
VERSANA_COMPANION_URL . 'assets/css/demo-library.css', // File URL
array(), // Dependencies (none)
VERSANA_COMPANION_VERSION // Version (for cache busting)
);
- Register and load CSS file
- Version number updates when plugin updates
- Breaks browser cache automatically
Part 6: Creating Placeholder Images
Step 6: Add Demo Thumbnails
You need thumbnail images for each demo. Create these files:
versana-companion/
└── assets/
└── images/
└── demos/
├── business.jpg (1200x800 recommended)
├── blog.jpg (1200x800 recommended)
└── portfolio.jpg (1200x800 recommended)
If you don’t have images yet:
The code already handles missing images! It will show a placeholder icon instead.
To test without images:
- Create the folders
- Leave them empty for now
- Placeholders will show automatically
When you’re ready:
- Take screenshots of each demo
- Resize to 1200×800 pixels
- Save as JPG (optimize for web)
- Upload to folders
Part 7: Testing the Demo Library
Test Your Demo Library
1. Go to theme options:
WordPress Admin → Appearance → Theme Options
2. Look for Demo Import tab:
Should see tabs:
[Demo Import] [Companion] [Header] [Footer] [Blog] [...]
↑
NEW TAB! (first position)
3. Click Demo Import tab:
Should show:
- Grid layout (3 demos)
- Thumbnails or placeholders
- Demo names and descriptions
- Preview and Import buttons
4. Verify each demo shows:
✓ Business Website
- Description visible
- Preview button links to demo URL
- Import button enabled (if XML exists)
✓ Personal Blog
- Description visible
- Buttons present
✓ Creative Portfolio
- Description visible
- Buttons present
5. Test if settings work:
a) Go to Companion tab
b) Uncheck "Enable Demo Import"
c) Save Settings
d) Go back to Demo Import tab
e) Should show: "Demo import is currently disabled"
f) Re-enable and test again
6. Test preview links:
Click "Preview" button
- Should open in new tab
- Should go to demo URL
- User can see live demo
7. Check responsive:
Resize browser window
- Should show 1 column on mobile
- Grid should adapt nicely
Part 8: Getting Single Demo Info
Step 7: Helper Function for Single Demo
Add helper to get specific demo:
/**
* Get single demo information
*
* @param string $demo_key Demo identifier
* @return array|null Demo data or null if not found
*/
function versana_companion_get_demo( $demo_key ) {
$demos = versana_companion_get_available_demos();
return isset( $demos[ $demo_key ] ) ? $demos[ $demo_key ] : null;
}
Usage:
// Get business demo
$demo = versana_companion_get_demo( 'business' );
if ( $demo ) {
echo 'Name: ' . $demo['name'];
echo 'File: ' . $demo['xml_file'];
// Check if file exists
if ( file_exists( $demo['xml_file'] ) ) {
echo 'Ready to import!';
}
}
When you’ll use this:
- Episode 7: Import functionality
- Episode 8: Demo details page
- Anywhere you need single demo info
Part 9: Complete Demo Library Code
All Functions Together
Here’s everything for the demo library:
/**
* ========================================
* DEMO LIBRARY FUNCTIONS
* ========================================
*/
/**
* Get available demos
*/
function versana_companion_get_available_demos() {
$demos = array(
'business' => array(
'name' => __( 'Business Website', 'versana-companion' ),
'description' => __( 'Professional business website with services and portfolio sections. Perfect for corporate sites.', 'versana-companion' ),
'preview_url' => 'https://demos.codoplex.com/versana/business/',
'thumbnail' => VERSANA_COMPANION_URL . 'assets/images/demos/business.jpg',
'xml_file' => VERSANA_COMPANION_PATH . 'demos/business/content.xml',
'category' => 'business',
'tags' => array( 'business', 'corporate' ),
),
'blog' => array(
'name' => __( 'Personal Blog', 'versana-companion' ),
'description' => __( 'Clean and minimal blog layout perfect for writers and content creators.', 'versana-companion' ),
'preview_url' => 'https://demos.codoplex.com/versana/blog/',
'thumbnail' => VERSANA_COMPANION_URL . 'assets/images/demos/blog.jpg',
'xml_file' => VERSANA_COMPANION_PATH . 'demos/blog/content.xml',
'category' => 'blog',
'tags' => array( 'blog', 'minimal' ),
),
'portfolio' => array(
'name' => __( 'Creative Portfolio', 'versana-companion' ),
'description' => __( 'Showcase your work with a beautiful portfolio layout.', 'versana-companion' ),
'preview_url' => 'https://demos.codoplex.com/versana/portfolio/',
'thumbnail' => VERSANA_COMPANION_URL . 'assets/images/demos/portfolio.jpg',
'xml_file' => VERSANA_COMPANION_PATH . 'demos/portfolio/content.xml',
'category' => 'portfolio',
'tags' => array( 'portfolio', 'creative' ),
),
);
return apply_filters( 'versana_companion_available_demos', $demos );
}
/**
* Get single demo
*/
function versana_companion_get_demo( $demo_key ) {
$demos = versana_companion_get_available_demos();
return isset( $demos[ $demo_key ] ) ? $demos[ $demo_key ] : null;
}
/**
* Add demo tabs
*/
function versana_companion_add_settings_tabs( $tabs ) {
$tabs['demo_import'] = array(
'title' => __( 'Demo Import', 'versana-companion' ),
'icon' => 'dashicons-download',
'callback' => 'versana_companion_render_demo_import_tab',
'priority' => 5,
);
$tabs['companion'] = array(
'title' => __( 'Companion', 'versana-companion' ),
'icon' => 'dashicons-admin-plugins',
'callback' => 'versana_companion_render_settings_tab',
'priority' => 10,
);
return $tabs;
}
add_filter( 'versana_option_tabs', 'versana_companion_add_settings_tabs' );
/**
* Render demo import tab
*/
function versana_companion_render_demo_import_tab() {
if ( ! versana_companion_get_setting( 'enable_demo_import', true ) ) {
?>
<div class="versana-tab-content">
<div class="notice notice-warning">
<p><?php esc_html_e( 'Demo import is disabled. Enable in Companion tab.', 'versana-companion' ); ?></p>
</div>
</div>
<?php
return;
}
$demos = versana_companion_get_available_demos();
?>
<div class="versana-tab-content">
<h2><?php esc_html_e( 'Import Demo Content', 'versana-companion' ); ?></h2>
<p class="description">
<?php esc_html_e( 'Choose a demo to import. This will add sample posts and pages.', 'versana-companion' ); ?>
</p>
<div class="versana-demo-library">
<?php foreach ( $demos as $demo_key => $demo ) : ?>
<div class="versana-demo-item">
<div class="demo-thumbnail">
<?php if ( ! empty( $demo['thumbnail'] ) && file_exists( str_replace( VERSANA_COMPANION_URL, VERSANA_COMPANION_PATH, $demo['thumbnail'] ) ) ) : ?>
<img src="<?php echo esc_url( $demo['thumbnail'] ); ?>" alt="<?php echo esc_attr( $demo['name'] ); ?>">
<?php else : ?>
<div class="demo-thumbnail-placeholder">
<span class="dashicons dashicons-admin-appearance"></span>
</div>
<?php endif; ?>
</div>
<div class="demo-info">
<h3 class="demo-name"><?php echo esc_html( $demo['name'] ); ?></h3>
<p class="demo-description"><?php echo esc_html( $demo['description'] ); ?></p>
</div>
<div class="demo-actions">
<?php if ( ! empty( $demo['preview_url'] ) ) : ?>
<a href="<?php echo esc_url( $demo['preview_url'] ); ?>" class="button" target="_blank">
<span class="dashicons dashicons-visibility"></span>
<?php esc_html_e( 'Preview', 'versana-companion' ); ?>
</a>
<?php endif; ?>
<?php if ( file_exists( $demo['xml_file'] ) ) : ?>
<button type="button" class="button button-primary versana-import-demo" data-demo="<?php echo esc_attr( $demo_key ); ?>">
<span class="dashicons dashicons-download"></span>
<?php esc_html_e( 'Import', 'versana-companion' ); ?>
</button>
<?php else : ?>
<button type="button" class="button" disabled>
<?php esc_html_e( 'File Missing', 'versana-companion' ); ?>
</button>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php
}
/**
* Enqueue assets
*/
function versana_companion_enqueue_demo_library_assets( $hook ) {
if ( 'appearance_page_versana-options' !== $hook ) {
return;
}
$active_tab = isset( $_GET['tab'] ) ? sanitize_text_field( $_GET['tab'] ) : '';
if ( 'demo_import' !== $active_tab ) {
return;
}
wp_enqueue_style(
'versana-companion-demo-library',
VERSANA_COMPANION_URL . 'assets/css/demo-library.css',
array(),
VERSANA_COMPANION_VERSION
);
}
add_action( 'admin_enqueue_scripts', 'versana_companion_enqueue_demo_library_assets' );
Conclusion
Congratulations! You’ve created a beautiful WordPress plugin demo library that displays available demos without needing a database. Simple, clean, and efficient!
What We Accomplished
✅ Understanding when NOT to use databases ✅ Defining demos in PHP arrays ✅ Adding Demo Import tab (priority 5) ✅ Displaying demos in grid layout ✅ Creating demo cards with thumbnails ✅ Adding preview and import buttons ✅ Styling with CSS ✅ Handling missing files gracefully ✅ Creating helper functions ✅ Testing the complete library
What We Learned
Technical Skills:
- PHP arrays for static data
- Grid layout with CSS
- WordPress filters for tabs
- Conditional asset loading
- File existence checking
- Extensibility with filters
- Helper function patterns
Best Practices:
- Use arrays for static data
- Check file existence before displaying
- Provide fallbacks (placeholders)
- Only load CSS where needed
- Make data filterable
- Create helper functions
- Handle edge cases
Key Takeaways
For WordPress plugin demo library:
- Arrays > Database – For static, fixed data
- Check Files – Always verify before showing
- Provide Fallbacks – Placeholders for missing images
- Grid Layout – Professional demo display
- Load Conditionally – CSS only where needed
- Make Extensible – Filters for customization
- Simple is Better – Don’t over-engineer
Your Plugin Progress
✓ Episode 2: Basic plugin
✓ Episode 3: Theme check
✓ Episode 4: Settings integration
✓ Episode 5: Demo library ← YOU ARE HERE
→ Episode 6: File operations (XML reading)
→ Episode 7: Demo import (actual import)
Frequently Asked Questions
Q: Why not use a database table? A: Demos are fixed, developer-defined content. Arrays are simpler, faster, and easier to maintain for static data.
Q: Can I add more demos later? A: Yes! Just add more items to the array in versana_companion_get_available_demos().
Q: What if I want to track downloads? A: You could add a simple counter in wp_options. No need for full table.
Q: Can child themes add demos? A: Yes! Use the versana_companion_available_demos filter to add custom demos.
Q: What thumbnail size should I use? A: 1200×800 pixels works well. CSS will resize automatically.
Q: Can I change the grid columns? A: Yes! Edit the CSS grid-template-columns property.
Q: What if XML file is missing? A: Button shows “File Missing” and is disabled. Code checks with file_exists().
Q: Can I add categories/tags? A: They’re in the array! We’ll use them for filtering in future episodes.
Next Episode Preview
Episode 6: File Operations
Now that we display demos, we’ll learn to read the XML files and prepare them for import!
Congratulations on completing Episode 5! You’ve built a professional demo library using simple arrays!
Series: Building Versana Companion Plugin
Episode: 5 of ongoing series (Demo Library Complete)


Leave a Reply