Skip to content

Commit 3563948

Browse files
committed
feat(plugin): added support for CSS and translations in plugins
1 parent 74fcac4 commit 3563948

File tree

21 files changed

+1070
-11
lines changed

21 files changed

+1070
-11
lines changed

docs/plugins.md

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,143 @@ class MyPlugin implements PluginInterface
120120
</div>
121121
```
122122

123-
## 9.6 Plugin version history
123+
## 9.6 Plugin stylesheets
124+
125+
Plugins can provide pre-compiled CSS files that will be automatically injected into both frontend and admin pages.
126+
127+
### 9.6.1 Adding stylesheets to your plugin
128+
129+
Implement the `getStylesheets()` method in your plugin class:
130+
131+
```php
132+
public function getStylesheets(): array
133+
{
134+
return [
135+
'assets/style.css', // Frontend styles
136+
'assets/admin-style.css' // Admin-specific styles
137+
];
138+
}
139+
```
140+
141+
**Important notes:**
142+
- Paths are relative to your plugin directory
143+
- Provide **pre-compiled CSS files** only (not SCSS)
144+
- CSS files are loaded after core styles (can override if needed)
145+
- Stylesheets are automatically injected into page `<head>`
146+
- Works in both frontend and admin areas
147+
148+
### 9.6.2 Plugin directory structure for CSS
149+
150+
```
151+
/content/plugins/YourPlugin/
152+
├── YourPluginPlugin.php
153+
└── assets/
154+
├── style.css
155+
└── admin-style.css
156+
```
157+
158+
## 9.7 Plugin translations
159+
160+
Plugins can provide translations in multiple languages that integrate seamlessly with phpMyFAQ's translation system.
161+
162+
### 9.7.1 Adding translations to your plugin
163+
164+
1. Implement the `getTranslationsPath()` method:
165+
166+
```php
167+
public function getTranslationsPath(): ?string
168+
{
169+
return 'translations'; // Path relative to plugin directory
170+
}
171+
```
172+
173+
2. Create translation files following phpMyFAQ's naming convention:
174+
175+
**File**: `/content/plugins/YourPlugin/translations/language_en.php`
176+
```php
177+
<?php
178+
$PMF_LANG['greeting'] = 'Hello';
179+
$PMF_LANG['message'] = 'Welcome to my plugin!';
180+
```
181+
182+
**File**: `/content/plugins/YourPlugin/translations/language_de.php`
183+
```php
184+
<?php
185+
$PMF_LANG['greeting'] = 'Hallo';
186+
$PMF_LANG['message'] = 'Willkommen zu meinem Plugin!';
187+
```
188+
189+
### 9.7.2 Using plugin translations
190+
191+
**In PHP code:**
192+
```php
193+
use phpMyFAQ\Translation;
194+
195+
$greeting = Translation::get('plugin.YourPlugin.greeting');
196+
$message = Translation::get('plugin.YourPlugin.message');
197+
```
198+
199+
**In Twig templates:**
200+
```twig
201+
{{ 'plugin.YourPlugin.greeting' | translate }}
202+
{{ 'plugin.YourPlugin.message' | translate }}
203+
```
204+
205+
### 9.7.3 Translation key format
206+
207+
Plugin translations use a namespaced format:
208+
```
209+
plugin.{PluginName}.{messageKey}
210+
```
211+
212+
- `plugin.` - Fixed namespace prefix
213+
- `{PluginName}` - Your plugin's name from `getName()`
214+
- `{messageKey}` - Key from your translation file's `$PMF_LANG` array
215+
216+
**Important:**
217+
- Plugin translations **cannot override** core phpMyFAQ translations
218+
- Translations are isolated per plugin
219+
- Automatic fallback to English if translation missing in current language
220+
- Support all 45+ phpMyFAQ languages
221+
222+
### 9.7.4 Plugin directory structure for translations
223+
224+
```
225+
/content/plugins/YourPlugin/
226+
├── YourPluginPlugin.php
227+
└── translations/
228+
├── language_en.php
229+
├── language_de.php
230+
├── language_fr.php
231+
└── language_es.php
232+
```
233+
234+
## 9.8 Complete plugin example with CSS and translations
235+
236+
See the `EnhancedExample` plugin for a complete working example demonstrating both features:
237+
238+
```
239+
/content/plugins/EnhancedExample/
240+
├── EnhancedExamplePlugin.php
241+
├── assets/
242+
│ ├── style.css
243+
│ └── admin-style.css
244+
└── translations/
245+
├── language_en.php
246+
├── language_de.php
247+
└── language_fr.php
248+
```
249+
250+
**Usage in Twig templates:**
251+
```twig
252+
{# Use the plugin event #}
253+
{{ phpMyFAQPlugin('enhanced.greeting', 'John') | raw }}
254+
255+
{# Access plugin translations directly #}
256+
<p>{{ 'plugin.EnhancedExample.adminMessage' | translate }}</p>
257+
```
258+
259+
## 9.9 Plugin version history
124260

125261
- 0.1.0: Initial version, shipped with phpMyFAQ 4.0.0
126-
- 0.2.0: Added support for plugin configuration options, shipped with phpMyFAQ 4.1.0
262+
- 0.2.0: Added support for plugin configuration options, plugin stylesheets and translations, shipped with phpMyFAQ 4.1.0

phpmyfaq/assets/templates/admin/index.twig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
<link rel="stylesheet" href="../assets/public/admin.css">
1818
<link rel="stylesheet" href="../assets/templates/default/theme.css">
19+
{% if pluginStylesheets is defined and pluginStylesheets is not empty %}
20+
{% for stylesheet in pluginStylesheets %}
21+
<link href="../{{ stylesheet }}" rel="stylesheet" media="screen">
22+
{% endfor %}
23+
{% endif %}
1924

2025
<script src="./assets/js/configuration.js"></script>
2126
<link rel="shortcut icon" href="../assets/images/favicon.ico">

phpmyfaq/assets/templates/default/index.twig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
{{ customCss | raw }}
2323
</style>
2424
{% endif %}
25+
{% if pluginStylesheets is defined and pluginStylesheets is not empty %}
26+
{% for stylesheet in pluginStylesheets %}
27+
<link href="{{ baseHref }}{{ stylesheet }}" rel="stylesheet" media="screen">
28+
{% endfor %}
29+
{% endif %}
2530
<link href="{{ baseHref }}assets/images/favicon.ico" rel="shortcut icon">
2631
<link href="{{ currentPageUrl }}" rel="canonical">
2732

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
/**
4+
* Enhanced Example Plugin demonstrating CSS and translation features
5+
*
6+
* Add
7+
*
8+
* {{ phpMyFAQPlugin('enhanced.greeting', 'John Doe') | raw }}
9+
*
10+
* into the Twig template.
11+
*
12+
* This Source Code Form is subject to the terms of the Mozilla Public License,
13+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
14+
* obtain one at https://mozilla.org/MPL/2.0/.
15+
*
16+
* @package phpMyFAQ
17+
* @author Thorsten Rinne <thorsten@phpmyfaq.de>
18+
* @copyright 2025 phpMyFAQ Team
19+
* @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
20+
* @link https://www.phpmyfaq.de
21+
* @since 2025-12-28
22+
*/
23+
24+
declare(strict_types=1);
25+
26+
namespace phpMyFAQ\Plugin\EnhancedExample;
27+
28+
use phpMyFAQ\Plugin\PluginEvent;
29+
use phpMyFAQ\Plugin\PluginInterface;
30+
use phpMyFAQ\Plugin\PluginConfigurationInterface;
31+
use phpMyFAQ\Translation;
32+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
33+
34+
class EnhancedExamplePlugin implements PluginInterface
35+
{
36+
public function getName(): string
37+
{
38+
return 'EnhancedExample';
39+
}
40+
41+
public function getVersion(): string
42+
{
43+
return '0.2.0';
44+
}
45+
46+
public function getDescription(): string
47+
{
48+
return 'Example plugin demonstrating CSS and translation support';
49+
}
50+
51+
public function getAuthor(): string
52+
{
53+
return 'phpMyFAQ Team';
54+
}
55+
56+
public function getDependencies(): array
57+
{
58+
return [];
59+
}
60+
61+
public function getConfig(): ?PluginConfigurationInterface
62+
{
63+
return null;
64+
}
65+
66+
public function getStylesheets(): array
67+
{
68+
return [
69+
'assets/style.css', // Frontend styles
70+
'assets/admin-style.css' // Admin styles
71+
];
72+
}
73+
74+
public function getTranslationsPath(): ?string
75+
{
76+
return 'translations';
77+
}
78+
79+
public function registerEvents(EventDispatcherInterface $eventDispatcher): void
80+
{
81+
$eventDispatcher->addListener('enhanced.greeting', [$this, 'onGreeting']);
82+
}
83+
84+
public function onGreeting(PluginEvent $event): void
85+
{
86+
$name = $event->getData();
87+
88+
// Use plugin-namespaced translations
89+
$greeting = Translation::get('plugin.EnhancedExample.greeting');
90+
$message = Translation::get('plugin.EnhancedExample.welcomeMessage');
91+
92+
$output = sprintf(
93+
'<div class="pmf-plugin-enhanced-greeting">
94+
<h3>%s, %s!</h3>
95+
<p>%s</p>
96+
</div>',
97+
htmlspecialchars($greeting ?? 'Hello'),
98+
htmlspecialchars($name),
99+
htmlspecialchars($message ?? 'Welcome to the Enhanced Example Plugin!')
100+
);
101+
102+
$event->setOutput($output);
103+
}
104+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Enhanced Example Plugin - Admin Styles
3+
*
4+
* This stylesheet demonstrates admin-specific styling for plugins.
5+
* Admin styles are typically more subtle and professional.
6+
*/
7+
8+
.pmf-plugin-enhanced-greeting {
9+
padding: 1rem;
10+
margin: 1rem 0;
11+
background: #f8f9fa;
12+
border-left: 4px solid #667eea;
13+
color: #333;
14+
border-radius: 4px;
15+
}
16+
17+
.pmf-plugin-enhanced-greeting h3 {
18+
margin: 0 0 0.5rem 0;
19+
font-size: 1.25rem;
20+
font-weight: 600;
21+
color: #667eea;
22+
}
23+
24+
.pmf-plugin-enhanced-greeting p {
25+
margin: 0;
26+
color: #666;
27+
font-size: 0.95rem;
28+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Enhanced Example Plugin - Frontend Styles
3+
*
4+
* This stylesheet demonstrates how plugins can provide their own CSS styling
5+
* for frontend pages.
6+
*/
7+
8+
.pmf-plugin-enhanced-greeting {
9+
padding: 1.5rem;
10+
margin: 1rem 0;
11+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
12+
color: white;
13+
border-radius: 8px;
14+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
15+
animation: fadeIn 0.5s ease-in;
16+
}
17+
18+
.pmf-plugin-enhanced-greeting h3 {
19+
margin: 0 0 0.5rem 0;
20+
font-size: 1.5rem;
21+
font-weight: 600;
22+
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
23+
}
24+
25+
.pmf-plugin-enhanced-greeting p {
26+
margin: 0;
27+
opacity: 0.95;
28+
font-size: 1rem;
29+
line-height: 1.6;
30+
}
31+
32+
@keyframes fadeIn {
33+
from {
34+
opacity: 0;
35+
transform: translateY(-10px);
36+
}
37+
to {
38+
opacity: 1;
39+
transform: translateY(0);
40+
}
41+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/**
4+
* German translation for EnhancedExample Plugin
5+
*
6+
* This file demonstrates how plugins can provide their own translations
7+
* that integrate with phpMyFAQ's translation system.
8+
*
9+
* This Source Code Form is subject to the terms of the Mozilla Public License,
10+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
11+
* obtain one at https://mozilla.org/MPL/2.0/.
12+
*
13+
* @package phpMyFAQ
14+
* @author phpMyFAQ Team
15+
* @copyright 2025 phpMyFAQ Team
16+
* @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
17+
* @link https://www.phpmyfaq.de
18+
* @since 2025-01-01
19+
*/
20+
21+
$PMF_LANG['greeting'] = 'Hallo';
22+
$PMF_LANG['welcomeMessage'] = 'Willkommen zum Enhanced Example Plugin mit Übersetzungsunterstützung!';
23+
$PMF_LANG['adminMessage'] = 'Dieses Plugin demonstriert CSS- und Übersetzungsfunktionen';
24+
$PMF_LANG['description'] = 'Dies ist ein umfassendes Beispiel, das zeigt, wie Plugins sowohl Stylesheets als auch Übersetzungen verwenden können';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/**
4+
* English translation for EnhancedExample Plugin
5+
*
6+
* This file demonstrates how plugins can provide their own translations
7+
* that integrate with phpMyFAQ's translation system.
8+
*
9+
* This Source Code Form is subject to the terms of the Mozilla Public License,
10+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
11+
* obtain one at https://mozilla.org/MPL/2.0/.
12+
*
13+
* @package phpMyFAQ
14+
* @author phpMyFAQ Team
15+
* @copyright 2025 phpMyFAQ Team
16+
* @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
17+
* @link https://www.phpmyfaq.de
18+
* @since 2025-01-01
19+
*/
20+
21+
$PMF_LANG['greeting'] = 'Hello';
22+
$PMF_LANG['welcomeMessage'] = 'Welcome to the Enhanced Example Plugin with translation support!';
23+
$PMF_LANG['adminMessage'] = 'This plugin demonstrates CSS and translation features';
24+
$PMF_LANG['description'] = 'This is a comprehensive example showing how plugins can use both stylesheets and translations';

0 commit comments

Comments
 (0)