{"id":13856623,"url":"https://github.com/aoxborrow/Paste","last_synced_at":"2025-07-13T19:32:03.450Z","repository":{"id":8003331,"uuid":"9411060","full_name":"aoxborrow/Paste","owner":"aoxborrow","description":"Paste is a lightweight CMS built around static files and folders instead of a database.","archived":true,"fork":false,"pushed_at":"2016-07-29T21:39:22.000Z","size":25390,"stargazers_count":18,"open_issues_count":0,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-25T20:43:14.121Z","etag":null,"topics":["cms","mustache","php","portfolio-website","static-site"],"latest_commit_sha":null,"homepage":"https://archive.pastelabs.com/paste-demo","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aoxborrow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-13T08:52:25.000Z","updated_at":"2024-04-21T15:53:25.000Z","dependencies_parsed_at":"2022-08-23T20:50:55.156Z","dependency_job_id":null,"html_url":"https://github.com/aoxborrow/Paste","commit_stats":null,"previous_names":["aoxborrow/paste","paste/paste"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aoxborrow%2FPaste","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aoxborrow%2FPaste/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aoxborrow%2FPaste/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aoxborrow%2FPaste/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aoxborrow","download_url":"https://codeload.github.com/aoxborrow/Paste/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225912206,"owners_count":17544120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms","mustache","php","portfolio-website","static-site"],"created_at":"2024-08-05T03:01:06.489Z","updated_at":"2024-11-22T14:30:28.078Z","avatar_url":"https://github.com/aoxborrow.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"## Paste\n\n- Paste is a lightweight \"CMS\" built around static files and folders instead of a database.\n- Each HTML file represents a page in the menu, each folder represents a section, to infinite depth.\n- [Mustache](http://mustache.github.io/) is used for logic-less templating including partials.\n- Variables and templating cascade down through the site heirarchy.\n- Configuration is defined within the HTML source, like so:\n\n```\n\u003c!--  \n@template: master\n@partial: project\n@title: The Page Title\n@visible: TRUE // visible in menu\n@label: Menu Label (optional)\n--\u003e\n```\n\n#### Design Goals\n\n- simple routing with user-definable routes and closures\n- [Mustache](http://mustache.github.io/) for ultra dumb templating\n- flexible templates and cascading page partials\n- configuration via simple inline syntax\n- takes some cues from [Stacey App](http://www.staceyapp.com/).\n- use latest PHP tech, e.g. Composer\n\n#### Requirements\n\n- PHP 5.3+\n- Apache mod_rewrite\n- [Mustache.php](https://github.com/bobthecow/mustache.php) (installed automatically by Composer)\n\n## Quick Start / Demo\n\nThe fastest way is to clone the [demo site](https://github.com/paste/paste-demo) and modify to taste!  Be sure to run `composer update` to install dependencies.\n\n**Demo Site:** https://github.com/paste/paste-demo  \n\n![Screenshot](https://github.com/paste/paste-demo/raw/master/assets/images/demo-site.png)\n\n\n## Installation\n\n[Use Composer](http://getcomposer.org/). Add `paste/paste` to your project's `composer.json`:\n```json\n{\n    \"require\": {\n        \"paste/paste\": \"dev-master\"\n    }\n}\n```\n\nCreate an `index.php` file for the front router:\n[(or copy from the demo site)](https://github.com/paste/paste-demo/blob/master/index.php)\n\n```php\n\u003c?php\n\n// composer autoload\nrequire 'vendor/autoload.php';\nuse Paste\\Paste;\n\n// configuration\n$config = array(\n\t// optionally specify a 'base_url' if serving Paste from a subdirectory, i.e. RewriteBase\n\t// 'base_url' =\u003e '/paste-demo',\n\t// relative path to content directory\n\t// 'content_dir' =\u003e 'content',\n\t// relative path to template directory\n\t// 'template_dir' =\u003e 'templates',\n\t// relative path to cache directory\n\t// 'cache_dir' =\u003e 'cache',\n);\n\n// load config and parse content directory\n$paste = new Paste($config);\n\n// (optional) user defined routing\n// 'route regex' =\u003e any valid callback\n// matched tokens from the regex will be passed as parameters, with $paste instance first\n$paste-\u003eadd_route('blog/([0-9]{4})/([0-9]{2})/([0-9]{2})/([A-Za-z0-9-_]+)', function($paste, $year, $month, $day, $name) {\n\t// ignore date and run normal content request\n\treturn $paste-\u003erender_url(\"blog/$name\");\n});\n\n// init routing and run\n$paste-\u003erun();\n```\nCreate the `content`, `templates`, `cache` directories in your web root. The `cache` folder must be writeable by Apache. Your web root should end up looking something like this:\n\n\u003cimg src=\"https://github.com/paste/paste-demo/raw/master/assets/images/content-example.png\" align=\"right\" style=\"margin: 15px;\"\u003e\n\n```\n/cache/\n/content/\n\tindex.html\n/templates/\n\ttemplate.stache\n/vendor/\nindex.php\ncomposer.json\n.htaccess\n```\n\nAdd the root content index file, `content/index.html`:\n\n```html\n\u003c!-- @title: Hello World --\u003e\n\u003c!-- @template: template --\u003e\n\u003ch3\u003eHello, world!\u003c/h3\u003e\n```\n\nAdd the first template, e.g. `templates/template.stache`:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\t\u003cmeta charset=\"utf-8\"\u003e\n\t\u003ctitle\u003e{{title}}\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\t{{{content}}}\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nCreate an `.htaccess` file to enable URL rewriting:\n[(or copy from the demo site)](https://github.com/paste/paste-demo/blob/master/.htaccess)\n\n```apache\n# don't list directories\nOptions -Indexes\n\n# Turn on URL rewriting\nRewriteEngine On\n\n# Installation directory -- same as your 'base_url'\nRewriteBase /\n\n# Protect dot files from being viewed\n\u003cFiles .*\u003e\n\tOrder Deny,Allow\n\tDeny From All\n\u003c/Files\u003e\n\n# Protect application and system files from being viewed\nRewriteRule ^(?:vendor|content|templates|cache)\\b.* index.php/$0 [L]\n\n# Allow any files or directories that exist to be displayed directly\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\n\n# Rewrite all other URLs to index.php/URL\nRewriteRule .* index.php/$0 [PT]\n\n# use utf-8 encoding for anything served text/plain or text/html\nAddDefaultCharset utf-8\n\n# force utf-8 for a number of file formats\nAddCharset utf-8 .html .css .js .xml .json .rss\n```\n\n\nNow visit your Paste site in a web browser and take in the _magic_!\n\n\n### REFACTOR 2016 TODOs:\n- ~~allow a rewrite base that is not root, i.e. allow running Paste from a subdirectory~~\n- ~~classes seem arbitrary, combine Paste \u0026 Content?~~\n- ~~make it completely OO, not sure why so much static~~\n\n\n### REWRITE 2013 TODOs:\n- ~~render content with Mustache string loader to allow referencing partials and context~~\n- ~~add a shortcut to hide pages like _ underscore prefix in the filename~~\n- ~~make example site more generic, add dummy text and illustrative CSS for menu heirarchy~~\n- ~~write new description and a quick usage guide w/ screenshots~~\n- ~~single template(), rest is partials()~~\n- ~~move static content stuff into Paste~~\n- ~~refactor Page lib~~\n\t- ~~Page Constructor -- change factory to Page::from_path()~~\n\t- ~~update Page-\u003eis_current() and Page-\u003eis\\_parent~~\n\t- ~~consolidate nav stuff to next() and prev(), remove unused~~\n\t- ~~change page-\u003eparents to something like parent_paths~~\n\t- ~~simplify find and find_all, etc.~~\n\t- ~~render menu() separately to remove invisible pages~~\n\t- ~~remove section in favor of parent~~\n- ~~use Mustache filesystem loader for partials and cache~~\n- ~~make Menu mustache partial resursive for infinite depth -- fix CSS~~\n- ~~more unique syntax for page/section vars~~\n- ~~proper cascading templates~~\n- ~~redo the section control as suggested in Page-\u003efactory? no~~\n- ~~return Paste to all static class~~\n- ~~Combine Content into Page~~\n- ~~Combine Controller \u0026 Content~~\n- ~~Combine Page \u0026 Template classes~~\n- ~~change mustache templates to just .stache~~\n- ~~just link to tumblr instead of using Tumblr blog driver~~\n- ~~consider only loading structure on demand (e.g. menu()), and then only loading page vars~~\n- ~~does a file based site really need a file cache? -- use memcache if anything. benchmark cache vs. no cache~~\n- ~~use namespacing, make autoloader PSR-0 compatible and package it for composer~~\n- ~~Paste::route() syntax for user defined routes~~\n- ~~separate core and a sample site for this repo, move personal portfolio stuff to separate repo~~\n- ~~simplify as much as possible. too much code for what it's supposed to be~~\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faoxborrow%2FPaste","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faoxborrow%2FPaste","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faoxborrow%2FPaste/lists"}