FΓΆrtroendemannaregister is a wordpress theme for municipalities presenting their elected politicians and their assignments.
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Type:wordpress-theme
pkg:composer/alingsas-kommun/fmr
Requires
- php: >=8.3
- blade-ui-kit/blade-heroicons: ^2.6
- laravel/tinker: ^2.10
- livewire/livewire: ^3.6
- log1x/sage-directives: ^2.0
- phpoffice/phpspreadsheet: ^5.1
- pixelfear/composer-dist-plugin: ^0.1.6
- roots/acorn: ^5.0
- roots/acorn-prettify: ^1.0
Requires (Dev)
- laravel/pint: ^1.20
Suggests
- log1x/sage-directives: A collection of useful Blade directives for WordPress and Sage (^1.0).
README
WordPress theme that converts your wordpress installation to a register of elected politicians
Features
- π§ Clean, efficient theme templating with Laravel Blade
- β‘οΈ Modern front-end development workflow powered by Vite
- π¨ A clean starting point for theme styles using Sass
- π Harness the power of Laravel with Acorn integration
- π― Structured namespace-based organization
- π Service provider pattern for clean code organization
- π§© Component-based architecture with Blade and Livewire
Requirements
Make sure all dependencies have been installed before moving on:
- Acorn v5
- WordPress >= 5.9
- PHP >= 8.2 (with
php-mbstringenabled) - Composer
- Node.js >= 20.0.0
- NPM
- Alpine.js (included)
Project Architecture
FMR is built on Roots Sage, a modern WordPress starter theme, enhanced with Laravel Acorn to bring Laravel's powerful features to WordPress.
Framework Stack
- WordPress Theme: Roots Sage
- Laravel Integration: Acorn (Laravel for WordPress)
- PHP Standard: PSR12
- Autoloading: PSR4
- Namespace Root:
App\
Key Concepts
This theme uses Laravel's service container and service providers pattern. All Laravel commands must be run through WordPress CLI using wp acorn instead of php artisan. The theme follows a structured, namespace-based organization where different types of functionality are separated into logical folders and namespaces.
β οΈ Important: Always use wp acorn instead of php artisan for all Laravel commands.
# β Correct wp acorn make:livewire Search wp acorn tinker # β Incorrect php artisan make:livewire Search # This won't work!
Theme Structure
themes/fmr/ # β Root of your fmr based theme βββ app/ # β Theme PHP (autoloaded classes) β βββ Core/ # β WP integration layer (post types, taxonomies, admin) β β βββ Admin/ # β Custom list/edit scaffolding β β βββ PostTypes/ # β CPT registrations β β βββ Taxonomies/ # β Custom taxonomies β β βββ Theme.php # β Core bootstrap β βββ Http/ # β Controllers & middleware β β βββ Controllers/ # β Web + API controllers β β βββ Middleware/ # β HTTP middleware (API keys etc.) β βββ Livewire/ # β Livewire component controllers β βββ Models/ # β Eloquent models targeting WP tables + customs β βββ Providers/ # β Service providers β β βββ ThemeServiceProvider.php β β βββ AdminServiceProvider.php β β βββ CoreServiceProvider.php β β βββ DatabaseServiceProvider.php β β βββ ServiceProvider.php β βββ Services/ # β Domain services (exports, field groups, etc.) β βββ Utilities/ # β Global theme utilities/helpers β βββ View/ # β Blade view components & composers βββ config/ # β Config files (database, prettify, routes) βββ database/ # β Laravel-style migrations & seeders β βββ migrations/ # β Custom tables (assignments, decision authorities, β¦) β βββ seeders/ # β `wp acorn db:seed` βββ resources/ # β Theme assets and templates β βββ css/ # β Tailwind + admin SCSS β βββ js/ # β Alpine components (frontend/admin) β βββ lang/ # β PHP + JSON translations β βββ views/ # β Blade templates (admin, public, Livewire) βββ routes/ # β Route definitions β βββ api.php # β API routes guarded by API keys β βββ web.php # β Public site routes βββ scripts/ # β Utility scripts (translations, etc.) βββ public/build/ # β Built assets (generated by Vite) βββ helpers.php # β Global helper functions βββ functions.php # β Theme bootloader βββ theme.json # β WP block/theme settings βββ composer.json # β PHP dependencies + autoload βββ package.json # β Node scripts/dependencies βββ vite.config.js # β Vite configuration file βββ vendor/ # β Composer packages (never edit manually)
Folder Structure & Namespaces
App Folder Organization
The app/ folder contains all autoloading classes organized by namespace. Each namespace serves a specific purpose:
App\View\Composers
Location: app/View/Composers/
Purpose: Provides data to views
Usage: Each composer specifies which templates should receive the data
Best Practice: Use for passing data to post type archive and single pages
Example: A composer that provides data to all single post templates
App\Livewire
Location: app/Livewire/
Purpose: Livewire component controllers for reactive functionality
Usage:
- Components like
SearchandAdvancedSearchproxy heavy logic to HTTP controllers (SearchController) while keeping the UI reactive. - Scaffold new components via
wp acorn make:livewire {ComponentName}and render them in Blade with<livewire:component-name />. Extension Tips: Keep component state serializable, reuse existing services/controllers, and wrap permission toggles with helpers such assetting()when needed.
App\Utilities
Location: app/Utilities/
Purpose: Global theme utilities usable throughout the theme
Examples:
AttributeFactory.php- Build HTML attributesClassFactory.php- Build CSS class namesGeneral.php- General utility functions
App\Models
Location: app/Models/
Purpose: Eloquent facades over WordPress core tables (posts, users, terms) plus bespoke tables (assignments, decision_authority).
Usage:
- Reuse scopes like
Post::type('board')->published()to keep queries expressive. - Keep model logic thin; delegate complex flows to Services.
Extension Tips: ExtendIlluminate\Database\Eloquent\Model, set$table,$primaryKey, and$timestampsexplicitly for WordPress tables, and follow PSR-4 naming.
App\Services
Location: app/Services/
Purpose: Encapsulate domain workflows such as exports (AssignmentExportService), anniversaries, and shared field group helpers.
Usage: Resolve via dependency injection (app(AssignmentExportService::class)) or type-hint in controllers. Each service should own one workflow so controllers stay thin.
Extension Tips: Register new services inside ThemeServiceProvider (or a dedicated provider) when they require bindings, and keep side effects (files, emails, etc.) here rather than in controllers.
App\Http\Controllers
Location: app/Http/Controllers/, with admin-specific controllers under App\Http\Controllers\Admin and API controllers under App\Http\Controllers\Api.
Purpose: Serve web, admin, and API requests. API controllers are intentionally read-only unless protected by additional auth layers and reuse shared transformers/services for consistent JSON.
Extension Tips: Duplicate the established patternβinject the relevant model/service, return JSON via response()->json() for APIs, and register routes inside routes/api.php or routes/web.php. Update ApiKeyMiddleware if authentication rules change.
Service Providers
Service providers handle registration and booting of classes. They follow Laravel's service provider pattern.
Main Service Provider
App\Providers\ThemeServiceProvider
- Registered in
functions.php - Registers other service providers:
AdminServiceProvider
Other Service Providers
AdminServiceProvider: Registers classes inApp\Adminnamespace
Core Admin Abstracts
The App\Core\Admin\Abstracts namespace provides reusable building blocks for WordPress-like list/add/edit experiences that sit on top of custom database tables:
EditPage: Wrapsadd_submenu_page, meta box registration, nonce handling, and saving logic for CRUD screens. Child classes (for assignments, decision authorities, etc.) only implementinitializeProperties(),getCurrentObject(), andhandleSave()to work with their specific models or tables.OptionsPage: Similar toEditPage, but geared toward configuration screens that store data in the WordPressoptionstable. It delegates the actual fields to field groups and ensures consistent save feedback.FieldGroup: Declarative meta box builder for post types. It wires nonce handling, tabbed layouts, relation pickers, and save hooks into WordPress' post edit screens so custom fields remain consistent across CPTs.OptionsFieldGroup: MirrorsFieldGroupbut persists values via the settings helper (setSetting()/setting()). Used by options pages to render reusable panels.MetaBox: Base class used by admin modules to add contextual meta boxes (for example, assignment details). It centralizes rendering helpers so each meta box stays small.RelationHandler: Encapsulates syncing logic between a custom record and related WordPress content (posts, taxonomies, or pivot tables). Admin edit pages call these handlers duringhandleSave()to keep relationships consistent.
Together these abstractions make it easy to scaffold new admin list/edit pages: extend EditPage, compose any number of FieldGroup/MetaBox classes, and optionally plug in RelationHandler helpers to keep bespoke tables in sync with WordPress data without rewriting the boilerplate each time.
Asset Building
Build Tool: Vite
Assets are built using Vite, configured in vite.config.js.
Entry Points
resources/css/app.css- Main theme styles (Tailwind)resources/js/app.js- Main frontend JavaScript (Alpine.js)resources/css/admin.scss- Admin stylesresources/js/admin.js- Admin JavaScript
Build Commands
# Development build with hot reload npm run dev # Production build npm run build
Output
Built assets are output to public/build/ directory.
Localization
Translation Files
Translation files are located in resources/lang/:
fmr.pot- Translation template (source)sv_SE.po- Swedish translationssv_SE.mo- Compiled translationsfmr-sv_SE-app-js.json- JavaScript translations (app)fmr-sv_SE-editor-js.json- JavaScript translations (editor)
Translation Commands
# Generate translation template npm run translate:pot # Update translation files npm run translate:update # Generate JavaScript translations npm run translate:js # Compile all translations npm run translate:compile
Usage in Code
PHP/Blade:
__('Text to translate', 'fmr') _e('Text to translate', 'fmr')
JavaScript:
// Translations are available via wp.i18n wp.i18n.__('Text to translate', 'fmr')
Theme Development
Initial Setup
- Run
npm installfrom the theme directory to install dependencies - Update
vite.config.jswith your local dev URL if needed - Run
composer installto install PHP dependencies
Development Workflow
-
Start development server:
npm run dev
This compiles assets when file changes are made and starts a Browsersync session.
-
Build for production:
npm run build
This compiles and minifies assets for production.
5. Indentation
Always use 4 spaces for indentation across all file types:
- PHP
- Blade templates
- JavaScript/JSX
- SCSS/CSS
6. Code Style
- PHP: PSR12 standard
- JavaScript: Single quotes, 4 spaces, semicolons
- SCSS: 4 spaces, single quotes
7. Dark Mode
Never add dark: classes - Dark mode is handled by an automatic color swapping system. The theme will automatically handle dark mode without explicit dark mode classes.
8. Testing Workflow
- Write code
- Test in
wp acorn tinker - Verify functionality
- Commit changes
9. Asset Management
- Use Vite for all asset building
- Keep entry points organized
- Use npm scripts for build commands
10. Localization
- Always use translation functions for user-facing text
- Run translation commands after adding new translatable strings
- Keep translation keys consistent
Quick Reference
Common Commands
# Livewire wp acorn make:livewire {ComponentName} # Testing wp acorn tinker # Translations npm run translate:pot npm run translate:update npm run translate:js # Assets npm run dev npm run build
File Locations
- PHP Classes:
app/{Namespace}/ - Blade Views:
resources/views/ - JavaScript:
resources/js/ - Styles:
resources/css/ - Translations:
resources/lang/ - Built Assets:
public/build/
Backend Building Blocks
Database Migrations & Seeders
- Location:
database/migrations/*.php,database/seeders/DatabaseSeeder.php - Purpose: Create and evolve custom tables such as
decision_authorityandassignmentswhile respecting WordPress foreign keys. - Usage:
- Create:
wp acorn make:migration create_example_table - Run:
wp acorn migrate - Rollback:
wp acorn migrate:rollback - Seed:
wp acorn db:seed
- Create:
- Extension tips: Mirror the existing migrations for index/foreign-key patterns, and keep table names snake_cased. When altering WordPress core tables, always guard with
Schema::hasColumnchecks.
Routes (Web + API)
- Web routes live in
routes/web.phpand are resolved via the normal WordPress front controller (e.g.,Route::get('/', HomeController::class)). Use helpers likeGeneral::getRouteSlug()so slugs stay configurable. - API routes live in
routes/api.php, grouped behindApp\Http\Middleware\ApiKeyMiddleware. Controllers return JSON resources for assignments, persons, parties, boards, and decision authorities. - Extend by adding new route groups or endpoints inside the respective file and binding them to controllers. Remember to register new controllers in a service provider if they need container bindings.
Documentation
Summary
This theme follows a structured, Laravel-inspired architecture within WordPress. Key principles:
- Always use
wp acorninstead ofphp artisan - Use commands for scaffolding - never manually create boilerplate
- Respect namespace organization - keep code in appropriate folders
- Use service providers for registration
- Test with Tinker - don't create test files
- 4 spaces indentation everywhere
- Follow PSR12 for PHP code style
When in doubt, check this README or use the appropriate wp acorn command to scaffold what you need.