pseo / laravel-pseo
Laravel package that generates robots.txt, sitemap.xml, and llms.txt — and imports pSEO campaign archives.
Requires
- php: ^8.2
- ext-zip: *
- erusev/parsedown: ^1.7
- illuminate/console: ^10.0|^11.0|^12.0
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/filesystem: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
README
Laravel package that serves robots.txt, sitemap.xml, and llms.txt from imported pSEO campaign content — with a built-in password-protected upload panel.
Zero project coupling. Install via Composer, set two .env values, done.
Install
composer require pseo/laravel-pseo
Service provider is auto-discovered. No manual registration needed.
# Optionally publish views to customize them:
php artisan vendor:publish --tag=pseo-views
Minimum .env
PSEO_SITE_URL=https://yoursite.com PSEO_UPLOAD_PASSWORD=your_secret_password
That's it. The panel is live at /pseo-upload and all three endpoints are registered.
All .env options
# ── Required ─────────────────────────────────────────────────────────────────── # Absolute URL of your site — used in sitemap.xml, llms.txt, robots.txt Sitemap directive PSEO_SITE_URL=https://yoursite.com # Password for the upload panel at /pseo-upload # Accepts plain text OR a bcrypt hash: # php artisan tinker --execute="echo Hash::make('secret');" PSEO_UPLOAD_PASSWORD=your_secret_password # ── Optional (defaults shown) ────────────────────────────────────────────────── # URL path for the upload panel (default: /pseo-upload) # PSEO_UPLOAD_PATH=/pseo-upload # Storage disk — any disk in config/filesystems.php (default: app default disk) # PSEO_DISK=local # Relative path on disk for campaign pages (default: pseo) # Layout: {disk_root}/{PSEO_CONTENT_PATH}/pages/{pillar,supporting,research}/ # Empty string = use disk root directly # PSEO_CONTENT_PATH=pseo # URL prefix for imported page slugs (default: /learn) # PSEO_LINK_PREFIX=/learn # Cache TTL in seconds for generated files (default: 3600, 0 = disabled) # PSEO_CACHE_TTL=3600 # llms.txt header (defaults: APP_NAME / empty) # PSEO_LLMS_NAME= # PSEO_LLMS_DESCRIPTION= # Disable if you want to serve article pages yourself # PSEO_CONTENT_ROUTES=true # Layout component for article pages (default: layouts.app) # Publish views to customize: php artisan vendor:publish --tag=pseo-views # PSEO_VIEW_LAYOUT=layouts.app # Route names (defaults derived from PSEO_LINK_PREFIX: learn.index, learn.show) # PSEO_ROUTE_NAME_INDEX=learn.index # PSEO_ROUTE_NAME_SHOW=learn.show
What it does
After install the package automatically registers:
| Route | Description |
|---|---|
GET /robots.txt |
Generated robots.txt |
GET /sitemap.xml |
Generated from imported markdown pages |
GET /llms.txt |
Generated from imported markdown pages |
GET /pseo-upload |
Password-protected upload panel |
GET /learn |
Article index page |
GET /learn/{slug} |
Single article page |
Import a campaign ZIP
Via the web panel
- Open
/pseo-uploadin your browser. - Enter the password.
- Upload a campaign ZIP and click Import.
Via Artisan
php artisan pseo:import /path/to/campaign.zip
php artisan pseo:import /path/to/campaign.zip --force # overwrite existing files
What the import does
- Copies
pillar/*.md,supporting/*.md,research/*.md→{disk}/{content_path}/pages/{type}/ - Copies
schema/*.json→{disk}/{content_path}/schema/ - Rewrites internal links from
/slugto{link_prefix}/slug - Merges
sitemap.xmlentries (deduped by<loc>) - Merges
llms.txtlinks under## Imported Pages(deduped by URL) - Writes
robots.txtonly if it doesn't already exist - Fixes malformed YAML front matter automatically
Build static files to public/
Pre-generate files for direct web-server serving (bypasses PHP routing):
php artisan pseo:build # all three php artisan pseo:build sitemap llms # subset
Advanced configuration
For custom robots.txt rules, sitemap priorities, or llms.txt sections, publish the config:
php artisan vendor:publish --tag=pseo-config
This creates config/pseo.php in your project. Edit as needed — .env values always take precedence.
Note: If you set
PSEO_UPLOAD_PASSWORDafter runningphp artisan route:cache, runphp artisan route:clearfirst — upload routes are only registered when the password is set.
Cache
Clear after importing:
php artisan cache:forget pseo.robots php artisan cache:forget pseo.sitemap php artisan cache:forget pseo.llms
Requirements
- PHP 8.2+
- Laravel 10, 11, or 12
ext-zip
License
MIT