PHPackages                             amund/kiss-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. amund/kiss-php

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

amund/kiss-php
==============

Kiss (Keep It Simply Static) is a php static site generator.

0.2.6(2w ago)022MITPHPCI passing

Since May 21Pushed 2w agoCompare

[ Source](https://github.com/Amund/kiss-php)[ Packagist](https://packagist.org/packages/amund/kiss-php)[ Docs](https://github.com/amund/kiss-php)[ RSS](/packages/amund-kiss-php/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (4)Dependencies (10)Versions (10)Used By (0)

💋 Kiss - Keep It Simply Static
==============================

[](#-kiss---keep-it-simply-static)

A PHP static site generator. Uses **Twig** for templating, supports YAML/JSON/PHP/XML/INI data sources, dynamic page parameters, static file sync, and a *watch* mode with partial rebuilds.

Prerequisites
-------------

[](#prerequisites)

- PHP 8.2+ (CLI)
- `inotifywait` (Linux/WSL) ou `fswatch` (macOS) pour le mode *watch*

Getting started
---------------

[](#getting-started)

```
composer global require amund/kiss-php
kiss init my-site
cd my-site
kiss build
```

CLI
---

[](#cli)

CommandDescription`kiss init [dir]`Creates a new site in the folder (or the current folder)`kiss build`Build the entire website`kiss watch`Build and then monitor the files (using inotifywait or fswatch)`kiss reset [all|dist|cache]`Remove `web/` and/or `tmp/``kiss route [list|name]`List the routes or rebuild a specific route`kiss copy [path]`Sync a file from `copy/` to `web/``kiss test`Validate the configuration (warmup without build)Default project structure
-------------------------

[](#default-project-structure)

```
kiss.yml        → Site configuration
├── copy/       → Static files (copied as-is to web/)
├── data/       → Global data (YAML/JSON/PHP/XML/INI/MD)
├── route/      → Route definitions (YAML/JSON/PHP/XML/INI)
├── template/   → Twig templates
└── web/        → Generated site (dist)

```

Configuration
-------------

[](#configuration)

File `kiss.yml` (also supports `.yaml`, `.php`, `.json`, `.xml`, `.ini`).

```
debug: true
path:
  copy: copy
  data: data
  route: route
  template: template
  dist: web
  cache: system
```

Environment variables (take precedence):

- `KISS_DEBUG=true`
- `KISS_VERBOSE=true`

Data sources
------------

[](#data-sources)

Files in `data/` are loaded automatically and available in Twig via `{{ global.* }}`.

Example — `data/site.yml`:

```
name: My Site
tagline: Great static site
```

In a Twig template:

```
{{ global.site.name }}
{{ global.site.tagline }}
```

### Markdown files

[](#markdown-files)

Markdown files (`.md`) in `data/` support frontmatter delimited by `---`:

```
---
title: My Article
date: 2024-01-01
---
Content **markdown** here.
```

The frontmatter fields are available directly, and the body is available as `content`. Combine with the `|markdown` filter in your templates:

```
{{ title }}
{{ content|markdown|raw }}
```

Routes
------

[](#routes)

### Single page

[](#single-page)

`route/index.yml`:

```
path: /index.html
template: page.twig
data:
  title: Home
```

### Pages with settings (`items`)

[](#pages-with-settings-items)

`route/blog.yml`:

```
path: /{slug}.html
template: post.twig
data:
  blog_title: "My Blog"
items:
  - slug: hello-world
    title: Hello World
  - slug: second-article
    title: Second article
```

Each item generates a page. `data` contains the metadata, which is merged into each child page.

### External reference (`$ref`)

[](#external-reference-ref)

```
path: /{slug}.html
template: post.twig
items:
  $ref: data/articles.yml
```

### Archive page + list

[](#archive-page--list)

```
path: /blog
template: blog_list.twig
data:
  title: "Blog"
items:
  $ref: data/posts.yml
```

Access in the archive template :

```
{{ title }}
{% for post in items %}
  {{ post.title }}
{% endfor %}
```

### URL Generation (`path()`)

[](#url-generation-path)

```
{{ path('about') }}                   → /about
{{ path('blog', {slug: 'hello'}) }}   → /hello.html
{{ path('blog') }}                     → /blog (page 1)
{{ path('blog', {page: 2}) }}          → /blog/page/2
```

### Accessing data from another route (`route()`)

[](#accessing-data-from-another-route-route)

```
{% set blog = route('blog') %}
{{ blog.title }}
{% for post in blog.items %}
  ...
{% endfor %}
```

### Pagination

[](#pagination)

`route/blog.yml`:

```
path: /blog
template: blog_list.twig
paginate: 10
data:
  title: "Archives"
items:
  $ref: data/posts.yml
```

Generates `blog/index.html` (page 1) and `blog/page/{n}/index.html` (subsequent pages).

```
{% for post in items %}
  ...
{% endfor %}
{% if prevPage %}
  ← Previous
{% endif %}
{% if nextPage %}
  Next →
{% endif %}
```

### Validation

[](#validation)

- `{param}` or `paginate` → `items` is required
- `data` is reserved for metadata
- The `$ref` should be set to `items`, not `data`

How it works
------------

[](#how-it-works)

- **Route manifest**: `tmp/kiss/route-manifest.php` tracks which files each route generated; orphaned files are cleaned on rebuild.
- **Template deps**: `tmp/kiss/template-deps.php` traces dependencies between templates (extends/include/embed) for partial rebuilds.
- **DataTree**: caches remote and local data sources as serialized PHP files.
- **Watch**: `inotifywait` detects changes and recompiles only the impacted routes.

License
-------

[](#license)

MIT

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance97

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity29

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

9

Last Release

15d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/16551810b8c56652cdcf583129be4fa53502818c9a0c5122960ccbce48132720?d=identicon)[Amund](/maintainers/Amund)

---

Top Contributors

[![Amund](https://avatars.githubusercontent.com/u/121880?v=4)](https://github.com/Amund "Amund (41 commits)")

---

Tags

blog-enginecmscontent-management-systemflat-fileinijsonkissmarkdownmulti-sourceno-databasephpssgstatic-site-generatorxmlyaml

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/amund-kiss-php/health.svg)

```
[![Health](https://phpackages.com/badges/amund-kiss-php/health.svg)](https://phpackages.com/packages/amund-kiss-php)
```

###  Alternatives

[tempest/framework

The PHP framework that gets out of your way.

2.2k31.1k11](/packages/tempest-framework)[craftcms/cms

Craft CMS

3.6k3.6M2.9k](/packages/craftcms-cms)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6941.5M395](/packages/drupal-core-recommended)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.5M370](/packages/easycorp-easyadmin-bundle)[pimcore/pimcore

Content &amp; Product Management Framework (CMS/PIM/E-Commerce)

3.8k3.8M444](/packages/pimcore-pimcore)[contao/core-bundle

Contao Open Source CMS

1231.6M2.6k](/packages/contao-core-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
