├── .gitignore ├── exporters ├── posterous │ ├── changelog.mdown │ ├── package.json │ ├── posterous.php │ └── readme.mdown └── wordpress │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── wordpress.php ├── fields ├── author │ ├── author.php │ ├── changelog.mdown │ ├── package.json │ └── readme.mdown ├── fileselect │ ├── changelog.mdown │ ├── fileselect.css │ ├── fileselect.php │ ├── package.json │ └── readme.mdown └── tags │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ ├── tags.css │ ├── tags.js │ └── tags.php ├── plugins ├── auth │ ├── accounts │ │ └── demo.php │ ├── auth.php │ ├── changelog.mdown │ ├── content │ │ ├── login │ │ │ └── login.txt │ │ └── logout │ │ │ └── logout.txt │ ├── package.json │ ├── readme.mdown │ ├── snippets │ │ └── login.php │ └── templates │ │ ├── login.php │ │ └── logout.php ├── color │ ├── changelog.mdown │ ├── color.php │ ├── package.json │ └── readme.mdown ├── contactform │ ├── changelog.mdown │ ├── contactform.php │ ├── lib │ │ ├── email.php │ │ └── submission.php │ ├── package.json │ ├── readme.mdown │ └── snippets │ │ ├── contactform.mail.php │ │ └── contactform.php ├── dribbble │ ├── changelog.mdown │ ├── dribbble.php │ ├── package.json │ └── readme.mdown ├── email │ ├── changelog.mdown │ ├── email.php │ ├── package.json │ └── readme.mdown ├── flickrbadge │ ├── changelog.mdown │ ├── flickrbadge.php │ ├── package.json │ └── readme.mdown ├── github │ ├── README.mdown │ ├── changelog.mdown │ ├── github.php │ └── package.json ├── highlight │ ├── changelog.mdown │ ├── highlight.php │ ├── highlight │ │ ├── geshi.php │ │ └── geshi │ │ │ ├── css.php │ │ │ ├── html.php │ │ │ ├── js.php │ │ │ ├── objc.php │ │ │ └── php.php │ ├── package.json │ ├── readme.mdown │ └── styles │ │ ├── css.css │ │ ├── html.css │ │ ├── js.css │ │ ├── objc.css │ │ └── php.css ├── instagram │ ├── changelog.mdown │ ├── instagram.php │ ├── package.json │ └── readme.mdown ├── randomimage │ ├── changelog.mdown │ ├── package.json │ ├── randomimage.php │ └── readme.mdown ├── readingtime │ ├── changelog.mdown │ ├── package.json │ ├── readingtime.php │ └── readme.mdown ├── readlater │ ├── changelog.mdown │ ├── package.json │ ├── readlater.php │ └── readme.mdown ├── related │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── related.php ├── resrc │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── resrc.php ├── search │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── search.php ├── sublimevideo │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── sublimevideo.php ├── tagcloud │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── tagcloud.php ├── thumb │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── thumb.php └── tweets │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── tweets.php ├── readme.mdown ├── snippets ├── breadcrumb │ ├── breadcrumb.php │ ├── changelog.mdown │ ├── package.json │ └── readme.mdown ├── contactform │ ├── contactform.mail.php │ ├── contactform.php │ └── readme.mdown ├── disqus │ ├── changelog.mdown │ ├── disqus.php │ ├── package.json │ └── readme.mdown ├── feed │ ├── changelog.mdown │ ├── feed.php │ ├── package.json │ └── readme.mdown ├── filelist │ ├── changelog.mdown │ ├── filelist.php │ ├── package.json │ └── readme.mdown ├── flattr │ ├── changelog.mdown │ ├── flattr.php │ ├── package.json │ └── readme.mdown ├── gallery │ ├── changelog.mdown │ ├── gallery.php │ ├── package.json │ └── readme.mdown ├── map │ ├── changelog.mdown │ ├── map.php │ ├── package.json │ └── readme.mdown ├── menu │ ├── changelog.mdown │ ├── menu.php │ ├── package.json │ └── readme.mdown ├── pagination │ ├── changelog.mdown │ ├── package.json │ ├── pagination.php │ └── readme.mdown ├── podcastfeed │ └── podcastfeed.php ├── prevnext │ ├── changelog.mdown │ ├── package.json │ ├── prevnext.php │ └── readme.mdown ├── submenu │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── submenu.php ├── treemenu │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── treemenu.php └── video │ ├── changelog.mdown │ ├── package.json │ ├── readme.mdown │ └── video.php └── templates ├── feed ├── readme.mdown └── template │ └── feed.php └── podcastfeed └── podcastfeed.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | plugins/visitor 3 | packages 4 | -------------------------------------------------------------------------------- /exporters/posterous/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.1 4 | + Initial release -------------------------------------------------------------------------------- /exporters/posterous/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "posterous", 3 | "readable": "Posterous", 4 | "version": "0.1", 5 | "stable": true, 6 | "description": "Export articles from a Posterous blog and import them into Kirby", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/", 9 | 10 | "params": { 11 | "blog": "Your Posterous blog", 12 | "username": "Your Posterous username (email)", 13 | "password": "Your Posterous password", 14 | "token": "Your Posterous API token", 15 | "template": "The desired name for your content files (for example article.txt)", 16 | "dateformat": "Setup the date format to use in content files (default 2012-02-09 16:00)" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /exporters/posterous/posterous.php: -------------------------------------------------------------------------------- 1 | "Users" > "api_token" 43 | $token = 'yourtoken'; 44 | 45 | // setup the desired name for your content files 46 | $template = 'article.txt'; 47 | 48 | // setup the date format, which will 49 | // be used in your content files 50 | // default is 2012-02-09 16:00 51 | $dateformat = 'Y-m-d H:i'; 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | // DON'T TOUCH THE LINES BELOW 66 | // =========================== 67 | 68 | // Stuff to run it with kpm 69 | if(isset($kpm)) { 70 | @extract($kpm['options']); 71 | $root = $kpm['contentdir']; 72 | 73 | function puterror($error) { 74 | kpmerror($error); 75 | } 76 | 77 | function putmessage($message) { 78 | kpmlog($message); 79 | } 80 | } else { 81 | require('kirby/lib/kirby.php'); 82 | function puterror($error) { 83 | dir($error); 84 | } 85 | 86 | function putmessage($message) { 87 | echo $message; 88 | } 89 | } 90 | 91 | set_time_limit(0); 92 | 93 | if($username == 'your@email-address.com' && $password == 'yourpassword' && $blog == 'yourblog') { 94 | puterror('Please setup the credentials for your Posterous blog.
Open posterous.php in your favorite editor and follow the instructions.'); 95 | } 96 | 97 | if(!is_dir($root)) puterror('The blog directory does not exist'); 98 | if(!is_writable($root)) puterror('The blog directory is not writable'); 99 | 100 | $posts = array(); 101 | $page = 1; 102 | 103 | $p = new posterous($username, $password, $token); 104 | 105 | while($data = $p->call('http://posterous.com/api/2/sites/' . $blog . '/posts/public', array('page' => $page))) { 106 | 107 | foreach($data as $d) { 108 | $posts[] = $d; 109 | } 110 | 111 | sleep(1); 112 | 113 | $page++; 114 | 115 | } 116 | 117 | if(!$posts) puterror('The posts couldn\'t be found'); 118 | 119 | $cnt = count($posts); 120 | $len = str::length($cnt); 121 | 122 | if($len <= 1) $len = 2; 123 | 124 | $n = 0; 125 | $skipped = array(); 126 | $errors = array(); 127 | 128 | foreach(array_reverse($posts) as $post) { 129 | 130 | $n++; 131 | $output = array(); 132 | 133 | if(empty($post->title) || empty($post->slug)) { 134 | $errors[] = $post; 135 | continue; 136 | } 137 | 138 | // collect tags 139 | $tags = array(); 140 | foreach($post->tags as $t) $tags[] = $t->name; 141 | 142 | 143 | $output[] = 'title: ' . $post->title; 144 | $output[] = 'date: ' . date($dateformat, strtotime($post->display_date)); 145 | $output[] = 'text: ' . "\n\n" . trim($post->body_full); 146 | $output[] = 'tags: ' . implode(', ', $tags); 147 | 148 | $name = pad($n, $len) . '-' . f::safe_name(basename($post->slug)); 149 | $dir = $root . '/' . $name; 150 | 151 | if(is_dir($dir)) { 152 | $skipped[] = basename($dir); 153 | continue; 154 | } 155 | 156 | dir::make($dir); 157 | 158 | $content = implode("\n\n" . '----' . "\n\n", $output); 159 | $file = $dir . '/' . $template; 160 | 161 | f::write($file, $content); 162 | 163 | } 164 | 165 | putmessage('Exported ' . $n . ' articles to ' . $root . '

'); 166 | 167 | if(!empty($errors)) { 168 | putmessage(count($errors) . ' article(s) could not be imported

'); 169 | } 170 | 171 | if(!empty($skipped)) { 172 | putmessage('The following folders have been skipped, because they already existed:' . a::show($skipped, false)); 173 | } 174 | 175 | // padding zero function 176 | function pad($number,$n) { 177 | return str_pad((int) $number,$n,"0",STR_PAD_LEFT); 178 | } 179 | 180 | // Minimal Posterous API Class 181 | class posterous { 182 | 183 | function __construct($username, $password, $token) { 184 | 185 | $this->username = $username; 186 | $this->password = $password; 187 | $this->token = $token; 188 | 189 | } 190 | 191 | function call($url, $args = array()) { 192 | 193 | $args['api_token'] = $this->token; 194 | 195 | $url = $url . '?' . http_build_query($args); 196 | 197 | $ch = curl_init(); 198 | curl_setopt($ch, CURLOPT_URL, $url); 199 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 200 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); 201 | curl_setopt($ch, CURLOPT_HEADER, false); 202 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 203 | curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password); 204 | curl_setopt($ch, CURLOPT_POST, 0); 205 | 206 | $data = curl_exec($ch); 207 | curl_close($ch); 208 | 209 | return @json_decode($data); 210 | 211 | } 212 | 213 | } 214 | -------------------------------------------------------------------------------- /exporters/posterous/readme.mdown: -------------------------------------------------------------------------------- 1 | # Posterous Article Exporter 2 | 3 | This exporter will grab all articles from your Posterous blog and export them to folders and text files, which will be readable by Kirby. 4 | 5 | ## Installation 6 | 7 | Download posterous.php and put it in the main directory of your Kirby site. Open posterous.php in your favorite editor and setup the name of your blog, your posterous username and password and the posterous API token. You should also make sure that $root is setup to the folder where all the exported articles should be stored and that this folder is writable. (change permissions to 0755) 8 | 9 | MAKE A BACKUP OF YOUR CONTENT FOLDER TO BE SURE TO NOT LOSE ANY DATA. 10 | 11 | Open http://yourkirbydomain.com/posterous.php in your browser to start the exporter. 12 | 13 | ## Clean-Up 14 | 15 | Make sure to remove posterous.php once you've finished exporting all your articles. 16 | 17 | ## The exporter does not… 18 | 19 | - …export images from Posterous 20 | - …convert HTML in your Posterous articles to Markdown 21 | - …export Posterous pages or custom post types 22 | 23 | ## Help needed! 24 | 25 | I could really need some help with improving the export so it will grab the images and videos and convert HTML to Markdown. 26 | -------------------------------------------------------------------------------- /exporters/wordpress/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.1 4 | + Initial release -------------------------------------------------------------------------------- /exporters/wordpress/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wordpress", 3 | "readable": "Wordpress", 4 | "version": "0.1", 5 | "stable": true, 6 | "description": "Export articles from a Wordpress blog and import them into Kirby", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/", 9 | 10 | "params": { 11 | "blog": "Your Wordpress blog URL", 12 | "username": "Your Wordpress username", 13 | "password": "Your Wordpress password", 14 | "template": "The desired name for your content files (for example article.txt)", 15 | "dateformat": "Setup the date format to use in content files (default 2012-02-09 16:00)" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /exporters/wordpress/readme.mdown: -------------------------------------------------------------------------------- 1 | # Wordpress Article Exporter 2 | 3 | This exporter will grab all articles from your Wordpress blog and export them to folders and text files, which will be readable by Kirby. 4 | 5 | ## Installation 6 | 7 | Download wordpress.php and put it in the main directory of your Kirby site. Open wordpress.php in your favorite editor and setup the url to your blog and your wordpress username and password. You should also make sure that $root is setup to the folder where all the exported articles should be stored and that this folder is writable. (change permissions to 0755) 8 | 9 | MAKE A BACKUP OF YOUR CONTENT FOLDER TO BE SURE TO NOT LOSE ANY DATA. 10 | 11 | Open http://yourkirbydomain.com/wordpress.php in your browser to start the exporter. 12 | 13 | ## Clean-Up 14 | 15 | Make sure to remove wordpress.php once you've finished exporting all your articles. 16 | 17 | ## The exporter does not… 18 | 19 | - …export images from Wordpress 20 | - …convert HTML in your Wordpress articles to Markdown 21 | - …export Wordpress pages or custom post types 22 | 23 | ## Troubleshooting 24 | 25 | If the exporter keeps on failing, please try to disable all Wordpress plugins and switch to the default theme. 26 | 27 | ## Help needed! 28 | 29 | I could really need some help with improving the export so it will convert HTML to Markdown or at least clean the HTML. 30 | 31 | -------------------------------------------------------------------------------- /fields/author/author.php: -------------------------------------------------------------------------------- 1 | user->username; 6 | 7 | ?> 8 | 9 | -------------------------------------------------------------------------------- /fields/author/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /fields/author/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "author", 3 | "readable": "Author", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Panel field to automatically add the current logged in user's username to a text input field", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/", 9 | 10 | "dependencies": { 11 | "panel": "0.8" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fields/author/readme.mdown: -------------------------------------------------------------------------------- 1 | # Kirby Panel Author field 2 | 3 | ## What is this 4 | 5 | Automatically add the current logged in user's username to a text input field 6 | 7 | ## Installation 8 | 9 | If not already exists, add a fields folder to your `site/panel` folder and copy the entire author folder there. Your structure should look like this: 10 | 11 | site 12 | panel 13 | fields 14 | author 15 | author.php 16 | 17 | ## In your blueprints 18 | 19 | As soon as you dropped the author field into your panel folder you can use it in your blueprints: 20 | 21 | fields: 22 | author: 23 | label: Author 24 | type: author 25 | 26 | -------------------------------------------------------------------------------- /fields/fileselect/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /fields/fileselect/fileselect.css: -------------------------------------------------------------------------------- 1 | .form .field.fileselect { 2 | margin-right: -20px; 3 | } 4 | .form .field.fileselect select { 5 | display: block; 6 | margin-top: -2px; 7 | width: 100%; 8 | margin-bottom: 5px; 9 | } 10 | -------------------------------------------------------------------------------- /fields/fileselect/fileselect.php: -------------------------------------------------------------------------------- 1 | pages()->active(); 6 | $files = $page->files(); 7 | $options = array(); 8 | 9 | if(isset($empty)) { 10 | $options[0] = '- ' . $empty . ' -'; 11 | } 12 | 13 | $filetype = (!isset($filetype)) ? false : (array)$filetype; 14 | $extension = (!isset($extension)) ? false : (array)$extension; 15 | 16 | foreach($files as $file) { 17 | 18 | if($file->type() == 'content') continue; 19 | if($filetype && !in_array($file->type(), $filetype)) continue; 20 | if($extension && !in_array($file->extension(), $extension)) continue; 21 | 22 | $options[$file->filename()] = $file->filename(); 23 | 24 | } 25 | 26 | ?> 27 | -------------------------------------------------------------------------------- /fields/fileselect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fileselect", 3 | "readable": "Fileselect", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Panel field to add a page's file to an extra field", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/", 9 | 10 | "dependencies": { 11 | "panel": "0.8" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fields/fileselect/readme.mdown: -------------------------------------------------------------------------------- 1 | # Kirby Panel Fileselect field 2 | 3 | ## What is this 4 | 5 | This is a custom fileselect field for the Kirby panel, which makes it easy to select an uploaded file from the current page and add it to your content txt as a separate field. 6 | 7 | ## Installation 8 | 9 | If not already exists, add a fields folder to your `site/panel` folder and copy the entire tags field folder there. Your structure should look like this: 10 | 11 | site 12 | panel 13 | fields 14 | fileselect 15 | fileselect.css 16 | fileselect.php 17 | 18 | ## In your blueprints 19 | 20 | As soon as you dropped the fileselect field into your panel folder you can use it in your blueprints: 21 | 22 | fields: 23 | file: 24 | label: My File 25 | type: fileselect 26 | 27 | This will render a select field with all available files for the current page. 28 | 29 | ## Options 30 | 31 | ### empty 32 | 33 | Add a first "empty" option to the select field with a custom label. This makes it possible to not select a file at all. 34 | 35 | #### Example 36 | 37 | fields: 38 | file: 39 | label: My File 40 | type: fileselect 41 | empty: Select a file 42 | 43 | 44 | ### filetype 45 | 46 | Filter the list of files, which are used for the select field by filetype. Available filetypes are image, video, document, sound, other. You can specify more than just one type 47 | 48 | #### Example 49 | 50 | fields: 51 | file: 52 | label: My File 53 | type: fileselect 54 | filetype: 55 | - document 56 | 57 | ### extension 58 | 59 | Filter the list of files, which are used for the select field by extension. You can specify more than just on extension and even combine this with filetype filtering for more control 60 | 61 | #### Example 62 | 63 | fields: 64 | file: 65 | label: My File 66 | type: fileselect 67 | extension: 68 | - jpg 69 | - png -------------------------------------------------------------------------------- /fields/tags/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /fields/tags/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tags", 3 | "readable": "Tags", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Panel field to add tags to a page", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/", 9 | 10 | "dependencies": { 11 | "panel": "0.8" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fields/tags/readme.mdown: -------------------------------------------------------------------------------- 1 | # Kirby Panel Tag field 2 | 3 | ## What is this 4 | 5 | This is a custom tag field for the Kirby panel, which makes it easy to add multiple tags or other kinds of multiple entries to a single Kirby page. Content will be added in a comma-separated list. The tag field includes a nice javascript plugin, which is similar to Facebook's User input or Tags on the Mac. It also includes autocompletion. 6 | 7 | ## Installation 8 | 9 | If not already exists, add a fields folder to your `site/panel` folder and copy the entire tags field folder there. Your structure should look like this: 10 | 11 | site 12 | panel 13 | fields 14 | tags 15 | tags.css 16 | tags.js 17 | tags.php 18 | 19 | ## In your blueprints 20 | 21 | As soon as you dropped the tags field into your panel folder you can use it in your blueprints: 22 | 23 | fields: 24 | tags: 25 | label: My Tags 26 | type: tags 27 | 28 | This will render the default tags field and will look at sibling pages for matching tag suggestions. You got a bunch of options to customize the field though. 29 | 30 | ## Options 31 | 32 | ### index 33 | 34 | You can choose between three different options where to get tag suggestions from: 35 | 36 | 1. siblings 37 | 38 | The plugin will check all siblings in the same parent folder to look for tag suggestions. It will collect a unique list of tags from all the other pages 39 | 40 | 2. template 41 | 42 | The plugin will check through all pages of your site and select tags from those with the same template – no matter where they are located. It will collect a unique list of tags. 43 | 44 | 3. all 45 | 46 | The plugin will fetch tags from all pages 47 | 48 | #### Example 49 | 50 | fields: 51 | tags: 52 | label: My Tags 53 | type: tags 54 | index: template 55 | 56 | 57 | ### field 58 | 59 | You can choose which field will be used to get tags from other pages. This makes it possible to not only use the tags field for – well, tags – but for all kinds of data from your site 60 | 61 | #### Example 62 | 63 | fields: 64 | tags: 65 | label: My Tags 66 | type: tags 67 | index: template 68 | field: title 69 | 70 | (This will pull titles from all pages with the same template as auto-suggestions) 71 | 72 | ### lower 73 | 74 | For tags it's often useful to automatically lowercase all tags. You can use this option to do that: 75 | 76 | #### Example 77 | 78 | fields: 79 | tags: 80 | label: My Tags 81 | type: tags 82 | lower: true 83 | 84 | (the resulting tag string will be completely lowercase) 85 | 86 | ### Separator 87 | 88 | Maybe you don't want to separate your data by comma. Set the separator character here. 89 | 90 | #### Example 91 | 92 | fields: 93 | tags: 94 | label: My Tags 95 | type: tags 96 | separator: ; 97 | 98 | ### data 99 | 100 | If you don't want to fetch suggestions from other pages, you can set your own array of strings, which will be used for autocompletion 101 | 102 | #### Example 103 | 104 | fields: 105 | tags: 106 | label: My Tags 107 | type: tags 108 | data: 109 | - design 110 | - architecture 111 | - photography 112 | - development 113 | - web 114 | 115 | -------------------------------------------------------------------------------- /fields/tags/tags.css: -------------------------------------------------------------------------------- 1 | /* autocomplete style */ 2 | .autocomplete { 3 | position: absolute; 4 | padding-top: 5px; 5 | z-index: 1000; 6 | } 7 | .autocomplete * { 8 | padding: 0; 9 | margin: 0; 10 | } 11 | .autocomplete ul:before { 12 | position: absolute; 13 | top: -5px; 14 | left: 10px; 15 | content: ""; 16 | border-left: 5px solid transparent; 17 | border-right: 5px solid transparent; 18 | border-bottom: 5px solid #222; 19 | } 20 | .autocomplete ul { 21 | position: relative; 22 | padding: 4px; 23 | background: #222; 24 | color: #fff; 25 | min-width: 150px; 26 | -webkit-border-radius: 3px; 27 | -moz-border-radius: 3px; 28 | border-radius: 3px; 29 | -webkit-box-shadow: rgba(0,0,0, .1) 0px 3px 5px; 30 | -moz-box-shadow: rgba(0,0,0, .1) 0px 3px 5px; 31 | box-shadow: rgba(0,0,0, .1) 0px 3px 5px; 32 | } 33 | .autocomplete li { 34 | list-style: none; 35 | text-align: left; 36 | padding: 4px 50px 4px 10px; 37 | cursor: pointer; 38 | margin-bottom: 1px; 39 | background: #333; 40 | } 41 | .autocomplete li:last-child { 42 | border-bottom: none; 43 | margin-bottom: 0; 44 | } 45 | .autocomplete li.selected, 46 | .autocomplete li.over { 47 | background: red; 48 | color: #fff; 49 | } 50 | 51 | 52 | /* tagbox styles */ 53 | .tagbox { 54 | position: relative; 55 | overflow: hidden; 56 | background: #f9f9f9; 57 | border: 1px solid #ddd; 58 | -webkit-border-radius: 3px; 59 | -moz-border-radius: 3px; 60 | border-radius: 3px; 61 | -webkit-box-shadow: #fff 0px 1px 0px; 62 | -moz-box-shadow: #fff 0px 1px 0px; 63 | box-shadow: #fff 0px 1px 0px; 64 | margin-right: -20px; 65 | } 66 | .tagbox * { 67 | margin: 0; 68 | padding: 0; 69 | } 70 | .tagbox.focus{ 71 | outline: 0; 72 | } 73 | .tagbox ul { 74 | overflow: hidden; 75 | padding: 10px 10px 6px 10px; 76 | -webkit-border-radius: 2px; 77 | -moz-border-radius: 2px; 78 | border-radius: 2px; 79 | -webkit-box-shadow: rgba(0,0,0,.07) 0px 2px 4px inset; 80 | -moz-box-shadow: rgba(0,0,0,.07) 0px 2px 4px inset; 81 | box-shadow: rgba(0,0,0,.07) 0px 2px 4px inset; 82 | } 83 | .tagbox li { 84 | position: relative; 85 | list-style: none; 86 | float: left; 87 | cursor: pointer; 88 | margin: 0 4px 4px 0; 89 | } 90 | .tagbox li.new input { 91 | font-family: Arial, sans-serif; 92 | border: none; 93 | display: block; 94 | height: 20px; 95 | line-height: 20px; 96 | font-size: 12px; 97 | background: none; 98 | } 99 | .tagbox li.new input:focus { 100 | outline: none; 101 | } 102 | .tagbox li .tag { 103 | position: relative; 104 | display: block; 105 | background: #222; 106 | color: #fff; 107 | border-radius: 20px; 108 | height: 20px; 109 | line-height: 20px; 110 | font-size-adjust: 100%; 111 | font-size: 12px; 112 | padding: 0 30px 0 12px; 113 | vertical-align: middle; 114 | } 115 | .tagbox li .delete { 116 | position: absolute; 117 | font-family: Arial, sans-serif; 118 | right: 7px; 119 | top: 4px; 120 | color: #fff; 121 | z-index: 100; 122 | cursor: pointer; 123 | color: #222; 124 | background: #fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAMAAACeL25MAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////QkJCfEGH6wAAABRJREFUeNpiYGRgACEgBhMgBBBgAABkAAl7vFkJAAAAAElFTkSuQmCC) no-repeat center center; 125 | width: 12px; 126 | text-indent: -6000px; 127 | font-size: 11px; 128 | line-height: 12px; 129 | height: 12px; 130 | text-align: center; 131 | -webkit-border-radius: 20px; 132 | -moz-border-radius: 20px; 133 | border-radius: 20px; 134 | } 135 | .tagbox .selected .tag { 136 | background: red; 137 | } -------------------------------------------------------------------------------- /fields/tags/tags.php: -------------------------------------------------------------------------------- 1 | pages()->active(); 7 | 8 | // define the separating character 9 | $separator = (isset($separator)) ? $separator : ','; 10 | 11 | // field to fetch existing tags from 12 | $field = (isset($field)) ? $field : $name; 13 | 14 | // lowercase all tags 15 | $lower = (isset($lower)) ? $lower : false; 16 | 17 | // use passed data if available or try to fetch data 18 | if(!isset($data) || !is_array($data)) { 19 | 20 | $data = array(); 21 | $store = array(); 22 | 23 | if(!isset($index)) $index = 'siblings'; 24 | 25 | switch($index) { 26 | case 'template': 27 | foreach($site->pages()->index() as $p) { 28 | if($p->template() == $page->template()) $store[] = $p; 29 | } 30 | break; 31 | case 'all': 32 | $store = $site->pages()->index(); 33 | break; 34 | case 'siblings': 35 | $store = $page->siblings(); 36 | break; 37 | } 38 | 39 | // get all tags 40 | foreach($store as $s) { 41 | $data = array_merge($data, str::split($s->{$field}, $separator)); 42 | } 43 | 44 | } 45 | 46 | // make sure we get a nice array 47 | $data = array_values(array_unique($data)); 48 | sort($data); 49 | 50 | ?> 51 | 52 | 53 | 62 | -------------------------------------------------------------------------------- /plugins/auth/accounts/demo.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | # setup your account credentials here 4 | # it's highly recommended to use md5 or sha1 encryption 5 | # for your passwords. read more about encryption in the 6 | # docs: http://getkirby.com/docs/panel/accounts 7 | 8 | username: demo 9 | password: demo 10 | group: admin -------------------------------------------------------------------------------- /plugins/auth/auth.php: -------------------------------------------------------------------------------- 1 | 'error', 25 | 'msg' => l::get('auth.error', 'Invalid username or password') 26 | ); 27 | 28 | // check for matching usernames 29 | if(str::lower($account->username()) != str::lower($username)) return array( 30 | 'status' => 'error', 31 | 'msg' => l::get('auth.error', 'Invalid username or password') 32 | ); 33 | 34 | // check for a matching password 35 | if(!self::checkPassword($account, $password)) return array( 36 | 'status' => 'error', 37 | 'msg' => l::get('auth.error', 'Invalid username or password') 38 | ); 39 | 40 | // generate a random token 41 | $token = str::random(); 42 | 43 | // add the username. 44 | $account->token = $token; 45 | 46 | // store the token in the cookie 47 | // and the user data in the session 48 | cookie::set('authFrontend', $token, 60*60*24); 49 | s::set('authFrontend.' . $token, $account->username()); 50 | 51 | go(url($redirect)); 52 | 53 | } 54 | 55 | static function user() { 56 | 57 | if(!is_null(self::$user)) return self::$user; 58 | 59 | $token = cookie::get('authFrontend'); 60 | 61 | if(empty($token)) return self::$user = false; 62 | 63 | $username = s::get('authFrontend.' . $token, false); 64 | 65 | if(empty($username)) return self::$user = false; 66 | 67 | $account = self::load($username); 68 | 69 | // make sure to remove the password 70 | // because this should never be visible to anybody 71 | unset($account->_['password']); 72 | 73 | if(empty($account) || $account->username() != $username) return self::$user = false; 74 | 75 | $account->token = $token; 76 | return self::$user = $account; 77 | 78 | } 79 | 80 | static protected function kill() { 81 | 82 | self::$user = null; 83 | 84 | // overwrite the token 85 | $token = str::random(); 86 | // the cookie is valid for 24 hours 87 | cookie::set('authFrontend', $token, 60*60*24); 88 | 89 | // restart the session 90 | s::restart(); 91 | 92 | } 93 | 94 | static public function logout($redirect = 'login') { 95 | 96 | self::kill(); 97 | 98 | // go to the homepage 99 | go(url($redirect)); 100 | 101 | } 102 | 103 | static public function firewall($params = array()) { 104 | 105 | global $site; 106 | 107 | $defaults = array( 108 | 'ignore' => array('login', 'logout'), 109 | 'redirect' => 'login', 110 | 'allow' => array(), 111 | 'deny' => array(), 112 | 'logout' => true, 113 | ); 114 | 115 | $options = array_merge($defaults, $params); 116 | $page = $site->pages()->active(); 117 | 118 | if(in_array($page->uid(), $options['ignore'])) return true; 119 | 120 | // get the current user 121 | $user = self::user(); 122 | 123 | if(!$user) { 124 | if($options['logout']) self::kill(); 125 | go(url($options['redirect'])); 126 | } 127 | 128 | $allowed = false; 129 | 130 | if(is_string($options['allow'])) $options['allow'] = array($options['allow']); 131 | if(is_string($options['deny'])) $options['deny'] = array($options['deny']); 132 | 133 | if(empty($options['allow'])) { 134 | $allowed = true; 135 | } else { 136 | 137 | foreach($options['allow'] as $allow) { 138 | 139 | // user 140 | if(preg_match('!^user:!', $allow)) { 141 | $username = str_replace('user:', '', $allow); 142 | 143 | if(str::lower($username) == str::lower($user->username())) { 144 | $allowed = true; 145 | break; 146 | } 147 | 148 | } else if(preg_match('!^group:!', $allow)) { 149 | $group = str_replace('group:', '', $allow); 150 | 151 | if($user->group() != '' && str::lower($group) == str::lower($user->group())) { 152 | $allowed = true; 153 | break; 154 | } 155 | 156 | } 157 | 158 | } 159 | 160 | } 161 | 162 | // deny loop 163 | 164 | foreach($options['deny'] as $allow) { 165 | 166 | // user 167 | if(preg_match('!^user:!', $allow)) { 168 | $username = str_replace('user:', '', $allow); 169 | 170 | if(str::lower($username) == str::lower($user->username())) { 171 | $allowed = false; 172 | break; 173 | } 174 | 175 | } else if(preg_match('!^group:!', $allow)) { 176 | $group = str_replace('group:', '', $allow); 177 | 178 | if($user->group() != '' && str::lower($group) == str::lower($user->group())) { 179 | $allowed = false; 180 | break; 181 | } 182 | 183 | } 184 | 185 | } 186 | 187 | 188 | if(!$allowed) { 189 | if($options['logout']) self::kill(); 190 | go(url($options['redirect'])); 191 | } 192 | 193 | return true; 194 | 195 | } 196 | 197 | static protected function load($username) { 198 | 199 | $username = str::lower($username); 200 | 201 | $dir = c::get('root.site') . '/accounts'; 202 | $file = $dir . '/' . $username . '.php'; 203 | 204 | if(!is_dir($dir) || !file_exists($file)) return false; 205 | 206 | $content = file_get_contents($file); 207 | $yaml = yaml($content); 208 | 209 | // remove the php direct access protection line 210 | unset($yaml[0]); 211 | 212 | return new AuthUser($yaml); 213 | 214 | } 215 | 216 | static protected function checkPassword($user, $password) { 217 | 218 | // check for empty passwords 219 | if(empty($password) || $user->password() == '') return false; 220 | 221 | // get the encryption 222 | $encryption = $user->encrypt(); 223 | 224 | // handle the different 225 | // encryption types 226 | switch($encryption) { 227 | // sha1 encoded 228 | case 'sha1': 229 | return (sha1($password) == $user->password()) ? true : false; 230 | break; 231 | // md5 encoded 232 | case 'md5': 233 | return (md5($password) == $user->password()) ? true : false; 234 | break; 235 | // plain passwords 236 | default: 237 | return ($password == $user->password()) ? true : false; 238 | break; 239 | } 240 | 241 | // we should never get here 242 | // but let's make sure 243 | return false; 244 | 245 | } 246 | 247 | } 248 | 249 | class AuthUser extends obj { 250 | 251 | 252 | } 253 | -------------------------------------------------------------------------------- /plugins/auth/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/auth/content/login/login.txt: -------------------------------------------------------------------------------- 1 | Title: Login 2 | -------------------------------------------------------------------------------- /plugins/auth/content/logout/logout.txt: -------------------------------------------------------------------------------- 1 | Title: Logout 2 | -------------------------------------------------------------------------------- /plugins/auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auth", 3 | "readable": "Authentication", 4 | "version": "1.0", 5 | "stable": false, 6 | "description": "Restrict user access to frontend pages", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/auth/readme.mdown: -------------------------------------------------------------------------------- 1 | # Authentication Plugin 2 | 3 | ## What is it? 4 | 5 | The Authentication plugin makes it possible to create user accounts and user groups for your website and restrict access to certain parts. 6 | 7 | ## Installation 8 | 9 | - Copy the `auth` folder to your `site/plugins` folder. 10 | - Copy `auth/snippets/login.php` to your `snippets` folder and optionally customize it 11 | - Create an invisible `content/login` folder with a `login.txt` 12 | - Create a `login.php` template in `site/templates` and include the login form snippet. I.e.: 13 | 14 | ``` 15 | 16 | 17 | 18 | 19 | 20 | ``` 21 | 22 | - Create an invisible `content/logout` folder with a `logout.txt` 23 | - Crate a `logout.php` template in `site/templates`: 24 | 25 | ``` 26 | 27 | ``` 28 | 29 | - Create an `site/accounts` folder and add your first user account. Use the username as filename (ie. `yourusername.php`). 30 | 31 | ``` 32 | 33 | 34 | # setup your account credentials here 35 | # it's highly recommended to use md5 or sha1 encryption 36 | # for your passwords. read more about encryption in the 37 | # docs: http://getkirby.com/docs/panel/accounts 38 | 39 | username: yourusername 40 | password: yourpassword 41 | group: optional-group-name 42 | ``` 43 | 44 | Now you have a fully functional login/logout system. 45 | 46 | ## Setting up the firewall 47 | 48 | ### Full restriction 49 | 50 | If you want to restrict access to all your pages, I recommend to add the firewall to your `header.php` snippet: 51 | 52 | ``` 53 | 54 | ``` 55 | 56 | This will block access to all pages for all unauthenticated users. 57 | 58 | 59 | ### Restriction per template 60 | 61 | If you want to fine-tune access to certain templates you should add the firewall as the first line of each template, which should have restricted access. 62 | 63 | ### General blocking + fine-tuning 64 | 65 | As a third alternative you can setup a general firewall in the header.php snippet and an additional firewall for single templates. This will give you full control over who can access what. 66 | 67 | ## Customizing the firewall 68 | 69 | The firewall has a bunch of settings, which can be used to give access to certain users or groups 70 | 71 | ### redirect (default: login) 72 | 73 | By default the firewall is redirecting to the login page, but you can change the redirect url with this option: 74 | 75 | // This firewall will redirect to the homepage 76 | Auth::firewall(array( 77 | 'redirect' => '/' 78 | )); 79 | 80 | // This firewall will redirect to the error page 81 | Auth::firewall(array( 82 | 'redirect' => 'error' 83 | )); 84 | 85 | ### logout (default: true) 86 | 87 | By default the firewall will logout users which are not allowed to access the current page. You can change this here: 88 | 89 | // This firewall will just redirect but not logout 90 | Auth::firewall(array( 91 | 'logout' => false 92 | )); 93 | 94 | 95 | ### allow 96 | 97 | By default the firewall will allow access to all available users and groups. You can fine-tune this here: 98 | 99 | // This firewall will only grant access to the user "yourusername" 100 | Auth::firewall(array( 101 | 'allow' => array('user:yourusername') 102 | )); 103 | 104 | // This firewall will only grant access to users in the group "admin" 105 | Auth::firewall(array( 106 | 'allow' => array('group:admin') 107 | )); 108 | 109 | // This firewall will only grant access to users in the group "admin" and a user "bart" 110 | Auth::firewall(array( 111 | 'allow' => array('group:admin', 'user:bart') 112 | )); 113 | 114 | ### deny 115 | 116 | You can also deny certain users or groups 117 | 118 | Auth::firewall(array( 119 | 'deny' => array('user:yourusername', 'group:editors') 120 | )); 121 | 122 | Deny will overwrite allow rules. 123 | 124 | ## The login snippet 125 | 126 | The login snippet should be customized to fit your needs for the login form. 127 | The Auth::login() method will always be needed in the first line to make the form work. 128 | You can set the redirect URL, which will be used to redirect users after a successful login. 129 | By default users will be taken to the homepage: 130 | 131 | 132 | 133 | ## The logout template 134 | 135 | In the logout template you are also able to specify the redirect URL after logouts like this: 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /plugins/auth/snippets/login.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 | Invalid username or password 8 |
9 | 10 | 11 |
12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 | -------------------------------------------------------------------------------- /plugins/auth/templates/login.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 | 8 | -------------------------------------------------------------------------------- /plugins/auth/templates/logout.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /plugins/color/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/color/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "color", 3 | "readable": "Color", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "A class to work with colors", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/color/readme.mdown: -------------------------------------------------------------------------------- 1 | # Color -------------------------------------------------------------------------------- /plugins/contactform/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.1 4 | + Initial release -------------------------------------------------------------------------------- /plugins/contactform/contactform.php: -------------------------------------------------------------------------------- 1 | defaults(); 11 | 12 | // set required and wanted fields 13 | $this->defaults('required', array('name', 'email', 'text')); 14 | $this->defaults('keep', array('name', 'email', 'text')); 15 | 16 | // set the default subject 17 | $this->defaults('subject', 'New contact form submission'); 18 | 19 | // take the current URL as the default goto URL 20 | $this->defaults('goto', $_SERVER['REQUEST_URI']); 21 | 22 | // set a custom validation event 23 | $this->defaults('validate', function($self) { 24 | // validate the email address 25 | if(!filter_var($self->value('email'), FILTER_VALIDATE_EMAIL)) $self->addInvalid('email'); 26 | }); 27 | 28 | // try to send the email 29 | $this->defaults('submit', function($self) { 30 | 31 | $to = $self->option('to'); 32 | $from = $self->option('from'); 33 | 34 | if(!$from) $self->option('from', $to); 35 | 36 | // set the email body 37 | $self->option('body', $self->body()); 38 | 39 | // send the email form, pass all options 40 | $send = email($self->options); 41 | 42 | if(error($send)) { 43 | $self->addInvalid('send'); 44 | return $self->trigger('error'); 45 | } 46 | 47 | $self->trigger('success'); 48 | 49 | }); 50 | 51 | // redirect to the "goto" url on success 52 | $this->defaults('success', function($self) { 53 | // redirect to callback url 54 | $url = $self->option('goto'); 55 | if (!empty($url)) { 56 | go($self->option('goto')); 57 | } 58 | }); 59 | 60 | // merge the defaults with the given options 61 | $this->options($params); 62 | 63 | // trigger the request 64 | $this->trigger('request'); 65 | 66 | } 67 | 68 | function body() { 69 | 70 | $body = $this->option('body'); 71 | 72 | if(empty($body)) { 73 | 74 | $body = snippet('contactform.mail', array(), true); 75 | 76 | if(empty($body)) { 77 | $body = 'Name: {name}' . PHP_EOL; 78 | $body .= '---------' . PHP_EOL; 79 | $body .= 'Email: {email}' . PHP_EOL; 80 | $body .= '---------' . PHP_EOL; 81 | $body .= 'Text: {text}' . PHP_EOL; 82 | } 83 | } 84 | 85 | foreach($this->data() as $key => $value) { 86 | $body = str_replace('{' . $key . '}', $value, $body); 87 | } 88 | 89 | return trim($body); 90 | 91 | } 92 | 93 | function htmlBody() { 94 | return nl2br(html($this->body())); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /plugins/contactform/lib/email.php: -------------------------------------------------------------------------------- 1 | 'John Doe ', 28 | * 'from' => 'Your Name ', 29 | * 'subject' => 'My first Email', 30 | * 'body' => 'Hello my friend! How are things going?' 31 | * )); 32 | * 33 | * Author: Bastian Allgeier 34 | * License: MIT License 35 | * 36 | */ 37 | 38 | 39 | function email($params=array()) { 40 | $email = new email($params); 41 | return $email->send(); 42 | } 43 | 44 | 45 | class email { 46 | 47 | var $options = array(); 48 | 49 | function __construct($params=array()) { 50 | 51 | $defaults = array( 52 | // global defaults 53 | 'use' => c::get('email.use', 'mail'), 54 | 'from' => c::get('email.from'), 55 | 'replyto' => c::get('email.replyto'), 56 | 'subject' => c::get('email.subject'), 57 | 'to' => c::get('email.to'), 58 | 59 | // postmark api defaults 60 | 'postmark.key' => c::get('email.postmark.key'), 61 | 'postmark.test' => c::get('email.postmark.test'), 62 | 63 | // amazon api defaults 64 | 'amazon.key' => c::get('email.amazon.key'), 65 | 'amazon.secret' => c::get('email.amazon.secret'), 66 | ); 67 | 68 | $this->options = array_merge($defaults, $params); 69 | 70 | // set the from address as the replyto address if no replyto address is specified 71 | if(empty($this->options['replyto'])) $this->options['replyto'] = $this->options['from']; 72 | 73 | } 74 | 75 | public function send() { 76 | 77 | if(c::get('email.disabled')) return array( 78 | 'status' => 'error', 79 | 'msg' => l::get('email.disabled', 'Email has been disabled') 80 | ); 81 | 82 | if(!v::email($this->extractAddress($this->options['from']))) return array( 83 | 'status' => 'error', 84 | 'msg' => l::get('email.error.invalid.sender', 'Invalid sender'), 85 | ); 86 | 87 | if(!v::email($this->extractAddress($this->options['to']))) return array( 88 | 'status' => 'error', 89 | 'msg' => l::get('email.error.invalid.recipient', 'Invalid recipient'), 90 | ); 91 | 92 | if(!v::email($this->extractAddress($this->options['replyto']))) return array( 93 | 'status' => 'error', 94 | 'msg' => l::get('email.error.invalid.replyto', 'Invalid Reply-To Address'), 95 | ); 96 | 97 | if(str::length($this->options['subject']) == 0) return array( 98 | 'status' => 'error', 99 | 'msg' => l::get('email.error.invalid.subject', 'The subject is missing'), 100 | ); 101 | 102 | $method = 'sendWith' . str::ucfirst($this->options['use']); 103 | 104 | if(!method_exists(__CLASS__, $method)) return array( 105 | 'status' => 'error', 106 | 'msg' => l::get('email.error.invalid.mailer', 'This email service is not supported'), 107 | ); 108 | 109 | return $this->$method(); 110 | 111 | } 112 | 113 | private function sendWithPostmark() { 114 | 115 | if(!$this->options['postmark.key']) return array( 116 | 'status' => 'error', 117 | 'msg' => l::get('email.error.invalid.key', 'Invalid API key'), 118 | ); 119 | 120 | // reset the api key if we are in test mode 121 | if($this->options['postmark.test']) $this->options['postmark.key'] = 'POSTMARK_API_TEST'; 122 | 123 | $url = 'http://api.postmarkapp.com/email'; 124 | 125 | $headers = array( 126 | 'Accept: application/json', 127 | 'Content-Type: application/json', 128 | 'X-Postmark-Server-Token: ' . $this->options['postmark.key'] 129 | ); 130 | 131 | $data = array( 132 | 'From' => $this->options['from'], 133 | 'To' => $this->options['to'], 134 | 'ReplyTo' => $this->options['replyto'], 135 | 'Subject' => $this->options['subject'], 136 | 'TextBody' => $this->options['body'] 137 | ); 138 | 139 | $response = $this->post($url, a::json($data), array('headers' => $headers)); 140 | $code = @$response['http_code']; 141 | 142 | if($code != 200) return array( 143 | 'status' => 'error', 144 | 'msg' => l::get('email.error', 'The mail could not be sent!'), 145 | 'response' => $response 146 | ); 147 | 148 | return array( 149 | 'status' => 'success', 150 | 'msg' => l::get('email.success', 'The mail has been sent'), 151 | 'response' => $response 152 | ); 153 | 154 | } 155 | 156 | private function sendWithAmazon() { 157 | 158 | if(!$this->options['amazon.key']) return array( 159 | 'status' => 'error', 160 | 'msg' => l::get('email.error.invalid.key', 'Invalid API key'), 161 | ); 162 | 163 | if(!$this->options['amazon.secret']) return array( 164 | 'status' => 'error', 165 | 'msg' => l::get('email.error.invalid.secret', 'Invalid API secret'), 166 | ); 167 | 168 | $setup = array( 169 | 'Action' => 'SendEmail', 170 | 'Destination.ToAddresses.member.1' => $this->options['to'], 171 | 'ReplyToAddresses.member.1' => $this->options['replyto'], 172 | 'ReturnPath' => $this->options['replyto'], 173 | 'Source' => $this->options['from'], 174 | 'Message.Subject.Data' => $this->options['subject'], 175 | 'Message.Body.Text.Data' => $this->options['body'] 176 | ); 177 | 178 | $params = array(); 179 | 180 | foreach($setup as $key => $value) { 181 | $params[] = $key . '=' . str_replace('%7E', '~', rawurlencode($value)); 182 | } 183 | 184 | sort($params, SORT_STRING); 185 | 186 | $host = 'email.us-east-1.amazonaws.com'; 187 | $url = 'https://' . $host . '/'; 188 | $date = gmdate('D, d M Y H:i:s e'); 189 | $signature = base64_encode(hash_hmac('sha256', $date, $this->options['amazon.secret'], true)); 190 | $query = implode('&', $params); 191 | $headers = array(); 192 | 193 | $auth = 'AWS3-HTTPS AWSAccessKeyId=' . $this->options['amazon.key']; 194 | $auth .= ',Algorithm=HmacSHA256,Signature=' . $signature; 195 | 196 | $headers[] = 'Date: ' . $date; 197 | $headers[] = 'Host: ' . $host; 198 | $headers[] = 'X-Amzn-Authorization: '. $auth; 199 | $headers[] = 'Content-Type: application/x-www-form-urlencoded'; 200 | 201 | $response = $this->post($url, $query, array('headers' => $headers)); 202 | $code = @$response['http_code']; 203 | 204 | if(!in_array($code, array(200, 201, 202, 204))) return array( 205 | 'status' => 'error', 206 | 'msg' => l::get('email.error', 'The mail could not be sent!'), 207 | 'response' => $response 208 | ); 209 | 210 | return array( 211 | 'status' => 'success', 212 | 'msg' => l::get('email.success', 'The mail has been sent'), 213 | 'response' => $response 214 | ); 215 | 216 | } 217 | 218 | private function sendWithMail() { 219 | 220 | $headers = array(); 221 | 222 | $headers[] = 'From: ' . $this->options['from']; 223 | $headers[] = 'Reply-To: ' . $this->options['replyto']; 224 | $headers[] = 'Return-Path: ' . $this->options['replyto']; 225 | $headers[] = 'Message-ID: <' . time() . '-' . $this->options['from'] . '>'; 226 | $headers[] = 'X-Mailer: PHP v' . phpversion(); 227 | $headers[] = 'Content-Type: text/plain; charset=utf-8'; 228 | $headers[] = 'Content-Transfer-Encoding: 8bit'; 229 | 230 | ini_set('sendmail_from', $this->options['from']); 231 | $send = mail($this->options['to'], str::utf8($this->options['subject']), str::utf8($this->options['body']), implode("\r\n", $headers)); 232 | ini_restore('sendmail_from'); 233 | 234 | if(!$send) return array( 235 | 'status' => 'error', 236 | 'msg' => l::get('email.error', 'The mail could not be sent!') 237 | ); 238 | 239 | return array( 240 | 'status' => 'success', 241 | 'msg' => l::get('email.success', 'The mail has been sent') 242 | ); 243 | 244 | } 245 | 246 | private function extractAddress($string) { 247 | if(v::email($string)) return $string; 248 | preg_match('/<(.*?)>/i', $string, $array); 249 | $address = @$array[1]; 250 | return (v::email($address)) ? $address : false; 251 | } 252 | 253 | private function post($url, $data=false, $options=array()) { 254 | 255 | $data = (is_array($data)) ? http_build_query($data) : $data; 256 | 257 | $defaults = array( 258 | 'timeout' => 10, 259 | 'headers' => array(), 260 | 'agent' => 'email/php', 261 | 'encoding' => 'utf-8' 262 | ); 263 | 264 | $options = array_merge($defaults, $options); 265 | $ch = curl_init(); 266 | 267 | $params = array( 268 | CURLOPT_URL => $url, 269 | CURLOPT_RETURNTRANSFER => true, 270 | CURLOPT_FOLLOWLOCATION => true, 271 | CURLOPT_ENCODING => $options['encoding'], 272 | CURLOPT_AUTOREFERER => true, 273 | CURLOPT_USERAGENT => $options['agent'], 274 | CURLOPT_CONNECTTIMEOUT => $options['timeout'], 275 | CURLOPT_TIMEOUT => $options['timeout'], 276 | CURLOPT_MAXREDIRS => 10, 277 | CURLOPT_SSL_VERIFYPEER => false, 278 | CURLOPT_SSL_VERIFYHOST => false, 279 | CURLOPT_POST => true, 280 | CURLOPT_POSTFIELDS => $data 281 | ); 282 | 283 | if(!empty($options['headers'])) $params[CURLOPT_HTTPHEADER] = $options['headers']; 284 | 285 | curl_setopt_array($ch, $params); 286 | 287 | $content = curl_exec($ch); 288 | $error = curl_errno($ch); 289 | $message = curl_error($ch); 290 | $response = curl_getinfo($ch); 291 | 292 | curl_close($ch); 293 | 294 | $response['error'] = $error; 295 | $response['message'] = $message; 296 | $response['content'] = $content; 297 | 298 | if(a::get($response, 'error')) return array( 299 | 'status' => 'error', 300 | 'msg' => 'The remote request failed: ' . $response['message'], 301 | 'response' => $response 302 | ); 303 | 304 | if(a::get($response, 'http_code') >= 400) return array( 305 | 'status' => 'error', 306 | 'msg' => 'The remote request failed - code: ' . $response['http_code'], 307 | 'code' => $response['http_code'], 308 | 'response' => $response 309 | ); 310 | 311 | return $response; 312 | 313 | } 314 | 315 | } -------------------------------------------------------------------------------- /plugins/contactform/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "contactform", 3 | "readable": "Contactform", 4 | "version": "0.1", 5 | "stable": false, 6 | "description": "Render and submit a simple contact form", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/contactform/readme.mdown: -------------------------------------------------------------------------------- 1 | # Contactform Plugin & Snippets (Alpha) 2 | 3 | This plugin helps you render and submit a simple contact form with name, email and text 4 | 5 | ## Installation 6 | Put the `contactform` folder in your `site/plugins` folder. If the `site/plugins` folder doesn't exist yet, create it. 7 | 8 | ### Installing snippets 9 | Copy the snippets from `snippets/contactform` in this repo and add them to `site/snippets`, don't create a subfolder in `site/snippets`. 10 | 11 | ### Add the contact form 12 | 13 | To add the contact form to your site, add the contactform snippet to your templates: 14 | 15 | ``` 16 | 17 | 18 | 19 | ``` 20 | 21 | ### Contact form settings 22 | 23 | Open `site/snippets/contactform.php` to set your email address and other options for the contact form: 24 | 25 | ``` 26 | 27 | $form = new contactform(array( 28 | 'to' => 'John ', 29 | 'from' => 'Contact Form ', 30 | 'subject' => 'New contact form request', 31 | 'goto' => $page->url() . '/status:thank-you' 32 | )); 33 | 34 | ``` 35 | 36 | You can also customize the HTML for the contact form however you need. 37 | 38 | ### Changing the email template 39 | 40 | Open `site/snippets/contactform.mail.php` to customize the email template. The contact form plugin will only send plain text emails. You can use the following placeholders in your template: 41 | 42 | ``` 43 | 44 | {name} 45 | {email} 46 | {text} 47 | 48 | ``` 49 | 50 | ## Requirements 51 | 52 | Since the plugin works with PHP closures, you need to run your site on PHP 5.3 + Older versions are not supported 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /plugins/contactform/snippets/contactform.mail.php: -------------------------------------------------------------------------------- 1 | Hey, 2 | 3 | your contact form has been submitted 4 | 5 | Name: {name} 6 | --------- 7 | Email: {email} 8 | --------- 9 | Text: 10 | 11 | {text} -------------------------------------------------------------------------------- /plugins/contactform/snippets/contactform.php: -------------------------------------------------------------------------------- 1 | 'John ', 5 | 'from' => 'Contact Form ', 6 | 'subject' => 'New contact form request', 7 | 'goto' => $page->url() . '/status:thank-you' 8 | )); 9 | 10 | ?> 11 |
12 | 13 | 14 | 15 |

Thank you very much for your request

16 |

We will get in contact as soon as possible

17 | 18 | 19 | 20 |

Get in contact

21 | 22 |
23 |
24 | 25 | isError('send')): ?> 26 |
The email could not be sent. Please try again later.
27 | isError()): ?> 28 |
The form could not be submitted. Please fill in all fields correctly.
29 | 30 | 31 |
32 | 33 | 34 |
35 | 36 |
37 | 38 | 39 |
40 | 41 |
42 | 43 | 44 |
45 | 46 |

All fields with * are required

47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 | 55 |
-------------------------------------------------------------------------------- /plugins/dribbble/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.2 (08.02.12) 4 | + Added Caching (Bastian Allgeier) 5 | 6 | ## Version 1.1 (02.02.12) 7 | + Added the ability to fetch the likes of a user (is turned off by default, to enable set `$_fetch_likes` to `true`, and set `$_number_of_likes` to the number of likes you want to fetch) 8 | + Added the ability to only load the likes and not the shots (set `$_number_of_shots` to `0`) 9 | + Added a function to retreat the username that was passed to the class 10 | * Improved phpdoc 11 | 12 | ## Version 1.0 (28.01.12) 13 | + Initial version -------------------------------------------------------------------------------- /plugins/dribbble/dribbble.php: -------------------------------------------------------------------------------- 1 | plugin for Kirby , that loads the shots of a player. 19 | * @author Simon Albrecht , caching added by Bastian Allgeier 20 | * @version 1.2 21 | * @copyright (c) 2012 Simon Albrecht 22 | */ 23 | class dribbble { 24 | 25 | // Variables 26 | var $username; 27 | var $shots; 28 | var $likes; 29 | var $player; 30 | 31 | /** 32 | * Constructor. Loads the data from Dribbble when the object is constructed. 33 | * @param string $_username The username of the player. 34 | * @param integer $_number_of_shots The number of shots that will be loaded. 35 | * @param boolean $_fetch_likes If the likes of the user should be fetched in a second call. 36 | * @param integer If $_fetch_likes is true, then how many likes should be fetched. 37 | * @param boolean $cache Enable/disable caching. Cache is enabled by default 38 | * @param integer $refresh Seconds before the cache will be refreshed. Default is in hour (3600 seconds) 39 | */ 40 | function __construct($_username = "s_albrecht", $_number_of_shots = 3, $_fetch_likes = false, $_number_of_likes = 3, $cache = true, $refresh = 3600) { 41 | // Init 42 | $this->username = $_username; 43 | $this->shots = array(); 44 | $this->likes = array(); 45 | $this->player = null; 46 | 47 | // Build URLs 48 | $base_url = "http://api.dribbble.com/players/" . $this->username; 49 | $shots_url = $base_url . "/shots"; 50 | $likes_url = $base_url . "/likes"; 51 | 52 | // create the cache directory if not there yet 53 | if($cache) dir::make(c::get('root.cache') . '/dribbble'); 54 | 55 | // Process the data 56 | if ($_number_of_shots > 0) { 57 | 58 | // define a cache id 59 | $shots_cache_id = 'dribbble/shots.' . md5($this->username) . '.' . $_number_of_shots . '.php'; 60 | $shots_cache_data = false; 61 | 62 | // try to fetch the data from cache 63 | if($cache) { 64 | $shots_cache_data = (cache::modified($shots_cache_id) < time()-$refresh) ? false : cache::get($shots_cache_id); 65 | } 66 | 67 | // if there's no data in the cache, load shots from the Dribbble API 68 | if(empty($shots_cache_data)) { 69 | $all_shots = $this->fetch_data($shots_url); 70 | $all_shots = json_decode($all_shots); 71 | $all_shots = $all_shots->shots; 72 | 73 | if($cache) cache::set($shots_cache_id, $all_shots); 74 | 75 | } else { 76 | $all_shots = $shots_cache_data; 77 | } 78 | 79 | // Only proceed if there is at least one shot. 80 | // If there's no shot, then player data can't be extracted from this API call 81 | // and must be extracted via /players/:id/ (maybe I'll implement that later) 82 | if (count($all_shots) > 0) { 83 | 84 | // Load shots data 85 | for ($i = 0; $i < $_number_of_shots; $i++) { 86 | if (!is_null($all_shots[$i])) { 87 | $this->shots[$i]->id = $all_shots[$i]->id; 88 | $this->shots[$i]->title = $all_shots[$i]->title; 89 | $this->shots[$i]->url = $all_shots[$i]->url; 90 | $this->shots[$i]->short_url = $all_shots[$i]->short_url; 91 | $this->shots[$i]->image = $all_shots[$i]->image_url; 92 | $this->shots[$i]->likes = $all_shots[$i]->likes_count; 93 | $this->shots[$i]->views = $all_shots[$i]->views_count; 94 | $this->shots[$i]->rebounds = $all_shots[$i]->rebounds_count; 95 | $this->shots[$i]->comments = $all_shots[$i]->comments_count; 96 | $this->shots[$i]->created = $all_shots[$i]->created_at; 97 | } 98 | } 99 | 100 | // Process player data 101 | $this->player->id = $all_shots[0]->player->id; 102 | $this->player->name = $all_shots[0]->player->name; 103 | $this->player->username = $all_shots[0]->player->username; 104 | $this->player->url = $all_shots[0]->player->url; 105 | $this->player->avatar_url = $all_shots[0]->player->avatar_url; 106 | $this->player->twitter = $all_shots[0]->player->twitter_screen_name; 107 | $this->player->location = $all_shots[0]->player->location; 108 | $this->player->followers = $all_shots[0]->player->followers_count; 109 | $this->player->following = $all_shots[0]->player->following_count; 110 | $this->player->likes = $all_shots[0]->player->likes_count; 111 | } 112 | } 113 | 114 | // Fetch all likes of the user (needs another API call). 115 | // If you only want to fetch the likes, not the shots, then set $_number_of_shots to 0. 116 | if ($_fetch_likes && $_number_of_likes > 0) { 117 | 118 | // define a cache id 119 | $likes_cache_id = 'dribbble/likes.' . md5($this->username) . '.' . $_number_of_likes . '.php'; 120 | $likes_cache_data = false; 121 | 122 | // try to fetch the data from cache 123 | if($cache) { 124 | $likes_cache_data = (cache::modified($likes_cache_id) < time()-$refresh) ? false : cache::get($likes_cache_id); 125 | } 126 | 127 | // if there's no data in the cache, load likes from the Dribbble API 128 | if(empty($likes_cache_data)) { 129 | $all_likes = $this->fetch_data($likes_url); 130 | $all_likes = json_decode($all_likes); 131 | $all_likes = $all_likes->shots; 132 | 133 | if($cache) cache::set($likes_cache_id, $all_likes); 134 | 135 | } else { 136 | $all_likes = $likes_cache_data; 137 | } 138 | 139 | 140 | // Process likes 141 | for ($i = 0; $i < $_number_of_likes; $i++) { 142 | if (!is_null($all_likes[$i])) { 143 | $this->likes[$i]->id = $all_likes[$i]->id; 144 | $this->likes[$i]->title = $all_likes[$i]->title; 145 | $this->likes[$i]->url = $all_likes[$i]->url; 146 | $this->likes[$i]->short_url = $all_likes[$i]->short_url; 147 | $this->likes[$i]->image = $all_likes[$i]->image_url; 148 | $this->likes[$i]->likes = $all_likes[$i]->likes_count; 149 | $this->likes[$i]->views = $all_likes[$i]->views_count; 150 | $this->likes[$i]->rebounds = $all_likes[$i]->rebounds_count; 151 | $this->likes[$i]->comments = $all_likes[$i]->comments_count; 152 | $this->likes[$i]->created = $all_likes[$i]->created_at; 153 | 154 | // Process the user the like belongs to 155 | $this->likes[$i]->player->id = $all_likes[$i]->player->id; 156 | $this->likes[$i]->player->name = $all_likes[$i]->player->name; 157 | $this->likes[$i]->player->username = $all_likes[$i]->player->username; 158 | $this->likes[$i]->player->url = $all_likes[$i]->player->url; 159 | $this->likes[$i]->player->avatar_url = $all_likes[$i]->player->avatar_url; 160 | $this->likes[$i]->player->twitter = $all_likes[$i]->player->twitter_screen_name; 161 | $this->likes[$i]->player->location = $all_likes[$i]->player->location; 162 | $this->likes[$i]->player->followers = $all_likes[$i]->player->followers_count; 163 | $this->likes[$i]->player->following = $all_likes[$i]->player->following_count; 164 | $this->likes[$i]->player->likes = $all_likes[$i]->player->likes_count; 165 | } 166 | } 167 | } 168 | } 169 | 170 | /** 171 | * Returns the shots of the player. 172 | * @return array Array of objects that contain the shots data. 173 | */ 174 | function shots() { 175 | return $this->shots; 176 | } 177 | 178 | /** 179 | * Returns the likes of the player. 180 | * @return array Array of objects that contain the likes data. 181 | */ 182 | function likes() { 183 | return $this->likes; 184 | } 185 | 186 | /** 187 | * Returns an object containing all the data of the player. 188 | * @return object Object containing all the player's data. 189 | */ 190 | function player() { 191 | return $this->player; 192 | } 193 | 194 | /** 195 | * Returns the username. 196 | * @return string The username used to construct this class. 197 | */ 198 | function username() { 199 | return $this->username; 200 | } 201 | 202 | /** 203 | * Fetches data from an url. 204 | * @param string The url from where data should be fetched. 205 | * @return object The data loaded from the url 206 | */ 207 | protected function fetch_data($url = null) { 208 | if (!is_null($url)) { 209 | 210 | // Init CURL 211 | $handler = curl_init(); 212 | 213 | // CURL options 214 | curl_setopt($handler, CURLOPT_URL, $url); 215 | curl_setopt($handler, CURLOPT_RETURNTRANSFER, 1); 216 | 217 | // Load data & close connection 218 | $data = curl_exec($handler); 219 | curl_close($handler); 220 | 221 | return $data; 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /plugins/dribbble/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dribbble", 3 | "readable": "Dribbble", 4 | "version": "1.2", 5 | "stable": true, 6 | "description": "Fetch player shots from Dribbble", 7 | "author": "Simon Albrecht", 8 | "url": "http://albrecht.me" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/dribbble/readme.mdown: -------------------------------------------------------------------------------- 1 | # Dribbble Plugin for Kirby by Simon Albrecht (1.1) 2 | This is a plugin for [Kirby](http://getkirby.com/) that fetches shots, player-info or likes for a user on [Dribbble](http://dribbble.com/) from the [Dribbble](http://dribbble.com/)-API. 3 | 4 | ## Installation 5 | Put the `dribbble.php` file in your `site/plugins` folder. If this folder doesn't exist yet, create it. 6 | 7 | ## Update instructions 8 | To update, just replace the old `dribbble.php` file in `site/plugins`, with the new one. 9 | 10 | ## Limitation 11 | The use of the [Dribbble API](http://dribbble.com/api) is restricted to a maximum of 60 API calls per minute. 12 | If your site exceeds that maximum, think about [enabling the cache](http://getkirby.com/docs/advanced-stuff/caching) for the site. 13 | 14 | ## Example usage 15 | shots(); 20 | $player = $dribbble->player(); 21 | $likes = $dribbble->likes(); 22 | 23 | foreach ($shots as $shot): ?> 24 | 25 |
26 |

title) ?>

27 | name ?> 28 | 29 | 30 | 31 | views ?> View(s) 32 | 33 |
34 | 35 | 36 | 37 | 46 | 47 | An example for use of this plugin can be viewed [on my website](http://albrecht.me/#dribbble). 48 | 49 | ## Attributes for the shot-object 50 | * `$shot->id` The ID of the shot 51 | * `$shot->title` The title of the shot 52 | * `$shot->url` The (long) url of the shot 53 | * `$shot->short_url` The short-url of the shot 54 | * `$shot->image` The image-url of the shot 55 | * `$shot->likes` The number of likes on the shot 56 | * `$shot->views` The number of views on the shot 57 | * `$shot->rebounds` The number of rebounds of the shot 58 | * `$shot->comments` The number of comments on the shot 59 | * `$shot->created` The date/time the liked post was created 60 | 61 | ## Attributes for the player-object 62 | * `$player->id` The ID of the player 63 | * `$player->name` The name of the player 64 | * `$player->username` The username of the player 65 | * `$player->avatar_url` The avatar-url of the player 66 | * `$player->twitter` The Twitter handle of the player 67 | * `$player->location` The location of the player 68 | * `$player->followers` The number of followers of the player 69 | * `$player->following` The number of users the player is following 70 | * `$player->likes` The number of shots the player has liked 71 | 72 | ## Attributes for the like-object 73 | * `$like->id` The ID of the liked shot 74 | * `$like->title` The title of the liked shot 75 | * `$like->url` The (long) url of the liked shot 76 | * `$like->short_url` The short-url of the liked shot 77 | * `$like->image` The image-url of the liked shot 78 | * `$like->likes` The number of likes on the liked shot 79 | * `$like->views` The number of views on the liked shot 80 | * `$like->rebounds` The number of rebounds of liked the shot 81 | * `$like->comments` The number of comments on liked the shot 82 | * `$like->created` The date/time the liked post was created 83 | * `$like->player` A representation of the user that created the liked shot. (same attributes as the player-object) 84 | 85 | ## Requirements 86 | Your web server must have support for cURL [(installation instructions)](http://www.php.net/manual/en/curl.installation.php). 87 | 88 | ## Author & Copyright 89 | Copyright 2012, Simon Albrecht [http://albrecht.me/](http://albrecht.me). 90 | If you use this plugin, feel free to ping me [@s_albrecht](http://twitter.com/s_albrecht). -------------------------------------------------------------------------------- /plugins/email/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/email/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "email", 3 | "readable": "Email", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Send mails via mail(), Amazon SES and Postmark", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/email/readme.mdown: -------------------------------------------------------------------------------- 1 | # Email Plugin 2 | 3 | ## What is it? 4 | 5 | It's a simple email sender plugin. You can use it everywhere in your code to send emails via PHP's mail(), [Amazon Simple Email Service](http://aws.amazon.com/ses/) or [Postmark](http://postmarkapp.com/) 6 | 7 | ## Installation 8 | 9 | Copy the email.php file to your site/plugins folder. 10 | 11 | ### Amazon SES configuration 12 | 13 | Go to your site/config/config.php and add the following rules: 14 | 15 | c::set('email.use', 'amazon'); 16 | c::set('email.amazon.key', 'Your Amazon SES Key'); 17 | c::set('email.amazon.secret', 'Your Amazon SES Secret'); 18 | 19 | ### Postmark configuration 20 | 21 | Go to your site/config/config.php and add the following rules: 22 | 23 | c::set('email.use', 'postmark'); 24 | c::set('email.postmark.key', 'Your Postmark API Key'); 25 | 26 | ## How to use it? 27 | 28 | You can use it in your templates, snippets or plugins like this: 29 | 30 | 'John Doe ', 34 | 'from' => 'Max Musterman ', 35 | 'subject' => 'My first Email', 36 | 'body' => 'Hello my friend! How are things going?' 37 | )); 38 | 39 | ?> 40 | 41 | ### React on sending errors 42 | 43 | 'John Doe ', 47 | 'from' => 'Max Musterman ', 48 | 'subject' => 'My first Email', 49 | 'body' => 'Hello my friend! How are things going?' 50 | )); 51 | 52 | if(error($send)) { 53 | 54 | // show the response 55 | a::show($send); 56 | 57 | // or do something else like saying that the email failed 58 | echo "The email could not be sent"; 59 | 60 | } 61 | 62 | ?> 63 | 64 | ## Available Params 65 | 66 | This is the full list of params you can pass to the email function: 67 | 68 | ### to 69 | 70 | The address the email will be sent to. You can use either just the address… 71 | 72 | 'to' => 'john@doe.com' 73 | 74 | …or the address together with a name… 75 | 76 | 'to' => 'John Doe ' 77 | 78 | If you are always sending to the same address, you can setup the to address in your config like this: 79 | 80 | c::set('email.to', 'John Doe '); 81 | 82 | Afterwards you don't need to pass the to address when calling the email function. 83 | 84 | ### from 85 | 86 | The address from which the mail has been sent. Please make sure to use an address which you are allowed to use to avoid spam. The following formats are allowed 87 | 88 | 'from' => 'john@doe.com' 89 | 90 | 'from' => 'John Doe ' 91 | 92 | If you are always sending from the same address, you can setup the from address in your config like this: 93 | 94 | c::set('email.from', 'John Doe '); 95 | 96 | Afterwards you don't need to pass the to address when calling the email function. 97 | 98 | ### replyto 99 | 100 | The reply address. The from address will be used if you don't pass this. The following formats are allowed 101 | 102 | 'from' => 'john@doe.com' 103 | 104 | 'from' => 'John Doe ' 105 | 106 | If you are always using the same reply address, you can setup the address in your config like this: 107 | 108 | c::set('email.replyto', 'John Doe '); 109 | 110 | Afterwards you don't need to pass the to address when calling the email function. 111 | 112 | ### subject 113 | 114 | The subject line for your email. If you are always using the same subject you can setup a default subject in your config: 115 | 116 | c::set('email.subject', 'This is my default subject'); 117 | 118 | ### body 119 | 120 | The plain text for your email. The email plugin does not support sending HTML emails. 121 | 122 | ### use 123 | 124 | If you want to switch the transport service, you can do it like this: 125 | 126 | 'use' => 'mail' 127 | 128 | 'use' => 'amazon' 129 | 130 | 'use' => 'postmark' 131 | 132 | ### postmark.key 133 | 134 | If you want to send from a different postmark api key, you can pass the key in the params, when calling the email function. 135 | 136 | ### postmark.test 137 | 138 | You can pass `postmark.test => true` when calling the email function to make a test call instead of sending a real request to the postmark api. Unfortunately this is not supported by the Amazon API as well. 139 | 140 | ### amazon.key 141 | 142 | If you want to send from a different amazon api key, you can pass the key in the params, when calling the email function. 143 | 144 | ### amazon.secret 145 | 146 | If you want to send from a different amazon api secret, you can pass the key in the params, when calling the email function. 147 | 148 | 149 | ## Author 150 | Bastian Allgeier 151 | -------------------------------------------------------------------------------- /plugins/flickrbadge/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/flickrbadge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flickrbadge", 3 | "readable": "Flickrbadge", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Display the latest pictures from your Flickr account", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/flickrbadge/readme.mdown: -------------------------------------------------------------------------------- 1 | # Flickrbadge Plugin 2 | 3 | ## What is it? 4 | 5 | It's a little plugin to display the latest public pictures from your Flickr account. 6 | 7 | ## Installation 8 | 9 | Copy the flickrbadge.php file to your site/plugins folder. 10 | You should make sure to enable caching. Otherwise the badge will make multiple API calls to Flickr's API every time the page is refreshed, which takes very long. 11 | 12 | - Go to site/config/config.php to set c::set('cache', true); 13 | - Make sure that site/cache is writable (change permissions to 0755) 14 | 15 | ## How to use it? 16 | 17 | You can add it to your templates like this: 18 | 19 | 'your-flickr-api-key', 23 | 'username' => 'your-flickr-username', 24 | 'limit' => 4, 25 | 'format' => 'medium' 26 | )); 27 | 28 | ?> 29 |
    30 | 31 |
  • 32 | 33 |

    title() ?>

    34 |
    taken()) ?>
    35 |
    Views: views() ?>
    36 |
    Comments: comments() ?>
    37 |
    Tags: tags()) ?>
    38 |
  • 39 | 40 |
41 | 42 | 43 | ## Available Options 44 | 45 | ### key (required) 46 | 47 | Set your Flickr api key. You can get a Flickr API Key over here: 48 | 49 | ### username (required) 50 | 51 | Set your Flickr username. 52 | 53 | ### limit (default: 10) 54 | 55 | Set the number of images you'd like to display in your badge 56 | 57 | ### format (default: square) 58 | 59 | Set the image format for your badge. The following formats are available: 60 | 61 | - square 62 | - thumbnail 63 | - small 64 | - medium 65 | - medium_640 66 | - large 67 | - original 68 | 69 | ### cache (default: true) 70 | 71 | Disable or enable the cache. Caching the results is highly recommended. Otherwise the badge will be super slow. You must make sure that `site/cache` is writable (change permissions to 0755) You must also set c::set('cache', true); in site/config/config.php to enable the cache. 72 | 73 | ### refresh (default: two hours) 74 | 75 | Set the cache expiry in seconds. By default it will be set to two hours. After two hours the badge will try to fetch fresh data from the API. Photo and user information will be kept forever unless you delete the cache files manually. This will speed up the update process. 76 | 77 | ## Available variables for $picture objects 78 | 79 | When looping through the result array you can use the following variables: 80 | 81 | ### $picture->url() 82 | 83 | The url to the Flickr picture page 84 | 85 | ### $picture->src() 86 | 87 | The url of the image file 88 | 89 | ### $picture->title() 90 | 91 | The title of the picture 92 | 93 | ### $picture->description() 94 | 95 | The description for the picture 96 | 97 | ### $picture->tags() 98 | 99 | An array of tags 100 | 101 | ### $picture->taken() 102 | 103 | The unix timestamp when the picture has been taken 104 | 105 | ### $picture->posted() 106 | 107 | The unix timestamp when the picture has been posted on Flickr 108 | 109 | ### $picture->lastupdate() 110 | 111 | The unix timestamp when the picture has been updated 112 | 113 | ### $picture->views() 114 | 115 | The number of views for this picture 116 | 117 | ### $picture->comments() 118 | 119 | The number of comments for this picture 120 | 121 | 122 | ## Credits 123 | 124 | The plugin uses the awesome phpFlickr Class by Dan Coulter: http://phpflickr.com/ 125 | 126 | ## Author 127 | Bastian Allgeier 128 | -------------------------------------------------------------------------------- /plugins/github/README.mdown: -------------------------------------------------------------------------------- 1 | GitHub Plugin for Kirby 2 | ======================= 3 | 4 | With that plugin you can implement a users GitHub information or list your repos easily in Kirby. 5 | 6 | Usage example for repos: 7 | ======================== 8 | ```php 9 | repos() as $repo): 13 | ?> 14 |
  • 15 |

    name ?>

    16 |

    description ?>

    17 |
  • 18 | 19 | ``` 20 | 21 | Attributes for repo() 22 | ===================== 23 | - `$repo->name` the name of the repository 24 | - `$repo->description` the description 25 | - `$repo->url` the url to the repository 26 | - `$repo->last_update` the timestamp to the last update 27 | - `$repo->forkcount` the number of forks 28 | - `$repo->watchers` the number of watchers 29 | 30 | Attributes for user() 31 | ===================== 32 | - `$user->username` the GitHub username 33 | - `$user->name` the real name 34 | - `$user->email` the email, if given 35 | - `$user->followers` the count of followers 36 | - `$user->following` the count of following 37 | - `$user->url` the GitHub-url 38 | - `$user->gravatar_id` the gravatar-id 39 | - `$user->repos_url` the url to the repos 40 | -------------------------------------------------------------------------------- /plugins/github/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | 5 | + Initial release 6 | -------------------------------------------------------------------------------- /plugins/github/github.php: -------------------------------------------------------------------------------- 1 | username = $username; 12 | $this->count = $count; 13 | } 14 | 15 | // Get repos and sort them 16 | public function repos($sorted = false) { 17 | if($this->count <= 0) return false; 18 | $url = 'https://api.github.com/users/' . $this->username . '/repos'; 19 | $data = $this->get_data($url); 20 | 21 | $this->repos = array(); 22 | 23 | foreach ($data as $key => $obj) { 24 | if($key >= $this->count) break; 25 | 26 | $this->repos[$key] = new stdClass; 27 | 28 | $this->repos[$key]->name = $obj->name; 29 | $this->repos[$key]->description = $obj->description; 30 | $this->repos[$key]->url = $obj->html_url; 31 | $this->repos[$key]->last_update = strtotime($obj->updated_at); 32 | $this->repos[$key]->forkount = $obj->forks_count; 33 | $this->repos[$key]->watchers = $obj->watchers_count; 34 | } 35 | 36 | if($sorted) { 37 | function cmp($a, $b) { 38 | if ($b->last_update == $a->last_update) return 0; 39 | return ($b->last_update < $a->last_update) ? -1 : 1; 40 | } 41 | usort($this->repos, 'cmp'); 42 | } 43 | 44 | return $this->repos; 45 | } 46 | 47 | // Get user 48 | public function user() { 49 | $url = 'https://api.github.com/users/' . $this->username; 50 | $data = $this->get_data($url); 51 | 52 | $this->user = new stdClass; 53 | 54 | $this->user->username = $data->login; 55 | $this->user->name = $data->name; 56 | $this->user->email = $data->email; 57 | $this->user->followers = $data->followers; 58 | $this->user->following = $data->following; 59 | $this->user->url = 'https://github.com/' . $data->login; 60 | $this->user->gravatar_id = $data->gravatar_id; 61 | $this->user->repos_url = $data->repos_url; 62 | 63 | return $this->user; 64 | } 65 | 66 | // Fetch data 67 | protected function get_data($url) { 68 | if($url == '') return false; 69 | $handler = curl_init(); 70 | 71 | curl_setopt($handler, CURLOPT_URL, $url); 72 | curl_setopt($handler, CURLOPT_RETURNTRANSFER, 1); 73 | curl_setopt($handler, CURLOPT_USERAGENT, $this->username); 74 | 75 | $data = curl_exec($handler); 76 | curl_close($handler); 77 | 78 | return json_decode($data); 79 | } 80 | } 81 | ?> 82 | -------------------------------------------------------------------------------- /plugins/github/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github", 3 | "readable": "GitHub", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Fetch GitHub user or repo", 7 | "author": "Arne Bahlo", 8 | "url": "http://arne.me" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/highlight/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.1 4 | + Initial release -------------------------------------------------------------------------------- /plugins/highlight/highlight.php: -------------------------------------------------------------------------------- 1 | set_header_type(GESHI_HEADER_NONE); 13 | $geshi->enable_classes(); 14 | $geshi->enable_keyword_links(false); 15 | $code = $geshi->parse_code(); 16 | return '' . $code . ''; 17 | 18 | } 19 | 20 | function smartHighlight($code) { 21 | 22 | // find all php stuff 23 | preg_match_all('!\<\?.*?\?\>!i', $code, $array); 24 | 25 | $result = ''; 26 | $php = array(); 27 | 28 | // replace php within html with placeholders 29 | foreach($array[0] as $key => $found) { 30 | $key = '____' . $key . '____'; 31 | $php[$key] = highlight($found, 'php'); 32 | $code = str_replace($found, $key, $code); 33 | } 34 | 35 | // now highlight the plain html 36 | $code = highlight($code, 'html'); 37 | 38 | // put the highlighted php back in 39 | foreach($php as $key => $p) { 40 | $code = str_replace($key, $p, $code); 41 | } 42 | 43 | return $code; 44 | 45 | } -------------------------------------------------------------------------------- /plugins/highlight/highlight/geshi/js.php: -------------------------------------------------------------------------------- 1 | 'Javascript', 44 | 'COMMENT_SINGLE' => array(1 => '//'), 45 | 'COMMENT_MULTI' => array('/*' => '*/'), 46 | 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, 47 | 'QUOTEMARKS' => array("'", '"'), 48 | 'ESCAPE_CHAR' => '\\', 49 | 'KEYWORDS' => array( 50 | 1 => array( 51 | 'as', 'break', 'case', 'catch', 'continue', 'decodeURI', 'delete', 'do', 52 | 'else', 'encodeURI', 'eval', 'finally', 'for', 'if', 'in', 'is', 'item', 53 | 'instanceof', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'void', 54 | 'while', 'write', 'with' 55 | ), 56 | 2 => array( 57 | 'class', 'const', 'default', 'debugger', 'export', 'extends', 58 | 'function', 'import', 'namespace', 'new', 'null', 'package', 'private', 59 | 'protected', 'public', 'super', 'use', 'var' 60 | ), 61 | 3 => array( 62 | 63 | // common functions for Window object 64 | 'alert', 'back', 'blur', 'close', 'confirm', 'focus', 'forward', 'home', 65 | 'name', 'navigate', 'onblur', 'onerror', 'onfocus', 'onload', 'onmove', 66 | 'onresize', 'onunload', 'open', 'print', 'prompt', 'scroll', 'status', 67 | 'stop', 68 | ), 69 | 4 => array( 70 | 'false', 'true' 71 | ) 72 | ), 73 | 'SYMBOLS' => array( 74 | '(', ')', '[', ']', '{', '}', '!', '@', '%', '&', '*', '|', '/', '<', '>' 75 | ), 76 | 'CASE_SENSITIVE' => array( 77 | GESHI_COMMENTS => false, 78 | 1 => false, 79 | 2 => false, 80 | 3 => false 81 | ), 82 | 'STYLES' => array( 83 | 'KEYWORDS' => array( 84 | 1 => 'color: #000066; font-weight: bold;', 85 | 2 => 'color: #003366; font-weight: bold;', 86 | 3 => 'color: #000066;' 87 | ), 88 | 'COMMENTS' => array( 89 | 1 => 'color: #009900; font-style: italic;', 90 | 'MULTI' => 'color: #009900; font-style: italic;' 91 | ), 92 | 'ESCAPE_CHAR' => array( 93 | 0 => 'color: #000099; font-weight: bold;' 94 | ), 95 | 'BRACKETS' => array( 96 | 0 => 'color: #66cc66;' 97 | ), 98 | 'STRINGS' => array( 99 | 0 => 'color: #3366CC;' 100 | ), 101 | 'NUMBERS' => array( 102 | 0 => 'color: #CC0000;' 103 | ), 104 | 'METHODS' => array( 105 | 1 => 'color: #006600;' 106 | ), 107 | 'SYMBOLS' => array( 108 | 0 => 'color: #66cc66;' 109 | ), 110 | 'REGEXPS' => array( 111 | 0 => 'color: #0066FF;' 112 | ), 113 | 'SCRIPT' => array( 114 | 0 => '', 115 | 1 => '', 116 | 2 => '', 117 | 3 => '' 118 | ) 119 | ), 120 | 'URLS' => array( 121 | 1 => '', 122 | 2 => '', 123 | 3 => '' 124 | ), 125 | 'OOLANG' => true, 126 | 'OBJECT_SPLITTERS' => array( 127 | 1 => '.' 128 | ), 129 | 'REGEXPS' => array( 130 | 0 => "/.*/([igm]*)?" // matches js reg exps 131 | ), 132 | 'STRICT_MODE_APPLIES' => GESHI_MAYBE, 133 | 'SCRIPT_DELIMITERS' => array( 134 | 0 => array( 135 | '' 136 | ), 137 | 1 => array( 138 | '' 139 | ) 140 | ), 141 | 'HIGHLIGHT_STRICT_BLOCK' => array( 142 | 0 => true, 143 | 1 => true 144 | ) 145 | ); 146 | 147 | ?> 148 | -------------------------------------------------------------------------------- /plugins/highlight/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highlight", 3 | "readable": "Highlight", 4 | "version": "0.1", 5 | "stable": false, 6 | "description": "Create Geshi highlighted code snippets from within Kirbytext", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/highlight/readme.mdown: -------------------------------------------------------------------------------- 1 | # Highlight Plugin (Alpha) 2 | 3 | ## What is it? 4 | 5 | It's a very alpha-style code highlighting plugin, which uses Geshi highlighting to create nice code snippets for php, html, js and css. Please use it at your own risk and read the instructions carefully to install it properly. 6 | 7 | ## Installation 8 | 9 | Copy the highlight folder and highlight.php and add them to site/plugins. (Create the plugins folder if it is not there) Copy the css files from the styles folder and add them to the folder where all your css files for your site are located. Load the needed style files in your templates: 10 | 11 | Example: 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ## How to use it? 20 | 21 | Whenever you want to add a highlighted code snippet to your content, do it like this: 22 | 23 | ```php 24 | 25 | some php code 26 | 27 | ``` 28 | 29 | ```html 30 | 31 | some html code 32 | 33 | ``` 34 | 35 | ```js 36 | 37 | some javascript code 38 | 39 | ``` 40 | 41 | ```css 42 | 43 | some css code 44 | 45 | ``` 46 | 47 | ## Code Block styles 48 | 49 | To remove unwanted spacing you should add 50 | 51 | pre { 52 | white-space: nowrap 53 | } 54 | 55 | ## Author 56 | Bastian Allgeier 57 | -------------------------------------------------------------------------------- /plugins/highlight/styles/css.css: -------------------------------------------------------------------------------- 1 | /* attributes */ 2 | .css .kw1 { 3 | color: #9d275f; 4 | } 5 | /* string values */ 6 | .css .st0, 7 | .css .re4 { 8 | color: #8b1a1f; 9 | } 10 | 11 | /* hex colors */ 12 | .css .re0, 13 | .css .re0 .nu0 { 14 | color: #8b1a1f; 15 | } 16 | 17 | /* known values */ 18 | .css .kw2 { 19 | color: #ae561d; 20 | } 21 | 22 | /* numbers (px etc) */ 23 | .css .nu0, 24 | .css .re3 { 25 | color: #063ff4; 26 | } 27 | 28 | /* !important */ 29 | .css .kw3 { 30 | color: #ff221b; 31 | } 32 | 33 | /* comments */ 34 | .css .co1, 35 | .css .co2, 36 | .css .coMULTI { 37 | color: #267e3d; 38 | } -------------------------------------------------------------------------------- /plugins/highlight/styles/html.css: -------------------------------------------------------------------------------- 1 | /* doctype */ 2 | .html .sc0 { 3 | color: #267e3d; 4 | } 5 | /* keywords (echo, required, etc) */ 6 | .html .kw1 { 7 | color: #9d2760; 8 | } 9 | /* tags */ 10 | .html .sc2, 11 | .html .kw2 { 12 | color: #9d2e8d; 13 | } 14 | /* attribute names */ 15 | .html .kw3 { 16 | color: #ac571d; 17 | } 18 | /* attribute values */ 19 | .html .st0 { 20 | color: #2437ad; 21 | } 22 | /* comments */ 23 | .html .co1, 24 | .html .co2, 25 | .html .coMULTI { 26 | color: #267e3d; 27 | } -------------------------------------------------------------------------------- /plugins/highlight/styles/js.css: -------------------------------------------------------------------------------- 1 | /* function names */ 2 | .js .me1, 3 | .js .kw3 { 4 | color: #004678; 5 | } 6 | 7 | /* predefined stuff (function, etc…) */ 8 | .js .kw1, 9 | .js .kw2 { 10 | color: #9d2760; 11 | } 12 | /* strings */ 13 | .js .st0 { 14 | color: #8b1a1f; 15 | } 16 | /* number */ 17 | .js .nu0 { 18 | color: #063ff4; 19 | } 20 | /* false | true */ 21 | .js .kw4 { 22 | color: #063ff4; 23 | } -------------------------------------------------------------------------------- /plugins/highlight/styles/objc.css: -------------------------------------------------------------------------------- 1 | .objc .de1, .objc .de2 {margin:0; padding:0; background:none; vertical-align:top;} 2 | .objc .imp {font-weight: bold; color: red;} 3 | .objc li, .objc .li1 {font-weight: normal; vertical-align:top;} 4 | .objc .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;} 5 | .objc .li2 {font-weight: bold; vertical-align:top;} 6 | .objc .kw1 {color: #a61390;} 7 | .objc .kw2 {color: #a61390;} 8 | .objc .kw3 {color: #a61390;} 9 | .objc .kw4 {color: #a61390;} 10 | .objc .kw5 {color: #400080;} 11 | .objc .kw6 {color: #2a6f76;} 12 | .objc .kw7 {color: #400080;} 13 | .objc .kw8 {color: #2a6f76;} 14 | .objc .kw9 {color: #400080;} 15 | .objc .co1 {color: #6e371a;} 16 | .objc .co2 {color: #11740a; font-style: italic;} 17 | .objc .co3 {color: #bf1d1a;} 18 | .objc .coMULTI {color: #11740a; font-style: italic;} 19 | .objc .es0 {color: #2400d9;} 20 | .objc .br0 {color: #002200;} 21 | .objc .sy0 {color: #002200;} 22 | .objc .st0 {color: #bf1d1a;} 23 | .objc .nu0 {color: #2400d9;} 24 | .objc .ln-xtra, .objc li.ln-xtra, .objc div.ln-xtra {background-color: #ffc;} 25 | .objc span.xtra { display:block; } 26 | 27 | -------------------------------------------------------------------------------- /plugins/highlight/styles/php.css: -------------------------------------------------------------------------------- 1 | .php { 2 | color: #004678; 3 | } 4 | 5 | /* keywords (echo, required, etc) */ 6 | .php .kw1 { 7 | color: #9d2760; 8 | } 9 | .php .kw2 { 10 | color: #9d2760; 11 | } 12 | /* predefined functions */ 13 | .php .kw3 { 14 | color: #7c3ab0; 15 | } 16 | 17 | /* , etc */ 18 | .php .kw4 { 19 | color: #e22013; 20 | } 21 | 22 | /* = */ 23 | .php .kw5 { 24 | color: #000; 25 | } 26 | 27 | /* comments */ 28 | .php .co1, 29 | .php .co2, 30 | .php .coMULTI { 31 | color: #267e3d; 32 | } 33 | 34 | /* brackets */ 35 | .php .br0 { 36 | color: #000; 37 | } 38 | 39 | /* strings */ 40 | .php .st0 { 41 | color: #f28630 !important; 42 | } 43 | 44 | /* numbers */ 45 | .php .nu0 { 46 | color: #063ff4; 47 | } 48 | 49 | /* functions */ 50 | .php .me1 { 51 | color: #004678; 52 | } 53 | 54 | /* variables */ 55 | .php .re0 { 56 | color: #926821; 57 | } 58 | -------------------------------------------------------------------------------- /plugins/instagram/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.1 (22.08.12) 4 | * Updated the readme with revisited installation instructions 5 | * Fixed a few notice bugs 6 | 7 | ## v1.0 (18.02.12) 8 | + Initial version -------------------------------------------------------------------------------- /plugins/instagram/instagram.php: -------------------------------------------------------------------------------- 1 | plugin for Kirby . 18 | * In order to use this plugin, you'll need to obtain an access token for API access. See the readme for more information. 19 | * @author Simon Albrecht 20 | * @version 1.0 21 | * @copyright (c) 2012 Simon Albrecht 22 | */ 23 | class instagram { 24 | var $images; 25 | var $user; 26 | 27 | /** 28 | * Constructor. Loads the data from the Instagram API. 29 | * @param string The access token. 30 | * @param integer The number of shots that will be loaded. 31 | * @param boolean Chache enabled. 32 | * @param integer How many seconds until the cache expires. 33 | * @param string The user-id of the user or 'self' for your own account. 34 | */ 35 | function __construct($_token = '', $_count = 10, $_cache = true, $_cache_expire = 3600, $_user = 'self') { 36 | // Init 37 | $this->images = array(); 38 | $this->user = new stdClass; 39 | 40 | // Check if a token is provided 41 | if (trim($_token) != '') { 42 | 43 | // Construct the API url… 44 | // http://instagr.am/developer/endpoints/users/ 45 | $url = "https://api.instagram.com/v1/users/{$_user}/media/recent/?access_token={$_token}&count={$_count}"; 46 | 47 | // Create cache directory if it doesn't exist yet 48 | if ($_cache) { 49 | dir::make(c::get('root.cache') . '/instagram'); 50 | } 51 | 52 | $images_cache_id = 'instagram/images.' . md5($_token) . '.' . $_count . '.php'; 53 | $images_cache_data = false; 54 | 55 | // Try to fetch data from cache 56 | if ($_cache) { 57 | $images_cache_data = (cache::modified($images_cache_id) < time() - $_cache_expire) ? false : cache::get($images_cache_id); 58 | } 59 | 60 | // Load data from the API if the cache expired or the cache is empty 61 | if (empty($images_cache_data)) { 62 | $data = $this->fetch_data($url); 63 | $photos = json_decode($data); 64 | 65 | // Set new data for the cache 66 | if ($_cache) { 67 | cache::set($images_cache_id, $photos); 68 | } 69 | } else { 70 | $photos = $images_cache_data; 71 | } 72 | 73 | // Process the images 74 | for ($i = 0; $i < $_count; $i++) { 75 | if (isset($photos->data[$i]) && count($photos->data) > 0) { 76 | 77 | // Get the user's data from the first image 78 | if ($i == 0) { 79 | $this->user->username = $photos->data[$i]->user->username; 80 | $this->user->full_name = $photos->data[$i]->user->full_name; 81 | $this->user->picture = $photos->data[$i]->user->profile_picture; 82 | } 83 | 84 | // create a new object for each image 85 | $obj = new stdClass; 86 | 87 | $obj->link = $photos->data[$i]->link; 88 | $obj->comments = @$photos->data[$i]->comments->count; 89 | $obj->likes = @$photos->data[$i]->likes->count; 90 | $obj->created = $photos->data[$i]->created_time; 91 | $obj->thumb = @$photos->data[$i]->images->thumbnail->url; 92 | $obj->url = @$photos->data[$i]->images->standard_resolution->url; 93 | $obj->image_lowres = @$photos->data[$i]->images->low_resolution->url; 94 | $obj->filter = $photos->data[$i]->filter; 95 | $obj->location = @$photos->data[$i]->location->name; 96 | $obj->latitude = @$photos->data[$i]->location->latitude; 97 | $obj->longitude = @$photos->data[$i]->location->longitude; 98 | $obj->tags = array(); 99 | 100 | // attach the new object to the array 101 | $this->images[$i] = $obj; 102 | 103 | // Process tags 104 | for ($j = 0; $j < count($photos->data[$i]->tags); $j++) { 105 | $this->images[$i]->tags[$j] = $photos->data[$i]->tags[$j]; 106 | } 107 | } 108 | } 109 | } else { 110 | throw new Exception('$_token MUST be set!'); 111 | } 112 | } 113 | 114 | /** 115 | * Returns the images that were loaded from the API. 116 | * @return array Array of objects containing all the photo's data. 117 | */ 118 | function images() { 119 | return $this->images; 120 | } 121 | 122 | /** 123 | * Returns information about the user. 124 | * @return object Object with information about the user. 125 | */ 126 | function user() { 127 | return $this->user; 128 | } 129 | 130 | /** 131 | * Fetches data from an url. 132 | * @param string The url from where data should be fetched. 133 | * @return object The data loaded from the url 134 | */ 135 | protected function fetch_data($url = null) { 136 | if (!is_null($url)) { 137 | 138 | // Init CURL 139 | $handler = curl_init(); 140 | 141 | // CURL options 142 | curl_setopt($handler, CURLOPT_URL, $url); 143 | curl_setopt($handler, CURLOPT_RETURNTRANSFER, 1); 144 | 145 | // Load data & close connection 146 | $data = curl_exec($handler); 147 | curl_close($handler); 148 | 149 | return $data; 150 | } 151 | } 152 | } -------------------------------------------------------------------------------- /plugins/instagram/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "instagram", 3 | "readable": "Instagram", 4 | "version": "1.1", 5 | "stable": true, 6 | "description": "Fetch images from Instagram", 7 | "author": "Simon Albrecht", 8 | "url": "http://albrecht.me" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/instagram/readme.mdown: -------------------------------------------------------------------------------- 1 | # Instagram Plugin for Kirby by Simon Albrecht (1.0) 2 | This is a plugin for [Kirby](http://getkirby.com/) that loads images from the [Instagram](http://instagram.com/) API. 3 | 4 | ## Installation 5 | 1. Put the `instagram.php` file in your `site/plugins` folder. If this folder doesn't exist yet, create it. 6 | 2. In order to interact with the Instagram API, you need to obtain an access token for yourself. 7 | 3. Visit and register an application. 8 | 4. Set the OAuth redirect_uri to the main URL (i.e. http://yourdomain.com) of your website. 9 | 5. Copy the Client-ID of the newly created app. 10 | 6. Visit: 11 | 12 | https://instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://yourdomain.com&response_type=token 13 | 14 | …in your browser, but replace CLIENT-ID with your client-id and YOURDOMAIN.COM with the OAuth redirect_uri you've entered while registering your app. 15 | 16 | 7. The browser will redirect you to your own website and in the address bar you will find your access token like this: 17 | 18 | http://yourdomain.com/#access_token=xxxxx.xxxxx.xxxxxxxxxxx 19 | 20 | 8. Copy the access token (everything after =) and save it somewhere. 21 | 9. Implement the plugin into your template. 22 | 23 | ## Update instructions 24 | To update, just replace the old `instagram.php` file in `site/plugins`, with the new one. 25 | 26 | ## Example usage 27 | images(); 33 | 34 | foreach ($images as $image): ?> 35 |
    36 | 37 |
    38 | 39 | location ?> (latitude ?>, longitude ?>) 40 | 41 |
    42 |
    43 | 44 | 45 | **Advanced Users:** See the source for further options. 46 | 47 | ## Attributes for the image 48 | * `$image->link` The link to the image 49 | * `$image->comments` The number of comments 50 | * `$image->likes` The number of likes 51 | * `$image->created` The timestamp when the image was created 52 | * `$image->thumb` The url of the thumbnail of the image 53 | * `$image->url` The url of the full-sized image 54 | * `$image->image_lowres` The url to a low-res version of the image 55 | * `$image->filter` The filter that was used 56 | * `$image->location` The location name 57 | * `$image->latitude` The latitude of the location 58 | * `$image->longitude` The longitude of the location 59 | * `$image->tags` An array of tags of the image 60 | 61 | ## Attributes for the user-object 62 | * `$user->username` The username of the user 63 | * `$user->full_name` The full name of the user 64 | * `$user->picture` The url to the avatar of the user 65 | 66 | ## Requirements 67 | Your web server must have support for cURL [(installation instructions)](http://www.php.net/manual/en/curl.installation.php). 68 | 69 | ## Author 70 | Copyright 2012, Simon Albrecht [http://albrecht.me/](http://albrecht.me). 71 | If you use this plugin, feel free to ping me [@s_albrecht](http://twitter.com/s_albrecht). -------------------------------------------------------------------------------- /plugins/randomimage/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/randomimage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "randomimage", 3 | "readable": "Random Image", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Display a random image from a given folder", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/randomimage/randomimage.php: -------------------------------------------------------------------------------- 1 | 10 | *
    11 | * 12 | * 13 | * The directory must be relative to the root of the site. 14 | * Otherwise URLs will be broken 15 | * 16 | * @param string $dir the relative path to the directory 17 | * @return string the full url to the image 18 | */ 19 | function randomimage($dir) { 20 | $files = dir::read(c::get('root') . '/' . $dir); 21 | shuffle($files); 22 | return url($dir . '/' . a::first($files)); 23 | } 24 | 25 | ?> -------------------------------------------------------------------------------- /plugins/randomimage/readme.mdown: -------------------------------------------------------------------------------- 1 | # Random Image 2 | 3 | Returns a random image url from a given directory 4 | Can be used to display random header images for example. 5 | 6 | ## Installation 7 | Put the `randomimage.php` file in your `site/plugins` folder. If this folder doesn't exist yet, create it. 8 | 9 | ## Example usage 10 | 11 |
    12 | 13 |
    14 | 15 | ## Notes 16 | 17 | The directory must be relative to the root of the site, otherwise URLs will be broken 18 | 19 | If you are working with images in a content directory you can simplify this by doing: 20 | 21 | images()->shuffle()->first()->url() ?> 22 | 23 | ## Author 24 | Bastian Allgeier 25 | -------------------------------------------------------------------------------- /plugins/readingtime/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/readingtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "readingtime", 3 | "readable": "Reading Time", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Estimate the reading time for your content", 7 | "author": "Roy Lodder", 8 | "url": "http://roylodder.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/readingtime/readingtime.php: -------------------------------------------------------------------------------- 1 | text()) ?> 12 | * 13 | * Author: Roy Lodder 14 | * Contributor: Bastian Allgeier 15 | * 16 | */ 17 | 18 | function readingtime($content, $params=array()) { 19 | 20 | $defaults = array( 21 | 'minute' => 'minute', 22 | 'minutes' => 'minutes', 23 | 'second' => 'second', 24 | 'seconds' => 'seconds', 25 | 'format' => '{minutesCount} {minutesLabel}, {secondsCount} {secondsLabel}' 26 | ); 27 | 28 | $options = array_merge($defaults, $params); 29 | $words = str_word_count(strip_tags($content)); 30 | 31 | $minutesCount = floor($words / 200); 32 | $secondsCount = floor($words % 200 / (200 / 60)); 33 | $minutesLabel = ($minutesCount <= 1) ? $options['minute'] : $options['minutes']; 34 | $secondsLabel = ($secondsCount <= 1) ? $options['second'] : $options['seconds']; 35 | 36 | $replace = array( 37 | 'minutesCount' => $minutesCount, 38 | 'minutesLabel' => $minutesLabel, 39 | 'secondsCount' => $secondsCount, 40 | 'secondsLabel' => $secondsLabel, 41 | ); 42 | 43 | $result = $options['format']; 44 | 45 | foreach($replace as $key => $value) { 46 | $result = str_replace('{' . $key . '}', $value, $result); 47 | } 48 | 49 | return $result; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /plugins/readingtime/readme.mdown: -------------------------------------------------------------------------------- 1 | # Estimated reading time plugin 2 | 3 | This is a plugin for [Kirby](http://getkirby.com/) that estimates the reading time for your content. 4 | 5 | ## Installation 6 | 7 | Put the `readingtime.php` file in your `site/plugins` folder. 8 | 9 | ## How to use it 10 | 11 | It's very simple! Just put `text()) ?>` in your template and it will echo the estimated reading time. You can pass any other page variable to estimate the reading time of it. 12 | 13 | ## Example usage 14 | 15 | 16 | 17 | 18 | 19 |
    20 | 21 |
    22 |

    title()) ?>

    23 | text()) ?> 24 | text()) ?> 25 |
    26 | 27 |
    28 | 29 | 30 | 31 | ## Language 32 | 33 | The plugin is very easy to localize. The default format for example is 3 minutes, 31 seconds. Pass the following params to translate it to any language: 34 | 35 | text(), array( 38 | 'minute' => 'Minute', 39 | 'minutes' => 'Minuten', 40 | 'second' => 'Sekunde', 41 | 'seconds' => 'Sekunden' 42 | )); 43 | 44 | ?> 45 | 46 | You can even change the entire format of the result: 47 | 48 | text(), array( 51 | 'minute' => 'Minute', 52 | 'minutes' => 'Minuten', 53 | 'second' => 'Sekunde', 54 | 'seconds' => 'Sekunden', 55 | 'format' => '{minutesCount} {minutesLabel} – {secondsCount} {secondsLabel} 56 | )); 57 | 58 | ?> 59 | 60 | ## Author 61 | 62 | Author: Roy Lodder 63 | Contributor: Bastian Allgeier 64 | 65 | Original Version: https://github.com/Roylodder/Kirbycms-Reading-Time-Snippet 66 | 67 | -------------------------------------------------------------------------------- /plugins/readlater/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/readlater/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "readlater", 3 | "readable": "Read later", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Save a page for later reading. Supports Instapaper and Pocket.", 7 | "author": "Roy Lodder", 8 | "url": "http://roylodder.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/readlater/readlater.php: -------------------------------------------------------------------------------- 1 | array( 7 | 'link' => 'http://www.instapaper.com/hello2?url={url}&title={title}', 8 | 'label' => 'Add to Instapaper', 9 | ), 10 | 'pocket' => array( 11 | 'link' => 'https://getpocket.com/save?url={url}&title={title}', 12 | 'label' => 'Save to Pocket', 13 | ), 14 | 'readability' => array( 15 | 'link' => 'http://www.readability.com/save?url={url}', 16 | 'label' => 'Add to Readability', 17 | ) 18 | ); 19 | 20 | if(!array_key_exists($tool, $tools)) return false; 21 | 22 | // make it possible to pass params 23 | // as third object instead of fourth. 24 | if(is_array($label)) { 25 | $params = $label; 26 | $label = false; 27 | } 28 | 29 | $defaults = array( 30 | 'label' => $label, 31 | 'rel' => false, 32 | 'target' => false, 33 | 'class' => 'readlater ' . $tool, 34 | 'url' => url::current(), 35 | ); 36 | 37 | $options = array_merge($defaults, $params); 38 | $url = urlencode($options['url']); 39 | $title = urlencode($content); 40 | $label = ($options['label']) ? $options['label'] : $tools[$tool]['label']; 41 | $rel = ($options['rel']) ? ' rel="' . $options['rel'] . '"' : ''; 42 | $target = ($options['target']) ? ' target="' . $options['target'] . '"' : ''; 43 | $class = ($options['class']) ? ' class="' . $options['class'] . '"' : ''; 44 | 45 | $link = str_replace('{url}', $url, $tools[$tool]['link']); 46 | $link = str_replace('{title}', $title, $link); 47 | 48 | return '' . $label . ''; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /plugins/readlater/readme.mdown: -------------------------------------------------------------------------------- 1 | # Read later plugin 2 | 3 | This is a plugin for [Kirby](http://getkirby.com/) that let´s you save the page for later reading. It currently supports [Instapaper](http://www.instapaper.com/) and [Pocket](http://getpocket.com/). 4 | 5 | ## Installation 6 | 7 | Put the `readlater.php` file in your `site/plugins` folder. 8 | 9 | ## How to use it 10 | 11 | Simple! Put `title(),'instapaper') ?>` in your template and it will echo the a link that let´s you save the page to Instapaper. Do you want to use Pocket? Then you use `title(),'pocket') ?>` in your template. 12 | 13 | You can pass any other page variable to use for the title. I asume that you use `$page->title()` for the title but you are free to change it. 14 | 15 | ## Example usage 16 | 17 | 18 | 19 | 20 | 21 |
    22 | 23 |
    24 | title(),'pocket') ?> 25 |

    title()) ?>

    26 | text()) ?> 27 |
    28 | 29 |
    30 | 31 | 32 | 33 | ## Link text 34 | 35 | The plugin let's you change the link text with ease. The default format for Instapaper is `Add to Instapaper`. For Pocket we use `Save to Pocket`. 36 | 37 | Simply pass the link text as third argument to use your own. 38 | 39 | title(), 'instapaper', 'Read later'); ?> 40 | 41 | ## Options 42 | 43 | You can add additional options to customize the html result: 44 | 45 | title(), 'instapaper', 'Read later', array( 48 | 'class' => 'mycustomclass', 49 | 'target' => '_blank', 50 | 'rel' => 'somerelattribute' 51 | )); 52 | 53 | ?> 54 | 55 | ## Author 56 | 57 | Author: Roy Lodder 58 | Contributor: Bastian Allgeier -------------------------------------------------------------------------------- /plugins/related/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/related/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "related", 3 | "readable": "Related", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Link related pages via their URI", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/related/readme.mdown: -------------------------------------------------------------------------------- 1 | # Related Pages 2 | 3 | ## What is it? 4 | 5 | This plugin makes it possible to link related pages very easily by their URI in content files. 6 | 7 | ## Installation 8 | 9 | Put the related.php file in your site/plugins folder. 10 | 11 | ## How to use it? 12 | 13 | ### In your content files 14 | 15 | Title: My title 16 | ---- 17 | Text: My text 18 | ---- 19 | Related: 20 | 21 | - projects/project-1 22 | - blog/my-article 23 | 24 | 25 | ### In your templates 26 | 27 | related() as $related): ?> 28 | title()) ?> 29 | 30 | 31 | 32 | ## Result 33 | 34 | The result of the related() function will be a full set of `$pages`, which you can apply the same methods to as you would to a normal set of `$pages`. This makes it possible to do stuff like: 35 | 36 | $related = related($page->related()); 37 | 38 | // show the url of the first related page 39 | echo $related->first()->url(); 40 | 41 | // show the title of the last related page 42 | echo $related->last()->title(); 43 | 44 | // limit the number of related items 45 | foreach($related->limit(5) as $related) { 46 | // do something 47 | } 48 | 49 | // etc. 50 | 51 | For each `$page` in the set of related `$pages` you have full access to all the custom fields and methods of the related `$page` 52 | 53 | 54 | ## Author 55 | Bastian Allgeier 56 | -------------------------------------------------------------------------------- /plugins/related/related.php: -------------------------------------------------------------------------------- 1 | related() as $related): ?> 23 | * title()) ?> 24 | * 25 | * 26 | * Author: Bastian Allgeier 27 | * 28 | */ 29 | 30 | function related($field) { 31 | 32 | global $site; 33 | 34 | // parse the field with yaml 35 | $raw = yaml($field); 36 | $related = array(); 37 | $pages = $site->pages(); 38 | 39 | foreach($raw as $r) { 40 | // make sure to only add found related pages 41 | if($rel = $pages->find($r)) $related[] = $rel; 42 | } 43 | 44 | return new relatedPages($related); 45 | 46 | } 47 | 48 | // this is only needed to build a proper find method 49 | // the pages find method will be broken with pages from 50 | // various subfolders 51 | class relatedPages extends pages { 52 | 53 | function find() { 54 | 55 | global $site; 56 | 57 | $args = func_get_args(); 58 | 59 | // find multiple pages 60 | if(count($args) > 1) { 61 | $result = array(); 62 | foreach($args as $arg) { 63 | $page = $this->find($arg); 64 | if($page) $result[] = $page; 65 | } 66 | return (empty($result)) ? false : new relatedPages($result); 67 | } 68 | 69 | return $site->pages()->find(a::first($args)); 70 | 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /plugins/resrc/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial Release -------------------------------------------------------------------------------- /plugins/resrc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resrc", 3 | "readable": "Resrc.it", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Provides a helper for prepending your image urls with http://resrc.it", 7 | "author": "Luke Watts", 8 | "url": "http://thisis.la/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/resrc/readme.mdown: -------------------------------------------------------------------------------- 1 | # Resrc.it 2 | 3 | ## What is it? 4 | 5 | Adds a helper for prepending your image urls with http://resrc.it, these can be configured 6 | 7 | ## Installation 8 | 9 | Put the resrc.php file in your site/plugins folder. 10 | 11 | ## How to use it? 12 | 13 | By default it will not prepend your URL's as resrc.it rely on sites being publically accessible, and if you're kicking of development you're probably working on `http://localhost:8888` 14 | 15 | Once you're up and running on a real server you just add the following lines to your 16 | 17 | ``` 18 | c::set('resrc', true); 19 | c::set('resrc.plan', 'app'); /* app or trial */ 20 | ``` 21 | 22 | ## Further reading 23 | 24 | Checkout [ReSRC support](http://www.resrc.it/support) for more information about exactly how best to implement it within your template. 25 | 26 | ## Author 27 | Luke Watts 28 | -------------------------------------------------------------------------------- /plugins/resrc/resrc.php: -------------------------------------------------------------------------------- 1 | resrc( array( 8 | 'url' => $url 9 | ) ); 10 | } 11 | 12 | class kirbytextExtended extends kirbytext { 13 | function __construct($text = false, $markdown=true) { 14 | parent::__construct($text, $markdown); 15 | 16 | $this->addTags('resrc'); 17 | } 18 | 19 | function resrc($params) { 20 | $url = @$params['url']; 21 | 22 | $version_of_resrc = c::get('resrc.plan') ? c::get('resrc.plan') : 'app'; 23 | 24 | return c::get('resrc') ? 'http://' . $version_of_resrc . '.resrc.it/' . $url : $url; 25 | } 26 | } -------------------------------------------------------------------------------- /plugins/search/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + added include option with "all", "visible" and "invisible" modes. 5 | 6 | ## v0.9 7 | + Initial release -------------------------------------------------------------------------------- /plugins/search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search", 3 | "readable": "Search", 4 | "version": "0.9", 5 | "stable": true, 6 | "description": "Provide a search form for your site", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/search/readme.mdown: -------------------------------------------------------------------------------- 1 | # Search Plugin (Beta) 2 | 3 | ## What is it? 4 | 5 | The search plugin makes it possible to search the entire content of your site and to build a nice search form for your users. 6 | 7 | ## Installation 8 | 9 | Put the search.php file in your site/plugins folder. 10 | 11 | ## How to use it? 12 | 13 | $search = new search(array('searchfield' => 'search')); 14 | $results = $search->results(); 15 | 16 | ## Available options 17 | 18 | ### searchfield 19 | 20 | The name of the html search field. This will also build the param in your URL: 21 | http://yourdomain.com/search/fieldname:searchword 22 | 23 | ### query 24 | 25 | Instead of passing a search field you can also pass a query string instead, which will be used to search for. The search won't be connected to a search form that way, but you can use it to manually search by that query. 26 | 27 | ### fields 28 | 29 | An array of field names to search in. By default all fields will be searched. 30 | 31 | ### mode ("and" or "or" | default is "or") 32 | 33 | Switch between "and" or "or" as search mode. 34 | 35 | ### score 36 | 37 | An array with field names as keys and score values, which will be mulitplied with the hits per field to get a more valid result 38 | 39 | ### words (default = false) 40 | 41 | Set this to true to search for full words only instead of strings within words. 42 | 43 | ### ignore 44 | 45 | An array of uris which should be ignored. This is perfect to not show "secret" pages in results or to skip the error page for example. 46 | 47 | ### include 48 | 49 | The include option makes it possible to take control of which pages are included in search results. You get the following options: "all", "visible", "invisible" 50 | 51 | ### in 52 | 53 | Specify a URI here to search within the children of that page instead of the entire site. 54 | 55 | ### minlength 56 | 57 | The minimum length of searchwords. 58 | 59 | ### stopwords 60 | 61 | An array of stopwords, which will not be considered during search. 62 | 63 | ### paginate 64 | 65 | Automatically paginate the final result. Add a number of rows to return for each result page. 66 | 67 | ## Author 68 | Bastian Allgeier 69 | -------------------------------------------------------------------------------- /plugins/search/search.php: -------------------------------------------------------------------------------- 1 | fields = a::get($options, 'fields', array()); 54 | $this->score = a::get($options, 'score', array()); 55 | $this->words = a::get($options, 'words'); 56 | $this->ignore = a::get($options, 'ignore', array()); 57 | $this->include = a::get($options, 'include', 'all'); 58 | $this->in = a::get($options, 'in'); 59 | $this->minlength = a::get($options, 'minlength', false); 60 | $this->stopwords = a::get($options, 'stopwords', array()); 61 | $this->query = a::get($options, 'query', false); 62 | $this->searchfield = a::get($options, 'searchfield', false); 63 | $this->paginate = a::get($options, 'paginate', false); 64 | $this->mode = str::lower(a::get($options, 'mode')) == 'and' ? 'and' : 'or'; 65 | 66 | $result = array(); 67 | 68 | // if you set a searchfield instead of a query 69 | // the query will automatically be fetched from 70 | // post or get requests 71 | if($this->searchfield) { 72 | $this->query = trim(urldecode(get($this->searchfield))); 73 | } 74 | 75 | // stop here if no searchword is found 76 | if(empty($this->query)) return false; 77 | 78 | $this->searchwords = preg_replace('/[^\pL]/u',',', preg_quote($this->query)); 79 | $this->searchwords = str::split($this->searchwords, ',', $this->minlength); 80 | 81 | if(!empty($this->stopwords)) { 82 | $this->searchwords = array_diff($this->searchwords, $this->stopwords); 83 | } 84 | 85 | if(empty($this->searchwords)) return false; 86 | 87 | // do this to save the count function for all loops 88 | $countSearchwords = count($this->searchwords); 89 | 90 | // define the set of pages to search in 91 | $pages = ($this->in) ? $site->pages()->find($this->in)->children()->index() : $site->pages()->index(); 92 | 93 | foreach($pages as $page) { 94 | 95 | if($this->include == 'visible' && !$page->isVisible()) continue; 96 | if($this->include == 'invisible' && $page->isVisible()) continue; 97 | 98 | if(in_array($page->uri(), $this->ignore)) continue; 99 | 100 | if(!empty($this->fields)) { 101 | $keys = array_intersect(array_keys($page->content->variables), $this->fields); 102 | } else if($page->content) { 103 | $keys = array_keys($page->content->variables); 104 | } 105 | 106 | $found = array(); 107 | $matchedTotal = 0; 108 | $score = 0; 109 | 110 | foreach($keys as $field) { 111 | $value = $page->$field; 112 | 113 | $matchedPerField = 0; 114 | $matchedWords = 0; 115 | $fieldScore = a::get($this->score, $field, 1); 116 | 117 | foreach($this->searchwords as $s) { 118 | 119 | // only match words 120 | if($this->words) { 121 | $m = @preg_match_all('!\b' . $s . '\b!i', $value, $array); 122 | } else { 123 | $m = @preg_match_all('!' . $s . '!i', $value, $array); 124 | } 125 | 126 | // track matched search words 127 | if($m) $matchedWords++; 128 | 129 | // add the matches to the page 130 | $matchedPerField = $matchedPerField+$m; 131 | 132 | } 133 | 134 | if( 135 | $this->mode == 'and' && $countSearchwords == $matchedWords && $matchedPerField > 0 || 136 | $this->mode == 'or' && $matchedPerField > 0 137 | ) { 138 | // add the number of hits; 139 | $matchedTotal = $matchedTotal+$matchedPerField; 140 | 141 | // apply the score for this field 142 | $score = $score+($matchedPerField*$fieldScore); 143 | } 144 | 145 | } 146 | 147 | // add all matched pages to the result set 148 | if($matchedTotal) { 149 | $result[$page->uid] = $page; 150 | $result[$page->uid]->searchHits = $matchedTotal; 151 | $result[$page->uid]->searchScore = $score; 152 | } 153 | 154 | } 155 | 156 | if(empty($result)) return false; 157 | 158 | $pages = new pages($result); 159 | $pages = $pages->sortBy('searchScore','desc'); 160 | 161 | // add pagination 162 | if($this->paginate) $pages = $pages->paginate($this->paginate, array('mode' => 'query')); 163 | 164 | $this->results = $pages; 165 | 166 | } 167 | 168 | function results() { 169 | return $this->results; 170 | } 171 | 172 | function query() { 173 | return $this->query; 174 | } 175 | 176 | } -------------------------------------------------------------------------------- /plugins/sublimevideo/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.1 4 | + Initial release -------------------------------------------------------------------------------- /plugins/sublimevideo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sublimevideo", 3 | "readable": "SublimeVideo", 4 | "version": "1.1", 5 | "stable": true, 6 | "description": "Use the SublimeVideo HTML5 player to display videos", 7 | "author": "Thibaut Ninove", 8 | "url": "http://wooconcept.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/sublimevideo/readme.mdown: -------------------------------------------------------------------------------- 1 | # SublimeVideo 2 | 3 | ## What is it? 4 | 5 | This plugin is a Kirbytext extension, in order to easily use the [SublimeVideo HTML5 Player](http://sublimevideo.net/). It provides you with a new tag: 6 | 7 | (sublime: video-name width: xxx height: yyy) 8 | 9 | ## Installation 10 | 11 | 1. Copy the `sublimevideo.php` file into your `site/plugins` folder. If the plugins folder doesn't exist yet, please create it. As a plugin, the file will be automatically loaded by Kirby. 12 | 13 | 2. Put your SublimeVideo embed code inside the `` tag of your site. It should look like this : 14 | 15 | ```html 16 | 17 | ``` 18 | 19 | Please note that you need to have a [SublimeVideo account](http://sublimevideo.net/plans) (free). This service is very easy to use but if you need help, please refer to [their documentation](http://docs.sublimevideo.net/quickstart-guide). I am also not going to discuss [video encoding](http://docs.sublimevideo.net/encode-videos-for-the-web) here. 20 | 21 | ## How to use it? 22 | 23 | This tag will load all video files and an image poster file from the current page folder, which match the video-name value. Here's a list of example files: 24 | 25 | - myvideo.hd.mp4 26 | - myvideo.hd.ogv 27 | - myvideo.hd.webm 28 | - myvideo.mobile.mp4 29 | - myvideo.mobile.ogv 30 | - myvideo.mobile.webm 31 | - myvideo.poster.png 32 | - myvideo.standard.mp4 33 | - myvideo.standard.ogv 34 | 35 | Use the tag… 36 | 37 | (sublime: myvideo width: 400 height: 300) 38 | 39 | …in your text to automatically load the SublimeVideo with all matching files. 40 | 41 | Adding `.hd` and `.standard` to files with the same extension will mark files as HD and low-res video files and will enable [SublimeVideo HD switching](http://docs.sublimevideo.net/hd-switching) You can also add the `.mobile` prefix to specify a file, which will be used on mobile devices. 42 | 43 | If you add an additional image file with the same naming convention (i.e. `myvideo.poster.png`) this file will be used as a preview as long as the video has not been loaded yet and if video playback is not available. 44 | 45 | ### Attributes 46 | 47 | - `sublime`: the files common name 48 | - `width`: the width of the video 49 | - `height`: the height of the video 50 | - `uid`: a unique id (optional), which will appear in the [SublimeVideo stats](http://docs.sublimevideo.net/optimize-for-stats) 51 | - `name`: the name of the video (optional), which will appear in the [SublimeVideo stats](http://docs.sublimevideo.net/optimize-for-stats) 52 | - `class`: an additional class name, which will be added to the video tag. SublimeVideo tags already have a sublime class by default, but you can use this optionally to add another class. 53 | 54 | ### Full Example 55 | 56 | (sublime: myvideo width: 540 height: 304 name: My awesome video uid: myvideo class: myvideo) 57 | 58 | ## Shortcut 59 | 60 | If you need to embed SublimeVideos directly in your template or snippet files you can use the available shortcut function: 61 | 62 | ```php 63 | 64 | 65 | 66 | ``` 67 | 68 | ## Support 69 | 70 | Provided as is, no support provided 71 | 72 | ## Author 73 | 74 | Author: Thibaut Ninove ([WooConcept](http://wooconcept.com)) 75 | Contributor: Bastian Allgeier -------------------------------------------------------------------------------- /plugins/sublimevideo/sublimevideo.php: -------------------------------------------------------------------------------- 1 | , with the help of Bastian Allgeier 6 | // Support: provided as is, no support provided 7 | 8 | 9 | // shortcut function to add sublime videos to templates and snippets as well. 10 | function sublime($id, $width=false, $height=false, $uid=false, $name=false, $class=false) { 11 | $kirbytext = kirbytext::classname(); 12 | $obj = new $kirbytext(); 13 | return $obj->sublime(array( 14 | 'sublime' => $id, 15 | 'width' => $width, 16 | 'height' => $height, 17 | 'uid' => ($uid) ? $uid : $id, 18 | 'name' => ($name) ? $name : $id, 19 | 'class' => $class 20 | )); 21 | } 22 | 23 | 24 | // kirbytext extension 25 | class kirbytextExtended extends kirbytext { 26 | 27 | function __construct($text=false, $markdown=true) { 28 | 29 | parent::__construct($text, $markdown); 30 | 31 | $this->addTags('sublime'); 32 | $this->addAttributes('uid', 'name'); 33 | 34 | } 35 | 36 | function sublime($params) { 37 | 38 | global $site; 39 | 40 | $page = ($this->obj) ? $this->obj : $site->pages()->active(); 41 | $id = @$params['sublime']; 42 | $class = @$params['class']; 43 | $videos = array(); 44 | $poster = false; 45 | 46 | // gather all video files which match the given id/name 47 | foreach($page->videos() as $v) { 48 | 49 | if(preg_match('!^' . preg_quote($id) . '!i', $v->name())) { 50 | 51 | $extension = f::extension($v->name()); 52 | $mobile = ($extension == 'mobile') ? $v->mobile = true : $v->mobile = false; 53 | $hd = ($extension == 'hd') ? $v->hd = true : $v->hd = false; 54 | 55 | $videos[] = $v; 56 | 57 | } 58 | 59 | } 60 | 61 | if(empty($videos)) return false; 62 | 63 | // find the poster for this video 64 | foreach($page->images() as $i) { 65 | if(preg_match('!^' . preg_quote($id) . '!i', $i->name())) { 66 | $poster = $i; 67 | break; 68 | } 69 | } 70 | 71 | $defaults = array( 72 | 'width' => 400, 73 | 'height' => 300, 74 | 'uid' => $id, 75 | 'name' => $id, 76 | ); 77 | 78 | $options = array_merge($defaults, $params); 79 | $width = html($options['width']); 80 | $height = html($options['height']); 81 | $uid = html($options['uid']); 82 | $name = html($options['name']); 83 | 84 | if(!$width) $width = c::get('kirbytext.video.width'); 85 | if(!$height) $height = c::get('kirbytext.video.height'); 86 | 87 | // create an additional css class if specified 88 | if(!empty($class)) $class = ' ' . html($class); 89 | 90 | // check for a poster 91 | $poster = ($poster) ? ' poster="' . $poster->url() . '"' : false; 92 | 93 | $html = ''; 101 | 102 | return $html; 103 | 104 | } 105 | 106 | } -------------------------------------------------------------------------------- /plugins/tagcloud/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.9 4 | + Initial release -------------------------------------------------------------------------------- /plugins/tagcloud/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tagcloud", 3 | "readable": "Tagcloud", 4 | "version": "0.9", 5 | "stable": true, 6 | "description": "Display a tag cloud", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/tagcloud/readme.mdown: -------------------------------------------------------------------------------- 1 | # Tagcloud Plugin (Beta) 2 | 3 | ## What is it? 4 | 5 | The tagcloud plugin will fetch all tags (comma separated) from subpages and return them with additional information - like the number of subpages for a each tag. 6 | 7 | ## Installation 8 | 9 | Put the tagcloud.php file in your site/plugins folder. 10 | 11 | ## How to use it? 12 | 13 | ### Content files 14 | 15 | To add tags to your content files, put them in a comma separated list: 16 | 17 | Title: Some Title 18 | ---- 19 | Text: Some Text 20 | ---- 21 | Tags: design, fun, photography 22 | ---- 23 | 24 | In your template add i.e.: 25 | 26 | find('blog'), array('limit' => 20)) ?> 27 | 28 | 33 | 34 | 35 | As first argument you pass the main page. All children of it will be searched to find all tags. So if you have a blog and you want to find all tags of blog articles you add pass the main blog page as first argument. 36 | 37 | 38 | ## Available options 39 | 40 | ### limit 41 | 42 | The number of tags in your tagcloud. If not specified, all tags will be returned. 43 | 44 | ### field 45 | 46 | The name of the Tags field in your content files. By default this is "tags" 47 | 48 | ### children 49 | 50 | Which children of the given page should be searched? Possible values are "all", "visible", "invisible". Default is "visible" 51 | 52 | ### baseurl 53 | 54 | The base URL, which will be used to build tag URLs. By default the URL of the given page. 55 | 56 | ### param 57 | 58 | The name of the param, which will be used for the URL. By default this is just "tag". So the default URL will be "http://yourdomain.com/given-page/tag:design" for example 59 | 60 | ### sort 61 | 62 | The field to sort by. By default the tagcloud will be sorted by the number of results per tag, but you can also sort it by tag name for example. 63 | 64 | ### sortdir 65 | 66 | The sort direction. Can be "desc" or "asc". Default is "desc" 67 | 68 | 69 | ## Author 70 | Bastian Allgeier 71 | -------------------------------------------------------------------------------- /plugins/tagcloud/tagcloud.php: -------------------------------------------------------------------------------- 1 | false, 10 | 'field' => 'tags', 11 | 'children' => 'visible', 12 | 'baseurl' => $parent->url(), 13 | 'param' => 'tag', 14 | 'sort' => 'results', 15 | 'sortdir' => 'desc' 16 | ); 17 | 18 | // merge defaults and options 19 | $options = array_merge($defaults, $options); 20 | 21 | switch($options['children']) { 22 | case 'invisible': 23 | $children = $parent->children()->invisible(); 24 | break; 25 | case 'visible': 26 | $children = $parent->children()->visible(); 27 | break; 28 | default: 29 | $children = $parent->children(); 30 | break; 31 | } 32 | 33 | $cloud = array(); 34 | $ds = DIRECTORY_SEPARATOR == '/' ? ':' : ';'; 35 | 36 | foreach($children as $p) { 37 | 38 | $tags = str::split($p->$options['field']()); 39 | 40 | foreach($tags as $t) { 41 | 42 | if(isset($cloud[$t])) { 43 | $cloud[$t]->results++; 44 | } else { 45 | $cloud[$t] = new obj(array( 46 | 'results' => 1, 47 | 'name' => $t, 48 | 'url' => $options['baseurl'] . '/' . $options['param'] . $ds . $t, 49 | 'isActive' => (param($options['param']) == $t) ? true : false, 50 | )); 51 | } 52 | 53 | } 54 | 55 | } 56 | 57 | $cloud = a::sort($cloud, $options['sort'], $options['sortdir']); 58 | 59 | if($options['limit']) { 60 | $cloud = array_slice($cloud, 0, $options['limit']); 61 | } 62 | 63 | return $cloud; 64 | 65 | } -------------------------------------------------------------------------------- /plugins/thumb/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.2 4 | 5 | - grayscale mode 6 | - timestamp is attached to thumbnail files 7 | 8 | ## v1.1 9 | + Initial release -------------------------------------------------------------------------------- /plugins/thumb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "thumb", 3 | "readable": "Thumb", 4 | "version": "1.1", 5 | "stable": true, 6 | "description": "Generate smaller versions of your images on the fly", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/thumb/readme.mdown: -------------------------------------------------------------------------------- 1 | # Thumb Plugin 2 | 3 | ## What is it? 4 | 5 | The thumb plugin makes it easy to include smaller, resized versions of your images in your pages without adding extra code or uploading smaller versions yourself. 6 | 7 | ## Installation 8 | 9 | Put the thumb.php file in your site/plugins folder. Add the plugins folder if it isn't there yet. Add a thumbs folder to the root dir of your site and make sure it is writable. If you want to change the location of your thumbs cache folder read more about the available default settings further down. 10 | 11 | ## How to use it? 12 | 13 | 200, 'height' => 150)); ?> 14 | 15 | or a more extended version: 16 | 17 | thumb($image, array( 18 | 'width' => 200, 19 | 'height' => 200, 20 | 'quality' => 90, 21 | 'upscale' => true, 22 | 'crop' => true, 23 | 'grayscale' => true 24 | )); 25 | 26 | ## Available options 27 | 28 | ### width 29 | 30 | set the maximum width of your image 31 | 32 | ### height 33 | 34 | set the maximum height of your image 35 | 36 | ### quality 37 | 38 | set the jpeg compression quality of your image. (0-100) 39 | 40 | ### upscale 41 | 42 | If this is set to true, images will be upscaled to the maximum height or width. 43 | 44 | ### crop 45 | 46 | Set this to true to crop the image to the given width and height. Upscale is true by default in this case. 47 | 48 | ### grayscale 49 | 50 | If set to true RGB images will be converted to grayscale 51 | 52 | ### datauri 53 | 54 | If set to true image URLs will be converted to data:URIs 55 | 56 | ## Available settings 57 | 58 | You can add the following config variables to your config file (site/config/config.php) to adjust the default settings of the thumb plugin: 59 | 60 | c::set('thumb.cache.root', c::get('root') . '/thumbs'); 61 | c::set('thumb.cache.url', c::get('url') . '/thumbs'); 62 | c::set('thumb.quality', 100); 63 | c::set('thumb.upscale', false); 64 | c::set('thumb.datauri', false); 65 | 66 | ## Requirements 67 | 68 | You must have GD Lib installed on your server to make this work. 69 | 70 | ## Author 71 | Bastian Allgeier 72 | -------------------------------------------------------------------------------- /plugins/thumb/thumb.php: -------------------------------------------------------------------------------- 1 | tag() : $thumb->url(); 6 | } 7 | 8 | class thumb { 9 | 10 | var $obj = null; 11 | var $root = false; 12 | var $url = false; 13 | var $sourceWidth = 0; 14 | var $sourceHeight = 0; 15 | var $width = 0; 16 | var $height = 0; 17 | var $tmpWidth = 0; 18 | var $tmpHeight = 0; 19 | var $maxWidth = 0; 20 | var $maxHeight = 0; 21 | var $mime = false; 22 | var $status = array(); 23 | var $upscale = false; 24 | var $quality = 100; 25 | var $alt = false; 26 | var $crop = false; 27 | var $grayscale = false; 28 | var $datauri = false; 29 | 30 | function __construct($image, $options=array()) { 31 | 32 | $this->root = c::get('thumb.cache.root', c::get('root') . '/thumbs'); 33 | $this->url = c::get('thumb.cache.url', c::get('url') . '/thumbs'); 34 | 35 | if(!$image) return false; 36 | 37 | $this->obj = $image; 38 | 39 | // set some values from the image 40 | $this->sourceWidth = $this->obj->width(); 41 | $this->sourceHeight = $this->obj->height(); 42 | $this->width = $this->sourceWidth; 43 | $this->height = $this->sourceHeight; 44 | $this->source = $this->obj->root(); 45 | $this->mime = $this->obj->mime(); 46 | 47 | // set the max width and height 48 | $this->maxWidth = @$options['width']; 49 | $this->maxHeight = @$options['height']; 50 | 51 | // set crop on/off 52 | $this->crop = @$options['crop']; 53 | 54 | // set greyscale on/off 55 | $this->grayscale = @$options['grayscale']; 56 | 57 | // set the quality 58 | $this->quality = a::get($options, 'quality', c::get('thumb.quality', 100)); 59 | 60 | // set the default upscale behavior 61 | $this->upscale = a::get($options, 'upscale', c::get('thumb.upscale', false)); 62 | 63 | // set datauri on/off 64 | $this->datauri = a::get($options, 'datauri', c::get('thumb.datauri', false)); 65 | 66 | // set the alt text 67 | $this->alt = a::get($options, 'alt', $this->obj->name()); 68 | 69 | // set the className text 70 | $this->className = @$options['class']; 71 | 72 | // set the new size 73 | $this->size(); 74 | 75 | // create the thumbnail 76 | $this->create(); 77 | 78 | } 79 | 80 | function tag() { 81 | 82 | if(!$this->obj) return false; 83 | 84 | $class = (!empty($this->className)) ? ' class="' . $this->className . '"' : ''; 85 | 86 | return ''; 87 | 88 | } 89 | 90 | function filename() { 91 | 92 | $options = false; 93 | 94 | $options .= ($this->maxWidth) ? '.' . $this->maxWidth : '.' . 0; 95 | $options .= ($this->maxHeight) ? '.' . $this->maxHeight : '.' . 0; 96 | $options .= ($this->upscale) ? '.' . $this->upscale : '.' . 0; 97 | $options .= ($this->crop) ? '.' . $this->crop : '.' . 0; 98 | $options .= ($this->grayscale) ? '.' . $this->grayscale : '.' . 0; 99 | $options .= '.' . $this->quality; 100 | 101 | return md5($this->source) . $options . '.' . $this->obj->extension; 102 | 103 | } 104 | 105 | function file() { 106 | return $this->root . '/' . $this->filename(); 107 | } 108 | 109 | function url() { 110 | if($this->datauri == true) { 111 | return (error($this->status)) ? $this->obj->url() : 'data:' . $this->mime . ';base64,' . base64_encode(file_get_contents($this->file())); 112 | } else { 113 | return (error($this->status)) ? $this->obj->url() : $this->url . '/' . $this->filename() . '?' . filemtime($this->file()); 114 | } 115 | } 116 | 117 | function size() { 118 | 119 | $maxWidth = $this->maxWidth; 120 | $maxHeight = $this->maxHeight; 121 | $upscale = $this->upscale; 122 | 123 | if($this->crop == true) { 124 | 125 | if(!$maxWidth) $maxWidth = $maxHeight; 126 | if(!$maxHeight) $maxHeight = $maxWidth; 127 | 128 | $sourceRatio = size::ratio($this->sourceWidth, $this->sourceHeight); 129 | $thumbRatio = size::ratio($maxWidth, $maxHeight); 130 | 131 | if($sourceRatio > $thumbRatio) { 132 | // fit the height of the source 133 | $size = size::fit_height($this->sourceWidth, $this->sourceHeight, $maxHeight, true); 134 | } else { 135 | // fit the height of the source 136 | $size = size::fit_width($this->sourceWidth, $this->sourceHeight, $maxWidth, true); 137 | } 138 | 139 | $this->tmpWidth = $size['width']; 140 | $this->tmpHeight = $size['height']; 141 | $this->width = $maxWidth; 142 | $this->height = $maxHeight; 143 | 144 | return $size; 145 | 146 | } 147 | 148 | // if there's a maxWidth and a maxHeight 149 | if($maxWidth && $maxHeight) { 150 | 151 | // if the source width is bigger then the source height 152 | // we need to fit the width 153 | if($this->sourceWidth > $this->sourceHeight) { 154 | $size = size::fit_width($this->sourceWidth, $this->sourceHeight, $maxWidth, $upscale); 155 | 156 | // do another check for the maxHeight 157 | if($size['height'] > $maxHeight) $size = size::fit_height($size['width'], $size['height'], $maxHeight); 158 | 159 | } else { 160 | $size = size::fit_height($this->sourceWidth, $this->sourceHeight, $maxHeight, $upscale); 161 | 162 | // do another check for the maxWidth 163 | if($size['width'] > $maxWidth) $size = size::fit_width($size['width'], $size['height'], $maxWidth); 164 | 165 | } 166 | 167 | } elseif($maxWidth) { 168 | $size = size::fit_width($this->sourceWidth, $this->sourceHeight, $maxWidth, $upscale); 169 | } elseif($maxHeight) { 170 | $size = size::fit_height($this->sourceWidth, $this->sourceHeight, $maxHeight, $upscale); 171 | } else { 172 | $size = array('width' => $this->sourceWidth, 'height' => $this->sourceHeight); 173 | } 174 | 175 | $this->width = $size['width']; 176 | $this->height = $size['height']; 177 | 178 | return $size; 179 | 180 | } 181 | 182 | function create() { 183 | 184 | $file = $this->file(); 185 | 186 | if(!function_exists('gd_info')) return $this->status = array( 187 | 'status' => 'error', 188 | 'msg' => 'GD Lib is not installed' 189 | ); 190 | 191 | if(file_exists($file) && (filectime($this->source) < filectime($file) || filemtime($this->source) < filemtime($file))) return $this->status = array( 192 | 'status' => 'success', 193 | 'msg' => 'The file exists' 194 | ); 195 | 196 | if(!is_writable(dirname($file))) return $this->status = array( 197 | 'status' => 'error', 198 | 'msg' => 'The image file is not writable' 199 | ); 200 | 201 | switch($this->mime) { 202 | case 'image/jpeg': 203 | $image = @imagecreatefromjpeg($this->source); 204 | break; 205 | case 'image/png': 206 | $image = @imagecreatefrompng($this->source); 207 | break; 208 | case 'image/gif': 209 | $image = @imagecreatefromgif($this->source); 210 | break; 211 | default: 212 | return $this->status = array( 213 | 'status' => 'error', 214 | 'msg' => 'The image mime type is invalid' 215 | ); 216 | break; 217 | } 218 | 219 | if(!$image) return array( 220 | 'status' => 'error', 221 | 'msg' => 'The image could not be created' 222 | ); 223 | 224 | // make enough memory available to scale bigger images (option should be something like 36M) 225 | if(c::get('thumb.memory')) ini_set('memory_limit', c::get('thumb.memory')); 226 | 227 | if($this->crop == true) { 228 | 229 | // Starting point of crop 230 | $startX = floor($this->tmpWidth / 2) - floor($this->width / 2); 231 | $startY = floor($this->tmpHeight / 2) - floor($this->height / 2); 232 | 233 | // Adjust crop size if the image is too small 234 | if($startX < 0) $startX = 0; 235 | if($startY < 0) $startY = 0; 236 | 237 | // create a temporary resized version of the image first 238 | $thumb = imagecreatetruecolor($this->tmpWidth, $this->tmpHeight); 239 | imagesavealpha($thumb, true); 240 | $color = imagecolorallocatealpha($thumb, 0, 0, 0, 127); 241 | imagefill($thumb, 0, 0, $color); 242 | imagecopyresampled($thumb, $image, 0, 0, 0, 0, $this->tmpWidth, $this->tmpHeight, $this->sourceWidth, $this->sourceHeight); 243 | 244 | // crop that image afterwards 245 | $cropped = imagecreatetruecolor($this->width, $this->height); 246 | imagesavealpha($cropped, true); 247 | $color = imagecolorallocatealpha($cropped, 0, 0, 0, 127); 248 | imagefill($cropped, 0, 0, $color); 249 | imagecopyresampled($cropped, $thumb, 0, 0, $startX, $startY, $this->tmpWidth, $this->tmpHeight, $this->tmpWidth, $this->tmpHeight); 250 | imagedestroy($thumb); 251 | 252 | // reasign the variable 253 | $thumb = $cropped; 254 | 255 | } else { 256 | $thumb = imagecreatetruecolor($this->width, $this->height); 257 | imagesavealpha($thumb, true); 258 | $color = imagecolorallocatealpha($thumb, 0, 0, 0, 127); 259 | imagefill($thumb, 0, 0, $color); 260 | imagecopyresampled($thumb, $image, 0, 0, 0, 0, $this->width, $this->height, $this->sourceWidth, $this->sourceHeight); 261 | } 262 | 263 | if($this->grayscale == true) { 264 | imagefilter($thumb, IMG_FILTER_GRAYSCALE); 265 | } 266 | 267 | switch($this->mime) { 268 | case 'image/jpeg': imagejpeg($thumb, $file, $this->quality); break; 269 | case 'image/png' : imagepng($thumb, $file, 0); break; 270 | case 'image/gif' : imagegif($thumb, $file); break; 271 | } 272 | 273 | imagedestroy($thumb); 274 | 275 | return $this->status = array( 276 | 'status' => 'success', 277 | 'msg' => 'The image has been created', 278 | ); 279 | 280 | } 281 | 282 | } -------------------------------------------------------------------------------- /plugins/tweets/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /plugins/tweets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tweets", 3 | "readable": "Tweets", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Display the latest tweets from any public Twitter account", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /plugins/tweets/readme.mdown: -------------------------------------------------------------------------------- 1 | # Tweets Plugin 2 | 3 | ## What is it? 4 | 5 | It's a little plugin to display the latest Tweets from any public Twitter account. 6 | 7 | ## Installation 8 | 9 | Copy the tweet.php file to your site/plugins folder. 10 | You should make sure to enable caching. Otherwise the plugin will call the Twitter API on every page view and you might soon be blocked. 11 | 12 | - Go to site/config/config.php to set c::set('cache', true); 13 | - Make sure that site/cache is writable (change permissions to 0755) 14 | 15 | ## How to use it? 16 | 17 | You can add it to your templates like this: 18 | 19 | 20 | 21 | 34 | 35 | 36 | ## Available Options 37 | 38 | Set options like this: 39 | 40 | 5, 44 | 'refresh' => 60*60*5 45 | )); 46 | 47 | ?> 48 | 49 | ### limit (default: 10) 50 | 51 | Sets the number of returned tweets. 52 | 53 | ### cache (default: true) 54 | 55 | Disable or enable the cache. Caching the results is highly recommended. Otherwise the plugin will be super slow. You must make sure that `site/cache` is writable (change permissions to 0755) You must also set c::set('cache', true); in site/config/config.php to enable the cache. 56 | 57 | ### hiderep (default: false) 58 | 59 | Show or hide replies you've tweeted, e.g. for users with a large number of replies that aren't interesting for the general public. 60 | 61 | ### refresh (default: 20 minutes) 62 | 63 | Set the cache expiry in seconds. By default it will be set to 20 minutes. After 20 minutes the plugin will fetch fresh data from the Twitter API. 64 | 65 | 66 | ## Attributes for the tweet-object 67 | 68 | * `$tweet->url()` The URL to the Tweet page on Twitter 69 | * `$tweet->text()` The text of the Tweet 70 | * `$tweet->date()` The timestamp when the Tweet has been posted 71 | * `$tweet->source()` The source, from which the Tweet has been posted 72 | * `$tweet->user()` The user object (see object attributes) 73 | 74 | ## Attributes for the user-object 75 | 76 | * `$tweet->user()->name()` The full name of the user 77 | * `$tweet->user()->username()` The Twitter username 78 | * `$tweet->user()->bio()` The Twitter bio 79 | * `$tweet->user()->url()` The URL to the user's Twitter page 80 | * `$tweet->user()->image()` The user avatar pic 81 | * `$tweet->user()->following()` The number of accounts the user is following 82 | * `$tweet->user()->followers()` The number of followers 83 | 84 | 85 | ## Author 86 | Bastian Allgeier 87 | 88 | -------------------------------------------------------------------------------- /plugins/tweets/tweets.php: -------------------------------------------------------------------------------- 1 | 10, 7 | 'cache' => true, 8 | 'hiderep' => false, //Parameter to hide replies in your feed - for accounts with high reply volumes 9 | 'refresh' => 60*20 // refresh every 20 minutes 10 | ); 11 | 12 | // add the username to the defaults array 13 | $defaults['username'] = $username; 14 | 15 | $options = array_merge($defaults, $params); 16 | 17 | // check the cache dir 18 | $cacheDir = c::get('root.cache') . '/tweets'; 19 | dir::make($cacheDir); 20 | 21 | // disable the cache if adding the cache dir failed 22 | if(!is_dir($cacheDir) || !is_writable($cacheDir)) $options['cache'] = false; 23 | 24 | // sanitize the limit 25 | if($options['limit'] > 200) $options['limit'] = 200; 26 | 27 | // generate a unique cache ID 28 | $cacheID = 'tweets/tweets.' . md5($options['username']) . '.' . $options['limit'] . '.php'; 29 | 30 | if($options['cache']) { 31 | $cache = (cache::modified($cacheID) < time()-$options['refresh']) ? false : cache::get($cacheID); 32 | } else { 33 | $cache = false; 34 | } 35 | 36 | if(!empty($cache)) return $cache; 37 | 38 | // Encode the key and secret from the Twitter config. 39 | $twitterKey = urlencode(c::get('twitter.key')); 40 | $twitterSecret = urlencode(c::get('twitter.secret')); 41 | 42 | // combine and base64 encode the key and secret with a colon seperator 43 | $twitterCode = base64_encode( $twitterKey . ':' . $twitterSecret ); 44 | 45 | // obtain a bearer token from the api, by building a request 46 | 47 | //url to use 48 | $url = 'https://api.twitter.com/oauth2/token'; 49 | 50 | //create header 51 | $header = array( 52 | 'http' => array( 53 | 'method' => "POST", 54 | 'header' => "Content-type: application/x-www-form-urlencoded;charset=UTF-8\r\n" 55 | ."Authorization: Basic " . $twitterCode ."\r\n", 56 | 'content' => "grant_type=client_credentials", 57 | ), 58 | ); 59 | 60 | //send the request 61 | $context = stream_context_create($header); 62 | $bearer = file_get_contents($url, false, $context); 63 | 64 | // decode the json response 65 | $bearer = json_decode($bearer); 66 | 67 | // send the rquest for tweets 68 | 69 | $url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=' . $options['username'] . '&count=' . $options['limit']. '&include_rts=true' . '&exclude_replies=' . $options['hiderep']; 70 | 71 | $header = array( 72 | 'http' => array( 73 | 'method' => "GET", 74 | 'header' => "Authorization: Bearer " . $bearer->access_token ."\r\n", 75 | ), 76 | ); 77 | 78 | $context = stream_context_create($header); 79 | 80 | $json = file_get_contents($url, false, $context); 81 | 82 | $data = json_decode($json); 83 | 84 | if(!$data) return false; 85 | 86 | $result = array(); 87 | 88 | foreach($data as $tweet) { 89 | 90 | $user = $tweet->user; 91 | 92 | $result[] = new tweet(array( 93 | 'url' => 'http://twitter.com/' . $options['username'] . '/status/' . $tweet->id_str, 94 | 'text' => $tweet->text, 95 | 'date' => strtotime($tweet->created_at), 96 | 'source' => $tweet->source, 97 | 'user' => new obj(array( 98 | 'name' => $user->name, 99 | 'bio' => $user->description, 100 | 'username' => $user->screen_name, 101 | 'url' => 'http://twitter.com/' . $user->screen_name, 102 | 'image' => 'http://twitter.com/api/users/profile_image/' . $user->screen_name, 103 | 'following' => $user->friends_count, 104 | 'followers' => $user->followers_count, 105 | )) 106 | )); 107 | 108 | } 109 | 110 | $result = new obj($result); 111 | 112 | if($options['cache']) cache::set($cacheID, $result); 113 | 114 | return $result; 115 | 116 | } 117 | 118 | class tweet extends obj { 119 | 120 | function date($format=false) { 121 | return ($format) ? date($format, $this->date) : $this->date; 122 | } 123 | 124 | function text($link=false) { 125 | return ($link) ? self::link(html($this->text)) : $this->text; 126 | } 127 | 128 | static function link($text) { 129 | $text = preg_replace('/(http|https):\/\/([a-z0-9_\.\-\+\&\!\#\~\/\,]+)/i', '$1://$2', $text); 130 | $text = preg_replace('/@([A-Za-z0-9_]+)/is', '@$1', $text); 131 | $text = preg_replace('/#([A-Aa-z0-9_-]+)/is', '#$1', $text); 132 | return $text; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /readme.mdown: -------------------------------------------------------------------------------- 1 | # Kirby 1 extensions 2 | 3 | **Deprecated. Please see http://github.com/getkirby** 4 | 5 | -------------------------------------------------------------------------------- /snippets/breadcrumb/breadcrumb.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/breadcrumb/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/breadcrumb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "breadcrumb", 3 | "readable": "Breadcrumb", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Display a breadcrumb navigation on your site", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/breadcrumb/readme.mdown: -------------------------------------------------------------------------------- 1 | # Breadcrumb Snippet 2 | 3 | ## What is it? 4 | 5 | A snippet which generates a breadcrumb for your site: 6 | For example: Home > Projects > Project 1 7 | 8 | ## Installation 9 | 10 | Put the breadcrumb.php file in your site/snippets folder 11 | 12 | ## How to use it? 13 | 14 | 15 | 16 | ## Customization 17 | 18 | Customize the html in site/snippets/breadcrumb.php to fit your site 19 | 20 | ## Author 21 | Bastian Allgeier 22 | -------------------------------------------------------------------------------- /snippets/contactform/contactform.mail.php: -------------------------------------------------------------------------------- 1 | Hey, 2 | 3 | your contact form has been submitted 4 | 5 | Name: {name} 6 | --------- 7 | Email: {email} 8 | --------- 9 | Text: 10 | 11 | {text} 12 | -------------------------------------------------------------------------------- /snippets/contactform/contactform.php: -------------------------------------------------------------------------------- 1 | 'John ', 5 | 'from' => 'Contact Form ', 6 | 'subject' => 'New contact form request', 7 | 'goto' => $page->url() . '/status:thank-you' 8 | )); 9 | 10 | ?> 11 |
    12 | 13 | 14 | 15 |

    Thank you very much for your request

    16 |

    We will get in contact as soon as possible

    17 | 18 | 19 | 20 |

    Get in contact

    21 | 22 |
    23 |
    24 | 25 | isError('send')): ?> 26 |
    The email could not be sent. Please try again later.
    27 | isError()): ?> 28 |
    The form could not be submitted. Please fill in all fields correctly.
    29 | 30 | 31 |
    32 | 33 | 34 |
    35 | 36 |
    37 | 38 | 39 |
    40 | 41 |
    42 | 43 | 44 |
    45 | 46 |

    All fields with * are required

    47 | 48 | 49 | 50 |
    51 |
    52 | 53 | 54 | 55 |
    56 | -------------------------------------------------------------------------------- /snippets/contactform/readme.mdown: -------------------------------------------------------------------------------- 1 | # Contactform Plugin & Snippets (Alpha) 2 | 3 | This plugin helps you render and submit a simple contact form with name, email and text 4 | 5 | ## Installation 6 | Put the `plugins/contactform` folder in this repo in your `site/plugins` folder. If this folder doesn't exist yet, create it. 7 | 8 | ### Installing snippets 9 | Copy the snippets in this folder and add them to `site/snippets` 10 | 11 | ### Add the contact form 12 | 13 | To add the contact form to your site, add the contactform snippet to your templates: 14 | 15 | ``` 16 | 17 | 18 | 19 | ``` 20 | 21 | ### Contact form settings 22 | 23 | Open `site/snippets/contactform.php` to set your email address and other options for the contact form: 24 | 25 | ``` 26 | 27 | $form = new contactform(array( 28 | 'to' => 'John ', 29 | 'from' => 'Contact Form ', 30 | 'subject' => 'New contact form request', 31 | 'goto' => $page->url() . '/status:thank-you' 32 | )); 33 | 34 | ``` 35 | 36 | You can also customize the HTML for the contact form however you need. 37 | 38 | ### Changing the email template 39 | 40 | Open `site/snippets/contactform.mail.php` to customize the email template. The contact form plugin will only send plain text emails. You can use the following placeholders in your template: 41 | 42 | ``` 43 | 44 | {name} 45 | {email} 46 | {text} 47 | 48 | ``` 49 | 50 | ## Requirements 51 | 52 | Since the plugin works with PHP closures, you need to run your site on PHP 5.3 + Older versions are not supported 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /snippets/disqus/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/disqus/disqus.php: -------------------------------------------------------------------------------- 1 | title(); 6 | if(!isset($disqus_developer)) $disqus_developer = false; 7 | if(!isset($disqus_identifier)) $disqus_identifier = $page->uri(); 8 | if(!isset($disqus_url)) $disqus_url = thisURL(); 9 | 10 | $disqus_title = addcslashes($disqus_title, "'"); 11 | $disqus_developer = ($disqus_developer) ? 'true' : 'false'; 12 | 13 | ?> 14 |
    15 | 28 | 29 | blog comments powered by Disqus 30 | -------------------------------------------------------------------------------- /snippets/disqus/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "disqus", 3 | "readable": "Disqus", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Embed your Disqus comments", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/disqus/readme.mdown: -------------------------------------------------------------------------------- 1 | # Disqus Snippet 1.0 2 | 3 | ## What is it? 4 | 5 | A snippet which makes embedding Disqus comments very easy 6 | 7 | ## Installation 8 | 9 | Put the disqus.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 'yourshortname')) ?> 14 | 15 | ## Options 16 | 17 | ### disqus_title 18 | 19 | The title for your comment thread. This is the page title by default 20 | 21 | ### disqus_developer 22 | 23 | Set this to true to enable developer mode 24 | 25 | ### disqus_identifier 26 | 27 | By default this is the slug for the current page, which is unique. You can set any custom identifier if you want here though. 28 | 29 | ### disqus_url 30 | 31 | By default this is the current page url. 32 | 33 | ## Author 34 | Bastian Allgeier 35 | -------------------------------------------------------------------------------- /snippets/feed/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.1 4 | + Added the descriptionExcerpt option. 5 | * Fixed some bugs 6 | 7 | ## v1.0 8 | + Initial release -------------------------------------------------------------------------------- /snippets/feed/feed.php: -------------------------------------------------------------------------------- 1 | '; 11 | 12 | ?> 13 | 14 | 15 | 16 | 17 | 18 | <?php echo (isset($title)) ? xml($title) : xml($page->title()) ?> 19 | 20 | 21 | modified()) ?> 22 | 23 | 24 | description() || isset($description)): ?> 25 | description()) ?> 26 | 27 | 28 | 29 | 30 | <?php echo xml($item->title()) ?> 31 | url()) ?> 32 | url()) ?> 33 | date()) ? date('r', $item->date()) : date('r', $item->modified()) ?> 34 | 35 | 36 | 37 | {$descriptionField}) ?>]]> 38 | 39 | {$descriptionField}, (isset($descriptionLength)) ? $descriptionLength : 140) ?>]]> 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /snippets/feed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feed", 3 | "readable": "Feed", 4 | "version": "1.1", 5 | "stable": true, 6 | "description": "Setup a RSS feed for your site", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/feed/readme.mdown: -------------------------------------------------------------------------------- 1 | # Feed Snippet 2 | 3 | ## What is it? 4 | 5 | A very simple snippet to help you setup RSS-Feeds for your site. 6 | 7 | ## Installation 8 | 9 | Put the feed.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | find('blog')->children()->visible()->flip()->limit(10); 19 | 20 | // this is how you embed the feed snippet with some options 21 | snippet('feed', array( 22 | 'link' => url('blog'), 23 | 'items' => $items, 24 | 'descriptionField' => 'text', 25 | 'descriptionLength' => 300 26 | )); 27 | 28 | ?> 29 | 30 | ## Available Options 31 | 32 | ### title 33 | 34 | You can specify a title for your feed here. Otherwise the title, which you've added to your content txt (in our case feed.txt) will be used 35 | 36 | ### description 37 | 38 | You can specify a description for your feed here. Otherwise the description, which you've added to your content txt (in our case feed.txt) will be used 39 | 40 | ### link 41 | 42 | Main link in your feed to your site. In this example we want to link to our blog page. 43 | 44 | ### modified 45 | 46 | If you want to specify a modified date, simply pass a timestamp here. Otherwise this will be auto generated by the last modified date of your entire site. 47 | 48 | ### items 49 | 50 | Any set of pages 51 | 52 | ### descriptionExcerpt 53 | 54 | Create an excerpt – which you can control with descriptionLength – or not. This is true by default. 55 | 56 | ### descriptionField 57 | 58 | If you want to show a description for each item in your feed, make sure to specify a field, which is available in any item and should be used for the description. For example every page of our blog has a text field, so we use that for the item description. 59 | 60 | ### descriptionLength 61 | 62 | This is maximum number of characters the description will have. An excerpt is automatically generated. 63 | 64 | ## Author 65 | Bastian Allgeier 66 | 67 | -------------------------------------------------------------------------------- /snippets/filelist/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/filelist/filelist.php: -------------------------------------------------------------------------------- 1 | files(); 10 | 11 | // filter the list of files by extension 12 | if(isset($extension)) $files = $files->findByExtension($extension); 13 | 14 | // sort the list 15 | $files = $files->sortBy($sort, $direction); 16 | 17 | // when excluding files, the UL will still be returned if there are no files to show 18 | foreach($files->_ as $file): 19 | if(in_array($file->extension(),$exclude)) unset($files->_[$file->filename]); 20 | endforeach; 21 | 22 | if(count($files->_)>0): 23 | ?> 24 | 25 | 30 | 31 | -------------------------------------------------------------------------------- /snippets/filelist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filelist", 3 | "readable": "Filelist", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Build a list of all available files for a page", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/filelist/readme.mdown: -------------------------------------------------------------------------------- 1 | # Filelist Snippet 2 | 3 | ## What is it? 4 | 5 | Filelist will generate a list of all or any matching files in your page's content folder. This is pretty handy for building download lists for example. 6 | 7 | ## Installation 8 | 9 | Put the filelist.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 14 | 15 | ## Options 16 | 17 | 'zip', 21 | 'sort' => 'filename', 22 | 'direction' => 'desc' // can be asc or desc 23 | )); 24 | 25 | ?> 26 | 27 | By passing additional variables you can customize the output of your list: 28 | 29 | ### extension 30 | 31 | Set the extension to only get a list of files with that extension. All files will be found by default if you don't specify an extension 32 | 33 | ### sort 34 | 35 | Change the sort field. Default is "filename" 36 | 37 | ### direction 38 | 39 | Change the sort direction. Default is "desc" 40 | 41 | 42 | ## Customization 43 | 44 | Customize the html in site/snippets/gallery.php to get the best result for your project 45 | 46 | ## Author 47 | Bastian Allgeier 48 | -------------------------------------------------------------------------------- /snippets/flattr/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/flattr/flattr.php: -------------------------------------------------------------------------------- 1 | url(); 9 | if(!isset($title)) $title = $page->title(); 10 | if(!isset($description)) $description = null; 11 | if(!isset($category)) $category = null; 12 | if(!isset($language)) $language = null; 13 | if(!isset($tags)) $tags = null; 14 | if(!isset($button)) $button = null; 15 | if(!isset($popout)) $popout = null; 16 | if(!isset($hidden)) $hidden = null; 17 | if(!isset($html5)) $html5 = false; 18 | 19 | if(!$instances) : 20 | 21 | // javascript output (once) 22 | ?> 23 | 37 | 50 | 51 | 64 | 65 | 76 | -------------------------------------------------------------------------------- /snippets/flattr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flattr", 3 | "readable": "Flattr", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Embed a Flattr button on your site", 7 | "author": "André Dujardin", 8 | "url": "http://djdn.de/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/flattr/readme.mdown: -------------------------------------------------------------------------------- 1 | # Flattr Snippet 2 | 3 | ## What is it? 4 | 5 | This snippet will embed a Flattr button in your site. You can set several options to customize it. The options are nearly equal to the original Flattr parameters. It even has a fallback if javascript is disabled and an optional HTML5 output. 6 | 7 | ## Installation 8 | 9 | Put the flattr.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | ```php 14 | 'your_user_id')) ?> 15 | ``` 16 | 17 | …or with more options… 18 | 19 | ```php 20 | 'your_user_id', 24 | 'url' => 'http://custom.url/path/to/page', 25 | 'title' => 'Your Page Headline', 26 | 'description' => 'Your Description', 27 | 'category' => 'One of the Flattr Categories', 28 | 'language' => 'en_GB', 29 | 'tags' => 'different, tags', 30 | 'button' => 'compact', 31 | 'popout' => '0', 32 | 'html5' => '1' 33 | )); 34 | 35 | ?> 36 | ``` 37 | 38 | ## Options 39 | 40 | ### user_id (required) 41 | 42 | A Flattr username. This is a required parameter for autosubmit but not for things that are already on flattr.com. 43 | 44 | ### url (optional) 45 | 46 | Each thing on Flattr requires a unique URL. All parts of the URL, including the both the parameters and fragments, are used to distinguish the difference between submitted URLs. If this parameter is unset, the snippet grabs the *$page->url()* string. 47 | 48 | ### title (optional) 49 | 50 | Will be used to describe your thing on Fattr. The *title* should be between 5-100 characters. All HTML is stripped. If this parameter is unset, the snippet grabs the *$page->title()* string. 51 | 52 | ### description (optional) 53 | 54 | Will be used to describe your thing. The *description* should be between 5-1000 characters. All HTML is stripped except the ** character which will be converted into newlines *(\n)*. 55 | 56 | ### category (optional) 57 | 58 | This parameter is used to sort things on Flattr and has no impact on the functionality of your button. It's value must be one of the [available categories](https://api.flattr.com/rest/v2/categories.txt). 59 | 60 | ### language (optional) 61 | 62 | Specifies which language your thing is in. Specifying the language will allow visitors on Flattr to filter through the large amount of things and get a personalized feed of items in their selected languages. The value must be a language code from the [available languages](https://api.flattr.com/rest/v2/languages.txt). Note that even tho this parameter is optional, a language will be guessed and added automatically if it is omitted. 63 | 64 | ### tags (optional) 65 | 66 | This parameter allows you to add tags that can be used to describe your thing. This is used on Flattr to allow further filtering and sorting of things. Multiple tags are seperated by a comma *,*. Using non alpha characters in tags are not supported nor is using a comma for obvious reasons. 67 | 68 | ### button (optional) 69 | 70 | We also provide a compact version of our Flattr button. This parameter tells the embedded button script which button layout to use. Set this parameter to *compact* if you want the *compact* button. Don't set the parameter at all if you are fine with the normal button. 71 | 72 | ### popout (optional) 73 | 74 | Set this parameter to *0* to disable the popout that appears when hovering the mouse cursor over the button. 75 | 76 | ### hidden (optional) 77 | 78 | Not all content is suitable for public listing. If you for one reason or another don't want your content to be listed on Flattr set this parameter to *1*. 79 | 80 | ### html5 (optional) 81 | 82 | You can get the output in valid html5 if you set this parameter to *1*. 83 | 84 | Further information can be found on the Flattr developer page: 85 | 86 | # Author 87 | André Dujardin -------------------------------------------------------------------------------- /snippets/gallery/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/gallery/gallery.php: -------------------------------------------------------------------------------- 1 | hasImages()): ?> 2 | 9 | -------------------------------------------------------------------------------- /snippets/gallery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gallery", 3 | "readable": "Gallery", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Generate a list of images", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/gallery/readme.mdown: -------------------------------------------------------------------------------- 1 | # Gallery Snippet 2 | 3 | ## What is it? 4 | 5 | This is a very basic gallery snippet, which will generate a list of images, which are available in your page's content folder. Don't expect too much. It's just a good starting point for your own gallery script. 6 | 7 | ## Installation 8 | 9 | Put the gallery.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 14 | 15 | ## Customization 16 | 17 | Customize the html in site/snippets/gallery.php to get the best result for your project 18 | 19 | ## Author 20 | Bastian Allgeier 21 | -------------------------------------------------------------------------------- /snippets/map/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/map/map.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 71 | 72 | 83 | -------------------------------------------------------------------------------- /snippets/map/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "map", 3 | "readable": "Google Maps", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Display a Google Maps map", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/map/readme.mdown: -------------------------------------------------------------------------------- 1 | # Google Maps Snippet 2 | 3 | ## What is it? 4 | 5 | This snippet will embed a Google Map in your site. You can set your own address, zoom level and some other options to customize it. It even has a fallback to the Google Maps Image API if javascript is disabled. 6 | 7 | ## Installation 8 | 9 | Put the map.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 'Mannheim, Germany')) ?> 14 | 15 | …or with more options… 16 | 17 | 'Mannheim, Germany', 21 | 'zoom' => 17, 22 | 'width' => 300, 23 | 'height' => 200 24 | )); 25 | 26 | ?> 27 | 28 | ## Options 29 | 30 | ### Address (required) 31 | 32 | Set the address for your map like you would on Google Maps. For Example "Mannheim, Germany" or "Timesquare, New York" 33 | 34 | ### Width (default is 300) 35 | 36 | Set the width of your map in pixels without "px" 37 | 38 | ### Height (default is 300) 39 | 40 | Set the height of your map in pixels without "px" 41 | 42 | ### Zoom (default is 15) 43 | 44 | Set the zoom level for your map. Anything between 1 and 20 makes sense. 45 | 46 | ### Type (default is roadmap) 47 | 48 | The map type. Can be roadmap, satellite, hybrid, terrain 49 | 50 | ### ID 51 | 52 | The id of your map. By default this is set to a random string to make multiple maps possible on a single page. 53 | 54 | ### Class (default is map) 55 | 56 | Set the class name for your map container. 57 | 58 | 59 | ## Author 60 | Bastian Allgeier 61 | -------------------------------------------------------------------------------- /snippets/menu/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/menu/menu.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/menu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "menu", 3 | "readable": "Menu", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Generate a main menu of your site based on visible pages.", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/menu/readme.mdown: -------------------------------------------------------------------------------- 1 | # Menu Snippet 2 | 3 | ## What is it? 4 | 5 | This snippet generates a main menu for your site. 6 | 7 | ## Installation 8 | 9 | Put the menu.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 14 | 15 | ## Customization 16 | 17 | Customize the html in site/snippets/menu.php to get the best result for your project 18 | 19 | ## Author 20 | Bastian Allgeier 21 | -------------------------------------------------------------------------------- /snippets/pagination/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/pagination/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pagination", 3 | "readable": "Pagination", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Adds full-flavoured pagination to your site", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/pagination/pagination.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/pagination/readme.mdown: -------------------------------------------------------------------------------- 1 | # Pagination Snippet 2 | 3 | ## What is it? 4 | 5 | Adds full-flavoured pagination to your site 6 | 7 | ## Installation 8 | 9 | Put the pagination.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | find('blog')->children()->paginate(10) ?> 14 | 15 | $articles->pagination())) ?> 16 | 17 | … or with additional ranged pagination … 18 | 19 | $articles->pagination(), 'range' => 5)) ?> 20 | 21 | ## Customization 22 | 23 | Change the html in site/snippets/pagination.php 24 | 25 | ## Author 26 | Bastian Allgeier 27 | -------------------------------------------------------------------------------- /snippets/podcastfeed/podcastfeed.php: -------------------------------------------------------------------------------- 1 | $podcast->title(), 7 | 'link' => url(), 8 | 'language' => 'en-en', 9 | 'modified' => $podcast->modified(), 10 | 'copyright' => $podcast->copyright(), 11 | 'description' => $podcast->description(), 12 | 'subtitle' => $podcast->subtitle(), 13 | 'author' => $podcast->author(), 14 | 'summary' => $podcast->summary(), 15 | 'category' => $podcast->category(), 16 | 'ownername' => $podcast->ownername(), 17 | 'owneremail' => $podcast->owneremail(), 18 | 'items' => array(), 19 | 'image' => ($podcast->images()->first()) ? $podcast->images()->first()->url() : false, 20 | ); 21 | 22 | $vars = array_merge($defaults, $vars); 23 | extract($vars); 24 | 25 | // send the right header 26 | header('Content-type: text/xml; charset="utf-8"'); 27 | 28 | // echo the doctype 29 | echo ''; 30 | 31 | ?> 32 | 33 | 34 | 35 | 36 | 37 | 38 | <?php echo xml($title) ?> 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | <?php echo xml($title); ?> 59 | 60 | 300 61 | 300 62 | 63 | 64 | 65 | 66 | 67 | <?php echo xml($item->title()) ?> 68 | url()) ?> 69 | date())) ?> 70 | 71 | text()) ?>]]> 72 | 73 | 74 | 75 | 76 | 77 | images()->first()): ?> 78 | 79 | 80 | 81 | files()->filterBy('extension', 'mp3')->first()): ?> 82 | 83 | url()) ?> 84 | 85 | 86 | duration()) ?> 87 | keywords()) ?> 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /snippets/prevnext/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/prevnext/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prevnext", 3 | "readable": "Prev Next", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Adds a prev page/next page snippet to your website", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/prevnext/prevnext.php: -------------------------------------------------------------------------------- 1 | hasPrevVisible()): ?> 2 | previous page 3 | 4 | 5 | hasNextVisible()): ?> 6 | next page 7 | 8 | -------------------------------------------------------------------------------- /snippets/prevnext/readme.mdown: -------------------------------------------------------------------------------- 1 | # PrevNext Snippet 2 | 3 | ## What is it? 4 | 5 | Puts a "previous page | next page" navigation on your pages. 6 | 7 | ## Installation 8 | 9 | Put the prevnext.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 14 | 15 | ## Customization 16 | 17 | Change the html in site/snippets/prevnext.php 18 | 19 | ## Author 20 | Bastian Allgeier 21 | -------------------------------------------------------------------------------- /snippets/submenu/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/submenu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "submenu", 3 | "readable": "Submenu", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Generate a sub menu for a page with visible children", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/submenu/readme.mdown: -------------------------------------------------------------------------------- 1 | # Submenu Snippet 2 | 3 | ## What is it? 4 | 5 | This snippet generates a submenu for each page on the first level with visible children. 6 | 7 | ## Installation 8 | 9 | Put the submenu.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 14 | 15 | ## Customization 16 | 17 | Customize the html in site/snippets/submenu.php to get the best result for your project 18 | 19 | ## Author 20 | Bastian Allgeier 21 | -------------------------------------------------------------------------------- /snippets/submenu/submenu.php: -------------------------------------------------------------------------------- 1 | findOpen(); 5 | $items = ($open) ? $open->children()->visible() : false; 6 | 7 | ?> 8 | count()): ?> 9 | 16 | 17 | -------------------------------------------------------------------------------- /snippets/treemenu/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/treemenu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "treemenu", 3 | "readable": "Treemenu", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Adds a tree menu to your site", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/treemenu/readme.mdown: -------------------------------------------------------------------------------- 1 | # Treemenu Snippet 2 | 3 | ## What is it? 4 | 5 | a very simple tree menu snippet, which renders a menu of all your site's pages and subpages 6 | 7 | ## Installation 8 | 9 | Put the treemenu.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | 14 | 15 | ## Customization 16 | 17 | Change the html in site/snippets/treemenu.php to get the best results for your project 18 | 19 | ## Start with a sublevel 20 | 21 | If you don't want it to start from the first level 22 | give it a set of pages, where it should start. i.e.: 23 | 24 | find('about-us')->children(); 28 | 29 | // create the snippet beginning with those subpages 30 | snippet('treemenu', array('subpages' => $subpages)); 31 | 32 | ?> 33 | 34 | ## Author 35 | Bastian Allgeier 36 | -------------------------------------------------------------------------------- /snippets/treemenu/treemenu.php: -------------------------------------------------------------------------------- 1 | pages() ?> 2 |
      3 | visible() AS $p): ?> 4 |
    • 5 | isActive()) ? ' class="active"' : '' ?> href="url() ?>">title() ?> 6 | hasChildren()): ?> 7 | $p->children())) ?> 8 | 9 |
    • 10 | 11 |
    -------------------------------------------------------------------------------- /snippets/video/changelog.mdown: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.0 4 | + Initial release -------------------------------------------------------------------------------- /snippets/video/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "video", 3 | "readable": "Video", 4 | "version": "1.0", 5 | "stable": true, 6 | "description": "Helper to create HTML5 video tags", 7 | "author": "Bastian Allgeier", 8 | "url": "http://getkirby.com/" 9 | } 10 | -------------------------------------------------------------------------------- /snippets/video/readme.mdown: -------------------------------------------------------------------------------- 1 | # Video Snippet 2 | 3 | ## What is it? 4 | 5 | a very simple helper to build full html 5 video tags. 6 | 7 | ## Installation 8 | 9 | Put the video.php file in your site/snippets folder 10 | 11 | ## How to use it? 12 | 13 | videos()->find('movie.mp4'), 18 | $page->videos()->find('movie.mobile.mp4'), 19 | $page->videos()->find('movie.webm'), 20 | $page->videos()->find('movie.ogv'), 21 | ); 22 | 23 | snippet('video', array( 24 | 'videos' => $videos, 25 | 'thumb' => $page->images()->find('movie.jpg') 26 | )); 27 | 28 | ?> 29 | 30 | ## Options 31 | 32 | ### width 33 | 34 | Set the width of the video. Default is 400px 35 | 36 | ### height 37 | 38 | Set the height of the video. Default is 300px 39 | 40 | ### preload 41 | 42 | (true|false) Default is true 43 | 44 | ### controls 45 | 46 | (true|false) Display controls for the video. Default is true 47 | 48 | ## Customization 49 | 50 | Change the html in site/snippets/video.php to get the best results for your project 51 | 52 | ## Author 53 | Bastian Allgeier 54 | -------------------------------------------------------------------------------- /snippets/video/video.php: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /templates/feed/readme.mdown: -------------------------------------------------------------------------------- 1 | # Feed Template 1.0 2 | 3 | ## What is it? 4 | 5 | This is used in connection with the feed snippet to setup a RSS-Feed for any part of your site 6 | 7 | ## Installation 8 | 9 | Put the `feed.php` file from inside the `template` folder into the `templates` folder of your Kirby installation. -------------------------------------------------------------------------------- /templates/feed/template/feed.php: -------------------------------------------------------------------------------- 1 | find('blog')->children()->visible()->flip()->limit(10); 7 | 8 | // this is how you embed the feed snippet with some options 9 | snippet('feed', array( 10 | 'link' => url('blog'), 11 | 'items' => $items, 12 | 'descriptionField' => 'text', 13 | 'descriptionLength' => 300 14 | )); 15 | 16 | ?> -------------------------------------------------------------------------------- /templates/podcastfeed/podcastfeed.php: -------------------------------------------------------------------------------- 1 | find('podcast'); 5 | 6 | // get any list of items 7 | // in this case we get all visible children of the podcast section, 8 | // flip them to get them in reverse order and make sure we only get the last 10 9 | $items = $podcast->children()->visible()->flip()->limit(10); 10 | 11 | // this is how you embed the feed snippet with some options 12 | snippet('podcastfeed', array( 13 | 'podcast' => $podcast, 14 | 'items' => $items, 15 | )); 16 | 17 | ?> --------------------------------------------------------------------------------