Skip to content

Commit d8f191a

Browse files
authored
Merge pull request #22 from fairpm/refactor/views
Reduce view layer duplication with shared templates and base mode
2 parents 1da724e + 6643977 commit d8f191a

37 files changed

+777
-1159
lines changed

README.md

Lines changed: 77 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# Fair-Explorer
22

3-
A WordPress plugin that provides a comprehensive repository browser for exploring and managing WordPress plugins and themes from the FAIR ecosystem.
3+
A WordPress plugin that provides a comprehensive repository browser for exploring and managing WordPress plugins, themes, and TYPO3 extensions from the FAIR ecosystem.
44

55
## Features
66

7-
- 🔍 **Package Search & Browse** - Search and explore WordPress plugins and themes with detailed information
7+
- 🔍 **Package Search & Browse** - Search and explore WordPress plugins, themes, and TYPO3 extensions with detailed information
88
- 🎨 **Theme Discovery** - Browse and preview WordPress themes with live demos
9-
-**Plugin Management** - Discover and explore WordPress plugins
10-
- �🛒 **Cart Functionality** - Add packages to cart with persistent storage via cookies
9+
- 🔌 **Plugin Management** - Discover and explore WordPress plugins
10+
- 🧩 **TYPO3 Extensions** - Browse and search TYPO3 extensions from the extensions API
11+
- 🛒 **Cart Functionality** - Add packages to cart with persistent storage via cookies
1112
- 🎮 **WordPress Playground Integration** - Generate blueprint URLs for instant WordPress demos
1213
-**Interactive UI** - Modern lightbox galleries, floating cart button, and smooth animations
1314
- 📱 **Responsive Design** - Mobile-friendly interface with SCSS-powered styling
@@ -20,7 +21,7 @@ A WordPress plugin that provides a comprehensive repository browser for explorin
2021
1. Download or clone this repository
2122
2. Place the `fair-explorer` folder in your `/wp-content/plugins/` directory
2223
3. Activate the plugin through the 'Plugins' menu in WordPress
23-
4. Create pages with slugs `plugins` and `themes` for the archive pages
24+
4. Create pages with slugs `plugins`, `themes`, and optionally set up TYPO3 extension routes for the archive pages
2425

2526
## Template Hierarchy & Customization
2627

@@ -30,41 +31,42 @@ Fair-Explorer supports WordPress template hierarchy, allowing themes to override
3031

3132
1. **Child Theme** (highest priority): `wp-content/themes/child-theme/fair-explorer/[template-file]`
3233
2. **Parent Theme**: `wp-content/themes/active-theme/fair-explorer/[template-file]`
33-
3. **Plugin Default** (fallback): `wp-content/plugins/fair-explorer/includes/view/[template-file]`
34+
3. **Plugin Default** (fallback): `wp-content/plugins/fair-explorer/includes/views/[template-file]`
3435

3536
### Available Templates
3637

3738
You can override these template files in your theme:
3839

39-
**Search Forms:**
40-
- `themes-search-form.php` - Theme search form
41-
- `plugins-search-form.php` - Plugin search form
40+
**Plugins:**
41+
- `plugins/plugins-search-form.php` - Plugin search form
42+
- `plugins/archive/plugins.php` - Plugins listing page
43+
- `plugins/archive/plugin.php` - Individual plugin card in the archive
44+
- `plugins/single/plugin.php` - Individual plugin display
4245

43-
**Archive Templates:**
44-
- `archive/themes.php` - Themes listing page
45-
- `archive/plugins.php` - Plugins listing page
46+
**Themes:**
47+
- `themes/themes-search-form.php` - Theme search form
48+
- `themes/archive/themes.php` - Themes listing page
49+
- `themes/archive/theme.php` - Individual theme card in the archive
50+
- `themes/single/theme.php` - Individual theme display
4651

47-
**Single Templates:**
48-
- `single/theme.php` - Individual theme display
49-
- `single/plugin.php` - Individual plugin display
52+
**TYPO3 Extensions:**
53+
- `extensions/extensions-search-form.php` - Extension search form
54+
- `extensions/archive/extensions.php` - Extensions listing page
55+
- `extensions/archive/extension.php` - Individual extension card in the archive
56+
- `extensions/single/extension.php` - Individual extension display
5057

5158
### Example Theme Override
5259

5360
To customize the themes listing in your theme:
5461

55-
1. Create folder: `wp-content/themes/your-theme/fair-explorer/`
56-
2. Copy: `wp-content/plugins/fair-explorer/includes/view/archive/themes.php`
57-
3. Paste to: `wp-content/themes/your-theme/fair-explorer/archive/themes.php`
62+
1. Create folder: `wp-content/themes/your-theme/fair-explorer/themes/archive/`
63+
2. Copy: `wp-content/plugins/fair-explorer/includes/views/themes/archive/themes.php`
64+
3. Paste to: `wp-content/themes/your-theme/fair-explorer/themes/archive/themes.php`
5865
4. Customize as needed
5966

60-
Your customizations will be preserved during plugin updates.
61-
62-
## Installation
67+
Each overridable template receives an `$args` array with all the data it needs. The type-specific templates (e.g. `plugins/archive/plugins.php`) delegate to shared partials internally, but when you override a template, you have full control and can write completely custom markup.
6368

64-
1. Download or clone this repository
65-
2. Place the `fair-explorer` folder in your `/wp-content/plugins/` directory
66-
3. Activate the plugin through the 'Plugins' menu in WordPress
67-
4. Create pages with slugs `plugins` and `themes` for the archive pages
69+
Your customizations will be preserved during plugin updates.
6870

6971
## Configuration
7072

@@ -83,6 +85,8 @@ Create WordPress pages with these exact slugs:
8385
- **plugins** - For the plugins archive and individual plugin pages
8486
- **themes** - For the themes archive and individual theme pages
8587

88+
TYPO3 extensions use the hardcoded root `packages/typo3`, so the archive is served at `packages/typo3/extensions/`. Ensure a WordPress page exists at that path for the content to render on.
89+
8690

8791
## URL Structure
8892

@@ -96,6 +100,10 @@ With the default configuration, your URLs will be:
96100
- Archive: `yoursite.com/packages/themes/`
97101
- Individual: `yoursite.com/packages/themes/theme-name/`
98102

103+
**TYPO3 Extensions:**
104+
- Archive: `yoursite.com/packages/typo3/extensions/`
105+
- Individual: `yoursite.com/packages/typo3/extensions/extension-name/`
106+
99107
**REST API:**
100108
- Playground Blueprint: `yoursite.com/wp-json/fair-explorer/v1/playground/blueprint`
101109

@@ -176,36 +184,56 @@ Returns a JSON blueprint compatible with WordPress Playground:
176184
```
177185
fair-explorer/
178186
├── includes/
179-
│ ├── controller/ # MVC Controllers
180-
│ │ ├── class-main.php # Main plugin controller
181-
│ │ ├── class-packages.php # Unified packages controller (themes & plugins)
182-
│ │ └── class-playground.php # WordPress Playground API
183-
│ ├── model/ # Data Models
184-
│ │ ├── class-singleton.php # Base singleton pattern
185-
│ │ ├── class-plugin-info.php # Plugin data model
186-
│ │ └── class-theme-info.php # Theme data model
187-
│ ├── view/ # Template Files (Plugin Defaults)
188-
│ │ ├── archive/ # Archive page templates
189-
│ │ │ ├── plugins.php
190-
│ │ │ └── themes.php
191-
│ │ ├── single/ # Single item templates
192-
│ │ │ ├── plugin.php
193-
│ │ │ └── theme.php
194-
│ │ ├── plugins-search-form.php
195-
│ │ └── themes-search-form.php
196-
│ ├── class-utilities.php # Template hierarchy helper
197-
│ └── autoload.php # PSR-4 autoloader
187+
│ ├── controller/ # MVC Controllers
188+
│ │ ├── class-main.php # Main plugin controller
189+
│ │ ├── class-packages.php # Unified packages controller (plugins, themes & extensions)
190+
│ │ ├── class-typo3.php # TYPO3 extensions API fetcher
191+
│ │ └── class-playground.php # WordPress Playground API
192+
│ ├── model/ # Data Models
193+
│ │ ├── class-singleton.php # Base singleton pattern
194+
│ │ ├── class-assetinfo.php # Base asset model (shared properties & methods)
195+
│ │ ├── class-plugininfo.php # Plugin data model
196+
│ │ ├── class-themeinfo.php # Theme data model
197+
│ │ └── class-extensioninfo.php # TYPO3 extension data model
198+
│ ├── views/ # Template Files (Plugin Defaults)
199+
│ │ ├── plugins/ # Plugin templates (overridable)
200+
│ │ │ ├── archive/
201+
│ │ │ │ ├── plugins.php
202+
│ │ │ │ └── plugin.php
203+
│ │ │ ├── single/
204+
│ │ │ │ └── plugin.php
205+
│ │ │ └── plugins-search-form.php
206+
│ │ ├── themes/ # Theme templates (overridable)
207+
│ │ │ ├── archive/
208+
│ │ │ │ ├── themes.php
209+
│ │ │ │ └── theme.php
210+
│ │ │ ├── single/
211+
│ │ │ │ └── theme.php
212+
│ │ │ └── themes-search-form.php
213+
│ │ ├── extensions/ # TYPO3 extension templates (overridable)
214+
│ │ │ ├── archive/
215+
│ │ │ │ ├── extensions.php
216+
│ │ │ │ └── extension.php
217+
│ │ │ ├── single/
218+
│ │ │ │ └── extension.php
219+
│ │ │ └── extensions-search-form.php
220+
│ │ └── shared/ # Shared partials (internal, not overridable)
221+
│ │ ├── archive-list.php # Generic archive listing
222+
│ │ ├── archive-card.php # Generic archive card
223+
│ │ ├── search-form.php # Generic search form
224+
│ │ └── single.php # Generic single view
225+
│ └── autoload.php # PSR-4 autoloader
198226
├── assets/
199227
│ ├── js/
200-
│ │ └── fair-explorer.js # Main JavaScript (ES6 classes)
228+
│ │ └── fair-explorer.js # Main JavaScript (ES6 classes)
201229
│ ├── scss/
202-
│ │ ├── fair-explorer.scss # Main SCSS file
230+
│ │ ├── fair-explorer.scss # Main SCSS file
203231
│ │ ├── _cart.scss # Cart styling
204232
│ │ ├── _lightbox.scss # Lightbox component
205233
│ │ └── _search.scss # Search components
206234
│ └── css/
207-
│ └── fair-explorer.css # Compiled CSS
208-
└── composer.json # PHP dependencies and scripts
235+
│ └── fair-explorer.css # Compiled CSS
236+
└── composer.json # PHP dependencies and scripts
209237
```
210238

211239

@@ -284,7 +312,7 @@ The cart system allows users to collect packages for later reference:
284312
### Rewrite Rules Not Working
285313

286314
1. Go to **Settings > Permalinks** and click "Save Changes"
287-
2. Ensure your pages have the correct slugs (`plugins`, `themes`)
315+
2. Ensure your pages have the correct slugs (`plugins`, `themes`, etc.)
288316
3. Check that `AE_ROOT` constant matches your URL structure
289317
4. Verify `Packages` class instances are properly initialized
290318

includes/controller/class-main.php

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
namespace FairExplorer\Controller;
99

10+
use FairExplorer\Controller\Typo3\Typo3;
11+
use FairExplorer\Controller\WordPress\Playground;
12+
1013
class Main extends \FairExplorer\Model\Singleton {
1114
/**
1215
* Constructor.
@@ -33,23 +36,38 @@ public static function get_platforms() {
3336

3437
$platforms = [
3538
[
36-
'asset_type' => 'plugins',
37-
'root' => $root,
38-
'model_class' => 'FairExplorer\Model\PluginInfo',
39-
'fetcher' => null,
39+
'asset_type' => 'plugins',
40+
'root' => $root,
41+
'view_prefix' => 'wordpress',
42+
'model_class' => 'FairExplorer\Model\PluginInfo',
43+
'fetcher' => null,
44+
'css_prefix' => 'plugin',
45+
'label' => 'Plugin',
46+
'label_plural' => 'Plugins',
47+
'search_label' => 'Search WordPress Plugins',
4048
],
4149
[
42-
'asset_type' => 'themes',
43-
'root' => $root,
44-
'model_class' => 'FairExplorer\Model\ThemeInfo',
45-
'fetcher' => null,
50+
'asset_type' => 'themes',
51+
'root' => $root,
52+
'view_prefix' => 'wordpress',
53+
'model_class' => 'FairExplorer\Model\ThemeInfo',
54+
'fetcher' => null,
55+
'css_prefix' => 'theme',
56+
'label' => 'Theme',
57+
'label_plural' => 'Themes',
58+
'search_label' => 'Search WordPress Themes',
4659
],
4760
[
48-
'asset_type' => 'extensions',
49-
'root' => 'packages/typo3',
50-
'slug_var' => 'extension_slug',
51-
'model_class' => 'FairExplorer\Model\ExtensionInfo',
52-
'fetcher' => [ Typo3::class, 'fetch' ],
61+
'asset_type' => 'extensions',
62+
'root' => 'packages/typo3',
63+
'view_prefix' => 'typo3',
64+
'slug_var' => 'extension_slug',
65+
'model_class' => 'FairExplorer\Model\ExtensionInfo',
66+
'fetcher' => [ Typo3::class, 'fetch' ],
67+
'css_prefix' => 'typo3-extension',
68+
'label' => 'Extension',
69+
'label_plural' => 'Extensions',
70+
'search_label' => 'Search TYPO3 Extensions',
5371
],
5472
];
5573

includes/controller/class-packages.php

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,31 @@ class Packages {
5050
*/
5151
protected $fetcher;
5252

53+
/**
54+
* CSS class prefix for this asset type (e.g. 'plugin', 'theme', 'typo3-extension').
55+
*/
56+
protected $css_prefix;
57+
58+
/**
59+
* Singular display label (e.g. 'Plugin', 'Theme', 'Extension').
60+
*/
61+
protected $label;
62+
63+
/**
64+
* Plural display label (e.g. 'Plugins', 'Themes', 'Extensions').
65+
*/
66+
protected $label_plural;
67+
68+
/**
69+
* Search input placeholder / label text.
70+
*/
71+
protected $search_label;
72+
73+
/**
74+
* View directory prefix (e.g. 'wordpress', 'typo3').
75+
*/
76+
protected $view_prefix;
77+
5378
/**
5479
* Constructor.
5580
*
@@ -64,6 +89,11 @@ public function __construct( $config = 'plugins' ) {
6489
$this->asset_singular = rtrim( $this->asset_type, 's' );
6590
$this->model_class = $config['model_class'];
6691
$this->fetcher = $config['fetcher'] ?? null;
92+
$this->css_prefix = $config['css_prefix'] ?? $this->asset_singular;
93+
$this->label = $config['label'] ?? ucfirst( $this->asset_singular );
94+
$this->label_plural = $config['label_plural'] ?? ucfirst( $this->asset_type );
95+
$this->search_label = $config['search_label'] ?? 'Search ' . ucfirst( $this->asset_type );
96+
$this->view_prefix = $config['view_prefix'] ?? '';
6797

6898
$root = $config['root'] ?? '';
6999
if ( '' !== $root ) {
@@ -106,10 +136,11 @@ protected static function legacy_config( $asset_type ) {
106136
];
107137

108138
return [
109-
'asset_type' => $asset_type,
110-
'root' => $root,
111-
'model_class' => $model_map[ $asset_type ] ?? 'FairExplorer\Model\PluginInfo',
112-
'fetcher' => null,
139+
'asset_type' => $asset_type,
140+
'root' => $root,
141+
'view_prefix' => 'wordpress',
142+
'model_class' => $model_map[ $asset_type ] ?? 'FairExplorer\Model\PluginInfo',
143+
'fetcher' => null,
113144
];
114145
}
115146

@@ -389,11 +420,16 @@ public function the_content( $content ) {
389420
protected function archive_the_content( $search_keyword ) {
390421
ob_start();
391422

423+
$view_base = $this->view_prefix . DIRECTORY_SEPARATOR . $this->asset_type;
424+
392425
Utilities::include_file(
393-
$this->asset_type . DIRECTORY_SEPARATOR . $this->asset_type . '-search-form.php',
426+
$view_base . DIRECTORY_SEPARATOR . $this->asset_type . '-search-form.php',
394427
[
395428
'target_page_slug' => $this->target_page_slug,
396429
'search_keyword' => $search_keyword,
430+
'css_prefix' => $this->css_prefix,
431+
'search_label' => $this->search_label,
432+
'label' => $this->label,
397433
]
398434
);
399435

@@ -409,13 +445,21 @@ protected function archive_the_content( $search_keyword ) {
409445
}
410446

411447
Utilities::include_file(
412-
$this->asset_type . DIRECTORY_SEPARATOR . 'archive' . DIRECTORY_SEPARATOR . $this->asset_type . '.php',
448+
$view_base . DIRECTORY_SEPARATOR . 'archive' . DIRECTORY_SEPARATOR . $this->asset_type . '.php',
413449
[
414450
'target_page_slug' => $this->target_page_slug,
415451
$this->asset_type . '_result' => $this->api_response->$results_property,
452+
'results' => $this->api_response->$results_property,
416453
'current_page' => max( 1, get_query_var( 'paged' ) ),
417454
'total_results' => $this->api_response->info['results'],
418455
'total_pages' => ceil( $this->api_response->info['results'] / $this->default_search_results_per_page ),
456+
'css_prefix' => $this->css_prefix,
457+
'label' => $this->label,
458+
'label_plural' => $this->label_plural,
459+
'model_class' => $this->model_class,
460+
'asset_type' => $this->asset_type,
461+
'asset_singular' => $this->asset_singular,
462+
'view_prefix' => $this->view_prefix,
419463
]
420464
);
421465

@@ -438,10 +482,16 @@ protected function single_the_content( $asset_slug ) {
438482
$model_class = $this->model_class;
439483
$asset_info = new $model_class( $this->api_response );
440484

485+
$view_base = $this->view_prefix . DIRECTORY_SEPARATOR . $this->asset_type;
486+
441487
Utilities::include_file(
442-
$this->asset_type . DIRECTORY_SEPARATOR . 'single' . DIRECTORY_SEPARATOR . $this->asset_singular . '.php',
488+
$view_base . DIRECTORY_SEPARATOR . 'single' . DIRECTORY_SEPARATOR . $this->asset_singular . '.php',
443489
[
444490
$this->asset_singular . '_info' => $asset_info,
491+
'asset_info' => $asset_info,
492+
'css_prefix' => $this->css_prefix,
493+
'asset_type' => $this->asset_type,
494+
'label' => $this->label,
445495
]
446496
);
447497

0 commit comments

Comments
 (0)