Jumbo
Content sites in plain PHP.
Dumbo's mum. Bigger ears.
composer global require notrab/jumbo
<?php
use Dumbo\Jumbo\Page;
return new Page(
paths: fn($site) => array_map(
fn($slug) => ["slug" => $slug],
$site->slugs(),
),
render: fn($context, $site) => $site->view("post", [
"post" => $site->find($context->req->param("slug")),
]),
);
Pick something to build
Each of these is a few files in a Jumbo site. Run jumbo new, add one, and you're away.
A blog with a feed
Posts in Markdown, a page for each one, and an RSS feed from the same list. Code is highlighted on the server.
// pages/rss.xml.php
return new Page(render: fn($c, $site) => $site->rss(
array_map(fn($post) => [
'title' => $post['title'],
'link' => "/blog/{$post['slug']}",
'date' => $post['meta']['date'],
], $site->posts())
));
Feeds and sitemaps →
A docs site, like this one
Markdown pages with a sidebar, components for callouts and tabs, and a table of contents from the headings.
# Routing
::: callout type="tip"
Files in pages/ are **routes**.
:::
```php
$site->find('routing')['toc'];
```
Content →
A landing page with a contact form
The page handles its own form. Validation errors show next to the fields, and a good post redirects.
actions: [
'default' => function ($input, $c) {
if (empty($input['email'])) {
return Action::fail(['email' => 'Required']);
}
return $c->redirect('/thanks', 303);
},
],
Actions →
A site in three languages
Every page is served under each locale, with translated Markdown and hreflang links.
'i18n' => ['locales' => ['en', 'fr', 'es']],
$site->find('home', $site->locale($c));
$site->alternates($c);
// ['en' => '/', 'fr' => '/fr', 'es' => '/es']
Locales →
A portfolio full of photos
Responsive images resized with GD, in WebP, with their sizes set so nothing jumps as they load.
<?= $site->img('/work/poster.jpg', 'Gig poster',
width: 800,
) ?>
Images →
A static site with a live corner
Build most pages for a CDN, and render search or a dashboard on each request with Dumbo middleware in front.
return new Page(
prerender: false,
render: fn($c, $site) => $site->view('search', [
'q' => $c->req->query('q'),
]),
);
Page data →
Put on your first show in about a minute
Install Jumbo, run jumbo new, and open your browser.