├── docs ├── panel-2 │ ├── url.md │ ├── fingerprint.md │ ├── login-automatically.md │ ├── routes.md │ ├── messages.md │ ├── blueprints.md │ ├── css.md │ └── fields.md ├── str-replace.md ├── dependencies.md ├── use-kirby-from-the-outside.md ├── site-methods.md ├── folder-setup.md ├── assets.md ├── videos.md ├── plugin │ ├── installation.md │ ├── readme.md │ └── best-practices.md ├── config.md ├── hooks.md ├── thumb.md ├── cache.md ├── extension-registry.md ├── plugin.md ├── vue.md ├── snippet.md ├── image.md ├── collection.md ├── routing.md ├── page.md └── htaccess.md ├── readme.md └── changelog.md /docs/panel-2/url.md: -------------------------------------------------------------------------------- 1 | # Panel 2 - Url 2 | 3 | ## Get panel root uri 4 | 5 | Not sure if it will work in all cases but it returns `panel` if not changed: 6 | 7 | ```php 8 | echo str_replace(kirby()->urls()->index() . '/', '', panel()->urls()->index()); 9 | ``` 10 | 11 | ## Get panel root url 12 | 13 | To get the panel root url from inside a field, do this: 14 | 15 | ```php 16 | echo panel()->urls()->index(); 17 | ``` -------------------------------------------------------------------------------- /docs/str-replace.md: -------------------------------------------------------------------------------- 1 | # strtr 2 | 3 | ## str::replace() alternative 4 | 5 | It's nice to be able to search replace with key/value pair. The toolkit does NOT provide such a function, but PHP does. 6 | 7 | **Solution:** 8 | 9 | ```php 10 | $string = strtr($string, 11 | array( 12 | 'Search for this' => 'Replace with this', 13 | 'Search something else' => 'Replace with something else' 14 | ) 15 | ); 16 | ``` -------------------------------------------------------------------------------- /docs/dependencies.md: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | 3 | Here are the known dependencies that Kirby uses. 4 | 5 | ## Kirby 6 | 7 | - [SimpleImage](https://github.com/claviska/SimpleImage) (for thumbs) 8 | - [Spyc](https://github.com/mustangostang/spyc) (for yaml operations) 9 | - [SQLight](https://www.sqlite.org/) 10 | 11 | ## Panel 2 12 | 13 | - [jQuery](https://jquery.com/) 14 | - [jQuery sortable](https://jqueryui.com/sortable/) 15 | -------------------------------------------------------------------------------- /docs/use-kirby-from-the-outside.md: -------------------------------------------------------------------------------- 1 | # Use Kirby from the outside 2 | 3 | If you use this code, you will have access to all the Kirby function from outside of Kirby: 4 | 5 | ```php 6 | define('DS', DIRECTORY_SEPARATOR); 7 | 8 | // load kirby 9 | require(DIR . DS . 'kirby' . DS . 'bootstrap.php'); 10 | 11 | $kirby = kirby(); 12 | $site = $kirby->site(); 13 | ``` 14 | 15 | **Source** 16 | 17 | https://forum.getkirby.com/t/traversing-content-outside-of-templates/968/3 18 | -------------------------------------------------------------------------------- /docs/site-methods.md: -------------------------------------------------------------------------------- 1 | # Site methods 2 | 3 | Site methods can be seen as global methods, attached to the `$site` object. 4 | 5 | **Place this code in a plugin:** 6 | 7 | ```php 8 | site::$methods['test'] = function($site, $arg1 = '', $arg2 = '') { 9 | return $site->homePage() . ' ' . $arg1 . ' ' . $arg2; 10 | }; 11 | ``` 12 | 13 | **Add this into a template or a snippet:** 14 | 15 | ```php 16 | test('testing', 12345); ?> 17 | ``` 18 | 19 | **Source** 20 | 21 | https://forum.getkirby.com/t/get-path-to-assets-images/1304/8 22 | -------------------------------------------------------------------------------- /docs/folder-setup.md: -------------------------------------------------------------------------------- 1 | # Folder setup 2 | 3 | A custom folder setup can be a perfect way to customize the urls for a plugin. Let's have a look at how it's done. 4 | 5 | **site.php** in root of your installation: 6 | 7 | ```php 8 | $kirby = kirby(); 9 | $kirby->roots->foldername = $kirby->roots()->index() . DS . 'foldername'; 10 | ``` 11 | 12 | Get it in a snippet or template like this: 13 | 14 | ```php 15 | echo kirby()->roots()->foldername(); 16 | ``` 17 | 18 | ## Sources 19 | 20 | - [Developer guide - Folders](https://getkirby.com/docs/developer-guide/configuration/folders) -------------------------------------------------------------------------------- /docs/panel-2/fingerprint.md: -------------------------------------------------------------------------------- 1 | # Fingerprint 2 | 3 | This feature is to prevent users from being logged out. Add this code in your `config.php` but change the returned string to anything you want. 4 | 5 | ```php 6 | s::$fingerprint = function() { 7 | return 'some fingerprint'; 8 | }; 9 | ``` 10 | 11 | >In scenarios, where IP or user agent based session fingerprints won't work, you can avoid problems that way. 12 | 13 | **Sources** 14 | 15 | - https://forum.getkirby.com/t/panel-keeps-logging-me-out/2747/20 16 | - https://forum.getkirby.com/t/panel-keep-login-out/6587/10 17 | - https://forum.getkirby.com/t/how-can-i-use-fingerprint/6047/4 18 | -------------------------------------------------------------------------------- /docs/assets.md: -------------------------------------------------------------------------------- 1 | # Assets 2 | 3 | ## Convert any image to object 4 | 5 | When an image is attached to a page, you can use [Thumb](https://getkirby.com/docs/cheatsheet/helpers/thumb) to resize that image. 6 | 7 | It's now also possible to resize an image that is outside the content folder. To do that, you first convert the image to an object. You will now have access to the methods of [media](https://getkirby.com/docs/toolkit/api#media). 8 | 9 | ```php 10 | $image = new Asset('assets/images/hero-default.jpg'); 11 | echo $image->resize(50)->url(); 12 | ``` 13 | 14 | - [How to use the new asset class to generate thumbnails](https://forum.getkirby.com/t/how-to-use-the-new-asset-class-to-generate-thumbnails/4245/5) -------------------------------------------------------------------------------- /docs/videos.md: -------------------------------------------------------------------------------- 1 | # Videos 2 | 3 | ## Kirby Courses 4 | 5 | Instead of listing all the upcoming videos here is the channel: 6 | 7 | https://www.youtube.com/channel/UCcsI8ZSvGDwIaSyLS0fGegg 8 | 9 | ## Patterns 10 | 11 | A great tutorial on the [Patterns](https://github.com/getkirby-plugins/patterns-plugin) plugin. 12 | 13 | https://vimeo.com/153132557 14 | 15 | ## Other videos 16 | 17 | - [Install Kirby CMS](https://www.youtube.com/watch?v=hnnBTt4ts10) 18 | - [Install CMS no database Kirby Php](https://www.youtube.com/watch?v=h_Xo9Q6wqok) 19 | - [Kirby CLI](https://www.youtube.com/watch?v=Rdn_t__Ag_Q) 20 | - [NightlyBuild 2015 - Bastian Allgeier - Homemade Pressure](https://www.youtube.com/watch?v=BV-5qIMyzD4) 21 | - [Alex Meisner Website - Kirby CMS Tutorial](https://www.youtube.com/watch?v=1CMVDKAgrtM) 22 | -------------------------------------------------------------------------------- /docs/plugin/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Use one of the alternatives below. 4 | 5 | ### 1. Kirby CLI 6 | 7 | If you are using the [Kirby CLI](https://github.com/getkirby/cli) you can install this plugin by running the following commands in your shell: 8 | 9 | ```text 10 | $ cd path/to/kirby 11 | $ kirby plugin:install username/plugin-name 12 | ``` 13 | 14 | ### 2. Clone or download 15 | 16 | 1. [Clone](https://github.com/username/plugin-name.git) or [download](https://github.com/username/plugin-name/archive/master.zip) this repository. 17 | 2. Unzip the archive if needed and rename the folder to `plugin-name`. 18 | 19 | **Make sure that the plugin folder structure looks like this:** 20 | 21 | ```text 22 | site/plugins/plugin-name/ 23 | ``` 24 | 25 | ### 3. Git Submodule 26 | 27 | If you know your way around Git, you can download this plugin as a submodule: 28 | 29 | ```text 30 | $ cd path/to/kirby 31 | $ git submodule add https://github.com/username/plugin-name site/plugins/plugin-name 32 | ``` -------------------------------------------------------------------------------- /docs/config.md: -------------------------------------------------------------------------------- 1 | # Config 2 | 3 | Sometimes you have data that should live in a global scope. You can use `$GLOBALS`, `define`, a singleton pattern, or with the [Kirby registry](https://getkirby.com/docs/developer-guide/plugins/registry). Let's have a look at how it's done. 4 | 5 | ## Set the global data 6 | 7 | The third argument can be string, array or an object which means you are not limited by it. 8 | 9 | ```php 10 | $data = array( 11 | 'key1' => 'data1', 12 | 'key2' => array( 13 | 'key' => 'value' 14 | ) 15 | ); 16 | kirby()->set('option', 'my_data', $data); 17 | ``` 18 | 19 | ## Get the global data 20 | 21 | `get` looks like `set` without the last argument. 22 | 23 | ```php 24 | $data = kirby()->get('option', 'my_data'); 25 | print_r($data); 26 | ``` 27 | 28 | The nice thing about it is that you don't need to think of what scope you are in. The first time I used it was to get a set value inside a kirbytext tag. 29 | 30 | ## Sources 31 | 32 | - [Developer guide - Extension registry](https://getkirby.com/docs/developer-guide/plugins/registry) -------------------------------------------------------------------------------- /docs/panel-2/login-automatically.md: -------------------------------------------------------------------------------- 1 | # Panel 2 - Login automatically 2 | 3 | This solution could be added to the config.php. Replace `YOURUSERNAME` and `YOURPASSWORD`. When visiting your domain and `/autologin` you will be logged in with no questions asked. 4 | 5 | ***Be aware that this could be a very dangerous feature and should not be used on a live environment*** 6 | 7 | ```php 8 | c::set('routes', array( 9 | array( 10 | 'pattern' => 'autologin', 11 | 'action' => function() { 12 | $username = 'YOURUSERNAME'; 13 | $password = 'YOURPASSWORD'; 14 | 15 | // Prevent access on the production system 16 | if(url::host() !== 'localhost') return false; 17 | 18 | $user = site()->user($username); 19 | if($user and $user->login($password)) { 20 | go('panel'); // or use go(); to redirect to the frontpage 21 | } else { 22 | echo 'invalid username or password'; 23 | return false; 24 | } 25 | } 26 | ) 27 | )); 28 | ``` 29 | 30 | **Source:** https://forum.getkirby.com/t/bypass-login-for-localhost-environment/3015 -------------------------------------------------------------------------------- /docs/panel-2/routes.md: -------------------------------------------------------------------------------- 1 | # Panel 2 - Routes 2 | 3 | If you make plugins for the Panel you can use routes, but you can also use Panel routes, routes specially for the Panel. 4 | 5 | **Visit the url below** 6 | 7 | Change domain to your domain and you need to prefix the route with `panel/`. 8 | 9 | ```text 10 | https://example.com/panel/my-panel-route/something` 11 | ``` 12 | 13 | **In your plugin** 14 | 15 | ```php 16 | panel()->routes(array( 17 | array( 18 | 'pattern' => 'my-panel-route/(:any)', 19 | 'action' => function($uid) { 20 | echo 'Hello from the panel! ' . $uid; 21 | } 22 | ) 23 | )); 24 | ``` 25 | 26 | It's often good to add some extra "protection". Below we check that the Panel exist and that a user is logged in. 27 | 28 | ```php 29 | if(class_exists('Panel') && site()->user()) { 30 | panel()->routes(array( 31 | array( 32 | 'pattern' => 'my-panel-route/(:any)', 33 | 'action' => function($uid) { 34 | echo 'Hello from the panel! ' . $uid; 35 | } 36 | ) 37 | )); 38 | } 39 | ``` 40 | 41 | **Source** 42 | 43 | https://github.com/pedroborges/kirby-autogit/blob/master/lib/routes.php -------------------------------------------------------------------------------- /docs/hooks.md: -------------------------------------------------------------------------------- 1 | # Hooks 2 | 3 | ## Custom hooks 4 | 5 | Maybe a hook is missing or you need a custom one for your plugin. Let's have a look at how it's done. 6 | 7 | **Add** a hook where you want the action to happend: 8 | 9 | ```php 10 | kirby()->hook('my_hook', function($arg1, $arg2) { 11 | echo $arg1; 12 | print_r($arg2); 13 | }); 14 | ``` 15 | 16 | **Trigger** the hook when you want the action to happend: 17 | 18 | ```php 19 | kirby()->trigger('my_hook', 20 | [ 21 | 'Argument 1', 22 | ['item' => 'Argument2'] 23 | ] 24 | ); 25 | ``` 26 | 27 | ### Reset triggered hooks 28 | 29 | When triggering a hook, it will only fire ones. If you trigger it again, it will not run. That's the behavior to prevent infinity loops. In some cases there is a need to trigger a hook more than ones. It's possible to reset the trigger array, like below. 30 | 31 | ```php 32 | kirby()::$triggered = array(); 33 | ``` 34 | 35 | - [Forum - Trigger hook does not fire oldpage](https://forum.getkirby.com/t/trigger-hook-does-not-fire-oldpage/8700/7) 36 | 37 | ## Sources 38 | 39 | - [Developer guide - Extension registry](https://getkirby.com/docs/developer-guide/plugins/registry) 40 | -------------------------------------------------------------------------------- /docs/panel-2/messages.md: -------------------------------------------------------------------------------- 1 | # Panel 2 - Messages 2 | 3 | There are `notify` which is a green message and `alert` which is a red error message. 4 | 5 | ## With hooks 6 | 7 | If you are inside the Panel and want to trigger a message, you can do that inside a hook. 8 | 9 | In both examples there is a redirect and in order for the message to work it needs to be there. In these cases it will redirect to the page it just created. 10 | 11 | ### Message 12 | 13 | ```php 14 | kirby()->hook('panel.page.create', function($page) { 15 | panel()->notify("Your page was created!"); 16 | panel()->redirect('pages/' . $page->id() . '/edit'); 17 | }); 18 | ``` 19 | 20 | ### Error message 21 | 22 | ```php 23 | kirby()->hook('panel.page.create', function($page) { 24 | panel()->alert("Error! Just kidding!"); 25 | panel()->redirect('pages/' . $page->id() . '/edit'); 26 | }); 27 | ``` 28 | 29 | ## Without hooks 30 | 31 | If you don't want to put the message into a hook you can use it for example directly into a field. 32 | 33 | ```php 34 | panel()->notify('Hello world!'); 35 | ``` 36 | 37 | or 38 | 39 | ```php 40 | panel()->error('Did not work!'); 41 | ``` 42 | 43 | **Sources** 44 | 45 | https://forum.getkirby.com/t/hooks-flash-message/6766/1 46 | https://forum.getkirby.com/t/trigger-panel-notification-message-from-field/3851/1 -------------------------------------------------------------------------------- /docs/thumb.md: -------------------------------------------------------------------------------- 1 | # Thumb 2 | 3 | ## toFile 4 | 5 | ### Old way 6 | 7 | How do you create a thumbnail with Kirby? 8 | 9 | **The most common is probably by using the `thumb` function like this:** 10 | 11 | ```php 12 | image($page->my_image()), array('width' => 300)); ?> 13 | ``` 14 | 15 | https://getkirby.com/docs/cheatsheet/helpers/thumb 16 | 17 | We need to wrap everything with a `thumb` function. To use a particular filename, we also need to wrap `$page->my_image()` inside `$page->image()`, else it will pick the first image. It's not very straight forward. 18 | 19 | ### New way 20 | 21 | To use `toFile` is a "new" way of working with thumbs. It's in the [docs](https://getkirby.com/docs/cheatsheet/field-methods/toFile) but not very prominent. 22 | 23 | **It looks much simpler:** 24 | 25 | ```php 26 | my_image()->toFile()->resize(300); ?> 27 | ``` 28 | 29 | **To check if the file exists we can do this:** 30 | 31 | ```php 32 | my_image()->toFile()) ? $image->resize(300) : ''; ?> 33 | ``` 34 | 35 | In the above, we check if `$page->my_image()->toFile()` exists and if it does, put it into `$image`. Then `$image` is used to resize the thumb. If it does not match, don't write anything. It may look complicated, but this way we can get away with a oneliner. 36 | 37 | https://forum.getkirby.com/t/site-thumb-not-created/9267/2 -------------------------------------------------------------------------------- /docs/cache.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | ## Partial cache 4 | 5 | ### Enable the cache 6 | 7 | In this case we want to enable the cache. The `cache.ignore` make sure no pages are cached. 8 | 9 | ```php 10 | c::set('cache', true); 11 | c::set('cache.ignore', ['*']); 12 | ``` 13 | 14 | ### `getCache` 15 | 16 | If the cache is already set, load data from the cache. If the cache is not set, return the data from the `setCache` function. 17 | 18 | ```php 19 | function getCache($key) { 20 | $cache = cache::get($key); 21 | if(!$cache) { 22 | $cache = setCache(); 23 | cache::set($key, $cache); 24 | } 25 | return $cache; 26 | } 27 | ``` 28 | 29 | ### `setCache` 30 | 31 | What is inside the `setCache` function is probably slow. That's why we need a cache for it. 32 | 33 | ```php 34 | function setCache() { 35 | return 'My data'; 36 | } 37 | ``` 38 | 39 | ### Function call 40 | 41 | The key is `my_cache`. If you change it a new cache file will be saved. 42 | 43 | ```php 44 | echo getCache('my_cache'); 45 | ``` 46 | 47 | - [Forum - Cache part of a page](https://forum.getkirby.com/t/cache-part-of-a-page/5199/1) 48 | 49 | ## Sources 50 | 51 | - [Developer guide - Caching](https://getkirby.com/docs/developer-guide/advanced/caching) 52 | - [Cheatcheet - Cache](https://getkirby.com/docs/cheatsheet/options/cache) 53 | - [Cheatcheet - Cache ignore](https://getkirby.com/docs/cheatsheet/options/cache-ignore) 54 | -------------------------------------------------------------------------------- /docs/extension-registry.md: -------------------------------------------------------------------------------- 1 | # Extension registry 2 | 3 | ## Custom registry set 4 | 5 | Maybe you need a custom registry for your plugin. 6 | 7 | **Put this code into a file that is loaded by a plugin, or autoloaded:** 8 | 9 | ```php 10 | set('type', 'name', __DIR__ . '/types/name.php'); 31 | echo $kirby->get('type', 'name'); 32 | ``` 33 | 34 | Change `type` to the name of your registry type name, but make sure everything is lowercase. Also change `name` to the name of your registry entry. 35 | 36 | - [Forum - How can I create an own registry of files or folders](https://forum.getkirby.com/t/how-can-i-create-an-own-registry-set-of-files-or-folder/6415) 37 | 38 | ## Sources 39 | 40 | - [Forum - How can I create an own registry of files or folders](https://forum.getkirby.com/t/how-can-i-create-an-own-registry-set-of-files-or-folder/6415) 41 | - [Developer guide - Extension registry](https://getkirby.com/docs/developer-guide/plugins/registry) 42 | -------------------------------------------------------------------------------- /docs/plugin.md: -------------------------------------------------------------------------------- 1 | # Plugin 2 | 3 | ## Force load plugins 4 | 5 | The `$plugin_name` is the plugin folder name: 6 | 7 | ```php 8 | kirby()->plugin($plugin_name); 9 | ``` 10 | 11 | It will only run once, not again by the core. 12 | 13 | ## Get loaded plugins 14 | 15 | ```php 16 | print_r( kirby()->plugins ); 17 | ``` 18 | 19 | ## Load plugin last 20 | 21 | Sometimes you might need to load your plugin last. It's not possible out of the box but when doing it like this it loads every plugin except your plugin first. It means your plugin will load last. Because a plugin will only be loaded once you don't need to worry about that the plugins will load mulitple times, they will only be loaded once. 22 | 23 | **Source:** https://forum.getkirby.com/t/load-your-plugin-last/5718 24 | 25 | ```php 26 | function loadOtherPluginsFirst() { 27 | $folders = glob( kirby()->roots()->plugins() . DS . '*', GLOB_ONLYDIR ); 28 | 29 | if( ! empty( $folders ) ) { 30 | foreach( $folders as $folder ) { 31 | $name = pathinfo($folder, PATHINFO_FILENAME); 32 | 33 | if( $name != 'my-plugin') { 34 | kirby()->plugin( $name ); 35 | } 36 | } 37 | } 38 | } 39 | ``` 40 | 41 | ## Plugin has loaded 42 | 43 | ```php 44 | if( kirby()->plugin('modules') ) { 45 | echo 'The Modules plugin has been loaded'; 46 | } 47 | ``` 48 | 49 | **Be aware:** If the plugin exist, but has not been loaded it will force load it and return `true` if exists. 50 | 51 | ## Plugin creation 52 | 53 | - [Boiler readme - Preview](plugin/readme.md) 54 | - [Boiler readme - Download](https://raw.githubusercontent.com/jenstornell/kirby-secrets/master/docs/plugin/readme.md) 55 | - [Plugin best practices](plugin/best-practices.md) 56 | -------------------------------------------------------------------------------- /docs/panel-2/blueprints.md: -------------------------------------------------------------------------------- 1 | # Panel 2 - Blueprints 2 | 3 | ## Special characters 4 | 5 | To allow special characters like quotes, always wrap the whole block with quotes and then escape the quotes inside it with `\`. 6 | 7 | ```text 8 | fields: 9 | my_field: 10 | title: "A field title with \"Quotes\"" 11 | type: text 12 | ``` 13 | 14 | - [Forum - Special characters breaking blueprint content in the panel](https://forum.getkirby.com/t/special-characters-breaking-blueprint-content-in-the-panel/3748/3) 15 | 16 | ## Field definition subfolders 17 | 18 | You can create global field definitions in subfolders. It's especially good if you have many global field definitions and it's starting to be messy. 19 | 20 | ```text 21 | fields: 22 | myfield: subfolder/definition 23 | ``` 24 | 25 | - [Kirby Courses - 10 Tips & Hidden Features](https://www.youtube.com/watch?v=YjbbcKWOLs8) 26 | 27 | ## Get all blueprints 28 | 29 | Especially for plugins it can sometimes be useful to be able to get all the blueprints. Let's see how that is done. 30 | 31 | ```php 32 | $blueprints = kirby()->get('blueprint'); 33 | print_r($blueprints); 34 | ``` 35 | 36 | - [Get the blueprint in a panel field from another page](https://forum.getkirby.com/t/get-the-blueprint-in-the-a-panel-field-from-another-page/4877/5) 37 | 38 | ## Sources 39 | 40 | - [Forum - Special characters breaking blueprint content in the panel](https://forum.getkirby.com/t/special-characters-breaking-blueprint-content-in-the-panel/3748/3) 41 | - [Kirby Courses - 10 Tips & Hidden Features](https://www.youtube.com/watch?v=YjbbcKWOLs8) 42 | - [Get the blueprint in a panel field from another page](https://forum.getkirby.com/t/get-the-blueprint-in-the-a-panel-field-from-another-page/4877/5) -------------------------------------------------------------------------------- /docs/vue.md: -------------------------------------------------------------------------------- 1 | # Kirby and Vue 2 | 3 | Vue is a js framework and if your site is not a js web app, you probably don't need it. 4 | 5 | ## Footer 6 | 7 | Here is a starting point placed in the `footer.php`, which uses [Vue](https://vuejs.org/) and [Vue Router](https://router.vuejs.org/en/). 8 | 9 | ```html 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 37 | 38 | 39 | 40 | ``` 41 | 42 | ## Config 43 | 44 | In your `config.php`, you can add a route. No matter what page it is, it's always visiting home. It makes Vue to take over the routes with javascript. 45 | 46 | ```php 47 | c::set('routes', array( 48 | array( 49 | 'pattern' => '(.+)', 50 | 'action' => function() { 51 | return site()->visit('/'); 52 | } 53 | ) 54 | )); 55 | ``` 56 | 57 | ### Sources 58 | 59 | - [The Net Ninja - Vue JS 2 (44 parts)](https://youtu.be/5LYrN_cAJoA) 60 | - [Vue.js Routing with vue-router](https://www.youtube.com/watch?v=Xktwf4yS2g0) 61 | - [Learn Vue 2: Step By Step](https://laracasts.com/series/learn-vue-2-step-by-step) 62 | - [Css tricks - Introduction to Vue](https://css-tricks.com/intro-to-vue-1-rendering-directives-events/) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Kirby Secrets 2 | 3 | *Unofficial documentation for Kirby CMS. It's is NOT maintained by the Kirby crew.* 4 | 5 | [Changelog](changelog.md) 6 | 7 | ## Kirby 8 | 9 | - [Assets](docs/assets.md) 10 | - [Collection](docs/collection.md) 11 | - [Config](docs/config.md) 12 | - [Cache](docs/cache.md) 13 | - [Dependencies](docs/dependencies.md) 14 | - [Extension registry](docs/extension-registry.md) 15 | - [Folder setup](docs/folder-setup.md) 16 | - [Hooks](docs/hooks.md) 17 | - [Htaccess](docs/htaccess.md) 18 | - [Image](docs/image.md) 19 | - [Page](docs/page.md) 20 | - [Plugin](docs/plugin.md) 21 | - [Routing](docs/routing.md) 22 | - [Site methods](docs/site-methods.md) 23 | - [Snippet](docs/snippet.md) 24 | - [`str::replace()` alternative](docs/str-replace.md) 25 | - [Thumb](docs/thumb.md) 26 | - [Use Kirby from the outside](docs/use-kirby-from-the-outside.md) 27 | 28 | 32 | 33 | ## Panel 2 34 | 35 | - [Blueprints](docs/panel-2/blueprints.md) 36 | - [CSS](docs/panel-2/css.md) 37 | - [Fields](docs/panel-2/fields.md) 38 | - [Fingerprint](docs/panel-2/fingerprint.md) 39 | - [Login automatically](docs/panel-2/login-automatically.md) 40 | - [Panel message](docs/panel-2/messages.md) 41 | - [Panel routes](docs/panel-2/routes.md) 42 | - [Panel url](docs/panel-2/url.md) 43 | 44 | ## External resources 45 | 46 | - [Videos](docs/videos.md) 47 | 48 | ## Add a secret 49 | 50 | If you have an own secrets, [add an issue](https://github.com/jenstornell/kirby-secrets/issues/new). 51 | 52 | ## Disclaimer 53 | 54 | Kirby Secrets contains unofficial undocumented code. Use the code at your own risk. There is a chance that it will not work with the next version of Kirby. 55 | 56 | ## Credits 57 | 58 | The whole community. -------------------------------------------------------------------------------- /docs/snippet.md: -------------------------------------------------------------------------------- 1 | # Snippet 2 | 3 | ## Get all snippet arguments 4 | 5 | We can send arguments to a snippet. We can also get all the arguments from inside the snippet. 6 | 7 | **Template / snippet** 8 | 9 | ```php 10 | snippet('my-snippet', ['car' => true, 'boat' => false]); 11 | ``` 12 | 13 | **Snippet** 14 | 15 | ```php 16 | print_r(get_defined_vars()['_data']); 17 | ``` 18 | 19 | **Results** 20 | 21 | ```text 22 | array( 23 | 'car' => true 24 | 'boat' => false 25 | ) 26 | ``` 27 | 28 | ## Snippet preview 29 | 30 | To preview snippets outside the normal pages is not as simple as it seems. 31 | 32 | Except reading the html, it also needs to read the page `$page` object. That require the snippet to know which template to use. 33 | 34 | ### Function needed 35 | 36 | It takes `$template`, `$data` and `$page`. It returns a html output. 37 | 38 | ```php 39 | class SnippetPreview extends Kirby\Component\Template { 40 | public function render($template, $data = [], $page = null) { 41 | $file = $template; 42 | $data = $this->data($page, $data); 43 | 44 | if(!file_exists($file)) { 45 | throw new Exception('The template could not be found'); 46 | } 47 | 48 | $tplData = tpl::$data; 49 | tpl::$data = array_merge(tpl::$data, $data); 50 | $result = tpl::load($file, null); 51 | tpl::$data = $tplData; 52 | 53 | return $result; 54 | } 55 | } 56 | ``` 57 | 58 | ### How to use it 59 | 60 | First we declare our class to a variable. Then we use `render` with a snippet, an empty array and a page object. The class is asking for a template, but we can send a snippet as well. 61 | 62 | ```php 63 | $SnippetPreview = new SnippetPreview(kirby()); 64 | 65 | $data = $SnippetPreview->render( 66 | kirby()->roots()->snippets() . DS . 'menu.php', 67 | array(), 68 | page('about') 69 | ); 70 | 71 | echo $data; 72 | ``` 73 | 74 | **Source** 75 | 76 | https://forum.getkirby.com/t/global-site-page-pages-in-route-snippet/5407/5 77 | -------------------------------------------------------------------------------- /docs/image.md: -------------------------------------------------------------------------------- 1 | # Image 2 | 3 | ## Image manipulation 4 | 5 | Kirby is based on [SimpleImage](https://github.com/claviska/SimpleImage). It means that you can use SimpleImage functions directly to make more advanced image manipulations than Kirby uses. 6 | 7 | ### Crop position top 8 | 9 | As of today you can't specify a crop position with the Kirby thumb function [#99](https://github.com/getkirby/toolkit/issues/99), but it's possible to build your own. 10 | 11 | ```php 12 | $simpleimageObject = new abeautifulsite\SimpleImage($image_path); 13 | $simpleimageObject->thumbnail(150, 300, 'top')->save($thumb_path); 14 | ``` 15 | 16 | If you don't want to build it yourself there is a plugin for it called [Kirby Crop Top](https://github.com/jenstornell/kirby-crop-top). 17 | 18 | There are many more things you can to. [Read more on SimpleImage docs](https://github.com/claviska/SimpleImage). 19 | 20 | ## Image content url 21 | 22 | If you are in the Panel and click on an image you will see a url like this: 23 | 24 | ```text 25 | https://example.com/content/1-projects/1-project-a/folding-rule.jpg 26 | ``` 27 | 28 | If you change the sort order of the pages you can't access the image by this url anymore. 29 | 30 | However there is a secret redirected url that you can use. Remove `content` and the sorting number prefix on all the pages in the hierarchy, in the url. 31 | 32 | ```text 33 | https://example.com/projects/project-a/folding-rule.jpg 34 | ``` 35 | 36 | This url will not work as `200` but as a `302`, temporary redirect. 37 | 38 | **Note** 39 | 40 | I'm personally not too fond of "magic" redirects that I did not ask for, but in this case I understand why it can be useful. 41 | 42 | ## Sources 43 | 44 | - [SimpleImage](https://github.com/claviska/SimpleImage) 45 | - [Issue #99](https://github.com/getkirby/toolkit/issues/99) 46 | - [Kirby Crop Top](https://github.com/jenstornell/kirby-crop-top) 47 | - [Kirby Courses - 10 Tips & Hidden Features](https://www.youtube.com/watch?v=YjbbcKWOLs8) 48 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | **2017-12-21** 4 | 5 | - [Thumb](docs/thumb.md) added. 6 | 7 | **2017-11-02** 8 | 9 | - [Hooks](docs/hooks.md) updated. 10 | - [Assets](docs/assets.md) added. 11 | - [Kirby and Vue](docs/vue.md) added. 12 | 13 | **2017-10-18** 14 | 15 | - Updated [Routing](docs/routing.md). 16 | - Merged almost every text. 17 | - Moved from the Wiki to the original repository. 18 | 19 | **2017-10-17** 20 | 21 | - New structure to simplify the workflow with the wiki pages. 22 | - Added [Depencencies](docs/dependencies.md). 23 | 24 | **2017-03-22** 25 | 26 | - [Plugin best practices](https://github.com/jenstornell/kirby-secrets/wiki/Plugin-best-practices) 27 | 28 | **2017-03-20** 29 | 30 | - [Global collection filter](https://github.com/jenstornell/kirby-secrets/wiki/Global-collection-filter) 31 | - Updated [Page value manipulation](https://github.com/jenstornell/kirby-secrets/wiki/Page-value-manipulation) 32 | 33 | **2017-03-16** 34 | 35 | - [Page value manipulation](https://github.com/jenstornell/kirby-secrets/wiki/Page-value-manipulation) 36 | 37 | **2017-03-14** 38 | 39 | - [Field controllers](https://github.com/jenstornell/kirby-secrets/wiki/Field-controllers) 40 | 41 | **2017-03-10** 42 | 43 | - [Htaccess browser cache](https://github.com/jenstornell/kirby-secrets/wiki/Htaccess-browser-cache) 44 | - [Htaccess gzip compression](https://github.com/jenstornell/kirby-secrets/wiki/Htaccess-gzip-compression) 45 | - [Htaccess redirect to https non www](https://github.com/jenstornell/kirby-secrets/wiki/Htaccess-redirect-to-https-non-www) 46 | - [Panel fingerprint](https://github.com/jenstornell/kirby-secrets/wiki/Fingerprint) 47 | - [Boiler readme](https://github.com/jenstornell/kirby-secrets/wiki/Boiler-readme) 48 | - [Site methods](https://github.com/jenstornell/kirby-secrets/wiki/Site-methods) 49 | 50 | **2017-03-08** 51 | 52 | - [Panel routes](https://github.com/jenstornell/kirby-secrets/wiki/Panel-routes) 53 | 54 | **2017-02-28** 55 | 56 | - [Image content url](https://github.com/jenstornell/kirby-secrets/wiki/Image-content-url) 57 | - [Field definition subfolders](https://github.com/jenstornell/kirby-secrets/wiki/Field-defintion-subfolders) 58 | - 20+ posts added. I lost track of them. It was before this changelog was created. -------------------------------------------------------------------------------- /docs/panel-2/css.md: -------------------------------------------------------------------------------- 1 | # Panel 2 - CSS 2 | 3 | ## Multiple panel css 4 | 5 | Instead of using `c::set` it's also possible to use the registry to add the option. It's also possible to use multiple css files. To do that just add them as array instead of a string. 6 | 7 | Adding multiple css files can be good when having a custom css file and also a css file from a plugin. 8 | 9 | ```php 10 | kirby()->set('option', 'panel.stylesheet', array( 11 | 'assets/plugins/my-plugin/css/panel.css', 12 | 'assets/css/panel.css' 13 | )); 14 | ``` 15 | 16 | ## Style panel login form 17 | 18 | To style the panel login form you can do this: 19 | 20 | **config.php** 21 | 22 | ```php 23 | c::set('panel.stylesheet', 'assets/css/panel.css'); 24 | ``` 25 | 26 | **panel.css** 27 | 28 | It will add a logo image and a "Powered by The company" to your form. 29 | 30 | ```css 31 | body.login .form:before { 32 | content: ''; 33 | height: 150px; 34 | width: 100%; 35 | margin-bottom: 1.5em; 36 | display: block; 37 | background: #fff url('../images/logo.svg') center no-repeat; 38 | background-size: contain; 39 | } 40 | body.login .form::after { 41 | color: #999; 42 | content: 'Powered by The company'; 43 | } 44 | body.login .form .btn-submit { 45 | margin: 0 0 1.5em 0; 46 | } 47 | body.login .form fieldset.buttons-centered { 48 | border-bottom: 1px solid #ccc; 49 | } 50 | ``` 51 | 52 | - [Forum - Share your custom panel css](https://forum.getkirby.com/t/share-your-custom-panel-css/5298/8) 53 | 54 | ## Style panel search box 55 | 56 | The panel search box can be hard to read. This is the way to style it white: 57 | 58 | **config.php** 59 | 60 | ```php 61 | c::set('panel.stylesheet', 'assets/css/panel.css'); 62 | ``` 63 | 64 | **panel.css** 65 | 66 | ```css 67 | .search-input { 68 | background-color: white; 69 | } 70 | .search:after { 71 | border-bottom-color: white 72 | } 73 | .search-section li.active a, .search-section li:hover a { 74 | color: white; 75 | background-color: rgba(255, 255, 255, .2); 76 | } 77 | ``` 78 | 79 | - [Forum - Share your custom panel css](https://forum.getkirby.com/t/share-your-custom-panel-css/5298/5) 80 | - [Issue #1014](https://github.com/getkirby/panel/issues/1014) 81 | 82 | ## Sources 83 | 84 | - [Developer guide - Panel CSS](https://getkirby.com/docs/developer-guide/panel/css) 85 | - [Forum - Share your custom panel css](https://forum.getkirby.com/t/share-your-custom-panel-css/5298/8) 86 | - [Issue #1014](https://github.com/getkirby/panel/issues/1014) -------------------------------------------------------------------------------- /docs/collection.md: -------------------------------------------------------------------------------- 1 | # Collection 2 | 3 | ## Is collection 4 | 5 | In the example below we check if the object is a collection. 6 | 7 | ```php 8 | if(is_a($collection, 'Collection')) { 9 | echo 'This is a collection'; 10 | } 11 | ``` 12 | 13 | [Forum - Check if the object is a page or collection](https://forum.getkirby.com/t/check-if-the-object-is-a-page-or-collection/6464) 14 | 15 | ## Global collection filter 16 | 17 | There is nothing called "Global collection filter", but it's possible to get close to creating one. 18 | 19 | ```php 20 | page::$methods['realChildren'] = function($page) { 21 | return $page->children()->filterBy('intendedTemplate', 'not in', ['modules', 'revision']); 22 | }; 23 | ``` 24 | 25 | ### Template / snippet 26 | 27 | ```php 28 | foreach($page->realChildren() as $child) { 29 | echo $child->title(); 30 | } 31 | ``` 32 | 33 | - It will not work on collections. 34 | - You can't name it `children` because then it will still use the native `children` method. 35 | 36 | [Forum - Global filters run it before template loads](https://forum.getkirby.com/t/global-filters-run-it-before-template-loads/6976/4) 37 | 38 | ## Collection rotator 39 | 40 | ### Get next collection of pages 41 | 42 | What we want here is an interval of pages and if it reaches the end of the collection, start over until the limit is reached. 43 | 44 | **Look at this list of pages:** 45 | 46 | ```text 47 | project-a 48 | project-b 49 | project-c 50 | project-d //The current page 51 | project-e 52 | ``` 53 | 54 | **Result should be a collection like this (limit set to 4):** 55 | 56 | ```text 57 | project-e 58 | // End of collection. Starts over to fill the limit. 59 | project-a 60 | project-b 61 | project-c 62 | ``` 63 | 64 | **Page method** 65 | 66 | ```php 67 | page::$methods['collectionRotator'] = function($page, $limit) { 68 | $pages = $page->siblings(); 69 | $offset = $pages->indexOf($page)+1; 70 | $items = $pages->slice($offset, $limit); 71 | $remainder = $pages->limit($limit-$items->count()); 72 | 73 | $collection = new Pages(); 74 | $collection->add($items); 75 | $collection->add($remainder); 76 | return $collection; 77 | }; 78 | ``` 79 | 80 | **Usage** 81 | 82 | ``` 83 | foreach($page->collectionRotator(4) as $child) { 84 | echo $child->title(); 85 | } 86 | ``` 87 | 88 | [Forum - Filter interval of pages](https://forum.getkirby.com/t/filter-interval-of-pages/5893) 89 | 90 | ## Sources 91 | 92 | - [Developer guide - Custom collection filters](https://getkirby.com/docs/developer-guide/objects/collections) 93 | - [Cookbook - Filtering](https://getkirby.com/docs/cookbook/filtering) 94 | -------------------------------------------------------------------------------- /docs/plugin/readme.md: -------------------------------------------------------------------------------- 1 | # Kirby Boiler Readme 2 | 3 | ![Version](https://img.shields.io/badge/version-0.1-green.svg) ![License](https://img.shields.io/badge/license-MIT-green.svg) ![Kirby Version](https://img.shields.io/badge/Kirby-2.0%2B-red.svg) 4 | 5 | *Version 0.1* 6 | 7 | Write a short description of what the plugin is about. 8 | 9 | ![Screenshot](https://placehold.it/888x150?text=Screenshot) 10 | 11 | ## Installation 12 | 13 | Use one of the alternatives below. 14 | 15 | ### 1. Kirby CLI 16 | 17 | If you are using the [Kirby CLI](https://github.com/getkirby/cli) you can install this plugin by running the following commands in your shell: 18 | 19 | ```text 20 | $ cd path/to/kirby 21 | $ kirby plugin:install username/plugin-name 22 | ``` 23 | 24 | ### 2. Clone or download 25 | 26 | 1. [Clone](https://github.com/username/plugin-name.git) or [download](https://github.com/username/plugin-name/archive/master.zip) this repository. 27 | 2. Unzip the archive if needed and rename the folder to `plugin-name`. 28 | 29 | **Make sure that the plugin folder structure looks like this:** 30 | 31 | ```text 32 | site/plugins/plugin-name/ 33 | ``` 34 | 35 | ### 3. Git Submodule 36 | 37 | If you know your way around Git, you can download this plugin as a submodule: 38 | 39 | ```text 40 | $ cd path/to/kirby 41 | $ git submodule add https://github.com/username/plugin-name site/plugins/plugin-name 42 | ``` 43 | 44 | ## Setup 45 | 46 | ### 1. Blueprint 47 | 48 | To make it work as expected, add the following code to your blueprint: 49 | 50 | ```text 51 | fields: 52 | yourfield: 53 | title: Your Field 54 | type: yourfield 55 | ``` 56 | 57 | ## Usage 58 | 59 | Text, images and videos are good things to describe how to use this plugin. 60 | 61 | ## Options 62 | 63 | The following options can be set in your `/site/config/config.php` file: 64 | 65 | ```php 66 | c::set('plugin.your.plugin.option1', 25); 67 | c::set('plugin.your.plugin.option2', 'foo'); 68 | ``` 69 | 70 | ### option1 71 | 72 | This option is an integer, a number which can be used for calculations. 73 | 74 | ## Changelog 75 | 76 | **0.1** 77 | 78 | - Initial release 79 | 80 | ## Requirements 81 | 82 | - [**Kirby**](https://getkirby.com/) 2.0+ 83 | 84 | ## Disclaimer 85 | 86 | This plugin is provided "as is" with no guarantee. Use it at your own risk and always test it yourself before using it in a production environment. If you find any issues, please [create a new issue](https://github.com/username/plugin-name/issues/new). 87 | 88 | ## License 89 | 90 | [MIT](https://opensource.org/licenses/MIT) 91 | 92 | It is discouraged to use this plugin in any project that promotes racism, sexism, homophobia, animal abuse, violence or any other form of hate speech. 93 | 94 | ## Credits 95 | 96 | - [Jens Törnell](https://github.com/jenstornell) 97 | - [Mathieu Etienne](https://github.com/Thiousi/) 98 | - [Flo Kosiol](https://github.com/flokosiol) -------------------------------------------------------------------------------- /docs/routing.md: -------------------------------------------------------------------------------- 1 | # Routing 2 | 3 | ## kirby()->routes() 4 | 5 | For plugins it's quite common to use the syntax below. 6 | 7 | ```php 8 | kirby()->routes(array( 9 | array( 10 | 'pattern' => 'my/awesome/(:any)', 11 | 'action' => function($uid) { 12 | echo $uid; 13 | } 14 | ) 15 | )); 16 | ``` 17 | 18 | - [Developer guide - Routing](https://getkirby.com/docs/developer-guide/advanced/routing) `c::set` 19 | - [Developer guide - Extension registry - Route](https://getkirby.com/docs/developer-guide/plugins/registry) `$kirby->set` 20 | - [Toolkit - Routing](https://getkirby.com/docs/developer-guide/toolkit/routing) `$router->register` 21 | 22 | ## Return a response or site visit 23 | 24 | Instead of use `echo` or `return false;` to output or return something from a route, you can create a response object. 25 | 26 | ### Response exemples 27 | 28 | ```php 29 | return new Response('Hello World!', 'html', 200); 30 | return new Response('You have an error!', 'html', 404); 31 | return new Response(json_encode(['Hello' => 'World']), 'json', 200); 32 | return new Response(snippet('error-message', [], true), 'html', 404); 33 | ``` 34 | 35 | - [Toolkit - Response object](https://getkirby.com/docs/toolkit/api#response) 36 | - [Forum - How to break a route](https://forum.getkirby.com/t/how-do-you-prefer-to-break-a-route/6518/1) 37 | - [Status codes](https://httpstatuses.com/) 38 | 39 | ### Visit examples 40 | 41 | The syntax `site()->visit('error')` will not work if you change [`c::set('error')`](https://getkirby.com/docs/cheatsheet/options/error). The example below is better in that case. 42 | 43 | ```php 44 | return site()->visit(site()->errorPage()); 45 | ``` 46 | 47 | ### Full example 48 | 49 | ```php 50 | kirby()->routes(array( 51 | array( 52 | 'pattern' => 'some/page', 53 | 'action' => function() { 54 | return new Response('You have an error!', 'html', 404); 55 | } 56 | ) 57 | )); 58 | ``` 59 | 60 | ## Regular expressions 61 | 62 | ### Pattern examples 63 | 64 | ```php 65 | 'pattern' => '(.+)', // Match all 66 | 'pattern' => '(?!assets)(.*)', // Match all except the assets folder 67 | ``` 68 | 69 | #### Full example 70 | 71 | ```php 72 | kirby()->routes(array( 73 | array( 74 | 'pattern' => '(.+)', 75 | 'action' => function($uri) { 76 | echo $uri; 77 | } 78 | ) 79 | )); 80 | ``` 81 | 82 | - [Github - #368 - Route with the pattern just `(:all)` does not match](https://github.com/getkirby/kirby/issues/368) 83 | - [Forum - Routes - Prevent nesting from hell](https://forum.getkirby.com/t/routes-prevent-nesting-from-hell/3304) 84 | - [Forum - Not condition in routes](https://forum.getkirby.com/t/not-condition-in-regex-in-routes/6335) 85 | 86 | ### Built in patterns 87 | 88 | ```php 89 | '(:num)' => '(-?[0-9]+)', 90 | '(:alpha)' => '([a-zA-Z]+)', 91 | '(:any)' => '([a-zA-Z0-9\.\-_%=]+)', 92 | '(:all)' => '(.*)', 93 | '/(:num?)' => '(?:/([0-9]+)', 94 | '/(:alpha?)' => '(?:/([a-zA-Z]+)', 95 | '/(:any?)' => '(?:/([a-zA-Z0-9\.\-_%=]+)', 96 | '/(:all?)' => '(?:/(.*)', 97 | ``` 98 | 99 | - [Forum - Enable plugins to override panel routes](https://forum.getkirby.com/t/enable-plugins-to-override-panel-routes/8820/4) 100 | -------------------------------------------------------------------------------- /docs/page.md: -------------------------------------------------------------------------------- 1 | # Page 2 | 3 | ## Multilevel find 4 | 5 | Maybe we need to find something on an unknown level. In the case below we search by the slug: 6 | 7 | ```php 8 | $match = page('projects')->index()->findBy('slug', 'project-a'); 9 | if($match) { 10 | echo 'My category found'; 11 | } 12 | ``` 13 | 14 | **Source** 15 | 16 | https://forum.getkirby.com/t/multilevel-find/5577/3 17 | 18 | ## Get root parent 19 | 20 | **Structure** 21 | 22 | Let's say we want to get `projects` if we are at `projects`, `project-b` and `some-subpage`. That's what we call a root page in this example. 23 | 24 | ```text 25 | home 26 | projects 27 | project-a 28 | project-b 29 | some-subpage 30 | ``` 31 | 32 | **Function** 33 | 34 | ```php 35 | function rootParent($page) { 36 | if($page->depth() == 1 && ! $page->isHomePage()) { 37 | return $page; 38 | } 39 | return $page->parents()->last(); 40 | } 41 | ``` 42 | 43 | **Snippet** 44 | 45 | If root page is set, print the title. 46 | 47 | ```php 48 | $root_parent = rootParent($page); 49 | if($root_parent) { 50 | echo $root_parent->title(); 51 | } 52 | ``` 53 | 54 | **Source** 55 | 56 | https://forum.getkirby.com/t/get-root-page-of-child/3295/5 57 | 58 | ## Has parents 59 | 60 | You can't write `if($page->parents())` to see if the page contains. It needs to be done like below. 61 | 62 | 63 | ```php 64 | if($page->parents()->count() > 0) { 65 | echo 'Has parents'; 66 | } 67 | ``` 68 | 69 | or 70 | 71 | ```php 72 | if($page->parents()->toArray()) { 73 | echo 'Has parents'; 74 | } 75 | ``` 76 | 77 | **Source** 78 | 79 | https://forum.getkirby.com/t/if-has-parents/4874/3 80 | 81 | ## Page value manipulation 82 | 83 | Let's say you want to overwrite the field values of a page object. It's not as simple as it sounds. 84 | 85 | **In this example I will show you how you do that.** 86 | 87 | ```php 88 | class Test extends Page { 89 | private $array = array( 90 | 'title' => 'My overwritten title!', 91 | 'text' => 'My overwritten text!', 92 | 'addresses' => 'My overwritten address!' 93 | ); 94 | 95 | function title() { 96 | return $this->__call('title'); 97 | } 98 | 99 | function __call($key, $arguments = NULL){ 100 | $call = parent::__call($key, $arguments = NULL); 101 | if(is_object($call) && get_class($call) == 'Field') { 102 | if(is_array($this->array) && array_key_exists($key, $this->array)) { 103 | $call->value = $this->array[$key]; 104 | } 105 | } 106 | return $call; 107 | } 108 | } 109 | 110 | $new = new Test($page->parent(), $page->dirname()); 111 | 112 | echo $new->title(); 113 | echo $new->text(); 114 | echo $new->addresses(); 115 | ``` 116 | 117 | **Results** 118 | 119 | ```text 120 | My overwritten title! 121 | My overwritten text! 122 | My overwritten address! 123 | ``` 124 | 125 | ### What the code does 126 | 127 | First I create my own class that I call `Test` which extends the `Page` class. 128 | 129 | In my case I have set up an array with key/value pair, where I want to use the values instead of the original page values. 130 | 131 | In `__call` I check if the key exists in the array. If it does, it will use my new value, else it will just go with the old one. 132 | 133 | For some reason I also needed to add the `title` function which should normally be taken care of by the `__call`, but in this case I needed to force it to do a call as well. 134 | 135 | I create a new instance of a class that I call `$new`. It needs both a parent and a dirname as arguments. That means that you need to base it on an already existing page. 136 | -------------------------------------------------------------------------------- /docs/htaccess.md: -------------------------------------------------------------------------------- 1 | # Htaccess 2 | 3 | ## Browser cache 4 | 5 | Using the browser cache is good for both speed and SEO (Search Engine Optimization). It will set an expire date on different types of files. 6 | 7 | Place this code at the bottom of your htaccess file. 8 | 9 | ```text 10 | 11 | ExpiresActive On 12 | ExpiresDefault "access plus 10 days" 13 | ExpiresByType text/css "access plus 1 week" 14 | ExpiresByType text/plain "access plus 1 month" 15 | ExpiresByType image/gif "access plus 1 month" 16 | ExpiresByType image/png "access plus 1 month" 17 | ExpiresByType image/jpeg "access plus 1 month" 18 | ExpiresByType image/svg+xml "access plus 1 month" 19 | ExpiresByType application/javascript "access plus 1 week" 20 | ExpiresByType application/x-icon "access plus 1 year" 21 | 22 | ``` 23 | 24 | - [css-tricks - Set expires](https://css-tricks.com/snippets/htaccess/set-expires/) 25 | 26 | ## Gzip compression 27 | 28 | Gzip compression is good for both speed and SEO (Search Engine Optimization). 29 | 30 | Place this code at the bottom of your htaccess file. 31 | 32 | ```text 33 | 34 | AddOutputFilterByType DEFLATE \ 35 | "application/atom+xml" \ 36 | "application/javascript" \ 37 | "application/json" \ 38 | "application/ld+json" \ 39 | "application/manifest+json" \ 40 | "application/rdf+xml" \ 41 | "application/rss+xml" \ 42 | "application/schema+json" \ 43 | "application/vnd.geo+json" \ 44 | "application/vnd.ms-fontobject" \ 45 | "application/x-font-ttf" \ 46 | "application/x-javascript" \ 47 | "application/x-web-app-manifest+json" \ 48 | "application/xhtml+xml" \ 49 | "application/xml" \ 50 | "font/eot" \ 51 | "font/opentype" \ 52 | "image/bmp" \ 53 | "image/svg+xml" \ 54 | "image/vnd.microsoft.icon" \ 55 | "image/x-icon" \ 56 | "text/cache-manifest" \ 57 | "text/css" \ 58 | "text/html" \ 59 | "text/javascript" \ 60 | "text/plain" \ 61 | "text/vcard" \ 62 | "text/vnd.rim.location.xloc" \ 63 | "text/vtt" \ 64 | "text/x-component" \ 65 | "text/x-cross-domain-policy" \ 66 | "text/xml" 67 | 68 | ``` 69 | 70 | - [Server configs apache](https://github.com/h5bp/server-configs-apache) 71 | - [Server configs apache - Compression](https://github.com/h5bp/server-configs-apache/blob/master/src/web_performance/compression.conf) 72 | 73 | ## Redirect to https and non www 74 | 75 | This code will to two things: 76 | 77 | - Redirect from http to https 78 | - Redirect from www to non www 79 | 80 | Place it directly after `RewriteEngine on`. 81 | 82 | ```text 83 | RewriteCond %{HTTP_HOST} !=localhost 84 | RewriteCond %{HTTP_HOST} ^www\. [NC,OR] 85 | RewriteCond %{HTTPS} off 86 | RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC] 87 | RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L,NE] 88 | ``` 89 | 90 | ### http to https 91 | 92 | https is good for both security and SEO (Search Engine Optimization). To be able to use it, you need a certificate like [Let's Encrypt](https://letsencrypt.org/) which is free of charge. 93 | 94 | ### www to non www 95 | 96 | Many years ago `www` was more common. Nowdays many sites remove it because it's not needed. A shorter address is also more readable on a mobile device where the address is often cut off. 97 | 98 | - [Stackoverflow](http://stackoverflow.com/questions/39973281/) 99 | 100 | ## Sources 101 | 102 | - [css-tricks - Set expires](https://css-tricks.com/snippets/htaccess/set-expires/) 103 | - [Server configs apache](https://github.com/h5bp/server-configs-apache) 104 | - [Server configs apache - Compression](https://github.com/h5bp/server-configs-apache/blob/master/src/web_performance/compression.conf) 105 | - [Stackoverflow - http to https, www to non www and respect urls](http://stackoverflow.com/questions/39973281/) 106 | -------------------------------------------------------------------------------- /docs/panel-2/fields.md: -------------------------------------------------------------------------------- 1 | # Panel 2 - Fields 2 | 3 | ## Use already taken field keys 4 | 5 | Maybe you are creating a field that looks like this: 6 | 7 | **Blueprint** 8 | 9 | ```text 10 | fields: 11 | my_field: 12 | label: My field 13 | type: myfield 14 | template: A template name 15 | ``` 16 | 17 | **Inside the field** 18 | 19 | This will probably **NOT** work well, because `template` is already used by the panel. 20 | 21 | ```php 22 | echo $field->template(); 23 | ``` 24 | 25 | This will however work: 26 | 27 | ```php 28 | echo $field->__call('template', null); 29 | ``` 30 | 31 | **Source** 32 | 33 | https://forum.getkirby.com/t/best-practice-for-blueprint-options-in-plugins/4278/7 34 | 35 | ## Field inheritance 36 | 37 | When building a field based on another field it can sometimes be needed to get the previous generated output. 38 | 39 | It's possible to "inherit" the content by using `parent::content()` in this case. 40 | 41 | ```php 42 | class myfieldField extends TextareaField { 43 | public function content() { 44 | $inherit_content = parent::content(); 45 | return $inherit_content . ' more content'; 46 | } 47 | } 48 | ``` 49 | 50 | **Source** 51 | 52 | https://forum.getkirby.com/t/field-inherit-from-parent-in-extended-class/4231 53 | 54 | ## Field controllers 55 | 56 | Field controllers can be used to separate the route from the logic it contains. 57 | 58 | ### Field 59 | 60 | Here is a field that I've shorten down just to show how to use field controllers. It only contains the route. The `action` is important because instead of adding logic, we add a function name as a string. 61 | 62 | This file is called `boilertext.php`. 63 | 64 | ```php 65 | class BoilertextField extends BaseField { 66 | public function routes() { 67 | return array( 68 | array( 69 | 'pattern' => 'ajax/(:any)/(:any)', 70 | 'method' => 'get', 71 | 'action' => 'fromController' 72 | ) 73 | ); 74 | } 75 | } 76 | ``` 77 | 78 | ### Controller 79 | 80 | This file needs to be called `controller.php` and placed in the field folder. The name of this class also needs to match your field. In this case I match is with `BoilertextField` and just add `Controller` to it. 81 | 82 | The `$var1` and `$var2` comes from the both `(:any)` in the field route. 83 | 84 | ```php 85 | class BoilertextFieldController extends Kirby\Panel\Controllers\Field { 86 | public function fromController($var1, $var2) { 87 | return 'FROM CONTROLLER ' . $var1 . ' ' . $var2; 88 | } 89 | } 90 | ``` 91 | 92 | **Source** 93 | 94 | https://github.com/molocLab/kirby-calendar-board/blob/master/fields/calendarboard/controller.php 95 | 96 | ## Field assets 97 | 98 | Working with field assets are covered well in the documentation but there are some secrets left out. 99 | 100 | ### Dynamic assets 101 | 102 | For panel fields, you normally add the assets in your class like this: 103 | 104 | ```php 105 | static public $assets = array( 106 | 'css' => array('style.css'), 107 | 'js' => array('script.js'), 108 | ); 109 | ``` 110 | 111 | The problem with it is that you can't change the name of the asset depending on a variable or condition. 112 | 113 | #### Solution 114 | 115 | Let's say we want to add a color config value with `c::set('my.plugin.color', 'red');`. 116 | 117 | First we need to define a `$assets` variable in the class: 118 | 119 | ```php 120 | class MyField extends BaseField { 121 | static public $assets; 122 | } 123 | ``` 124 | 125 | Below the class we can add things to it: 126 | 127 | ```php 128 | MyField::$assets = array( 129 | 'css' => array('style.' . c::get('my.plugin.color') . '.css'), 130 | 'js' => array('script.js'), 131 | ); 132 | ``` 133 | 134 | A downside to this is that we can't add the assets inside the class with this solution. 135 | 136 | **Source + issue:** https://github.com/getkirby/panel/issues/1058 137 | 138 | ## Field routes 139 | 140 | Kirby has routes but the fields also have their own routes. Below is a stripped down field that shows how to work with routes in fields. 141 | 142 | ```php 143 | class BoilerField extends BaseField { 144 | public function routes() { 145 | return array( 146 | array( 147 | 'pattern' => 'ajax/(:any)/(:any)', 148 | 'method' => 'get', 149 | 'action' => function($var1, $var2) { 150 | return response::json( array( $var1, $var2 ) ); 151 | } 152 | ) 153 | ); 154 | } 155 | } 156 | ``` 157 | 158 | ### Url format 159 | 160 | When the route is setup in the field you can test it by visiting the url for it. Change the domain to your domain. Replace `[PAGE_ID]` with for example `projects/project-a`. Replace `[BLUEPRINT_KEY]` with for example `text` and `[FIELD_NAME]` with `textarea`. 161 | 162 | ```text 163 | https://example.com/panel/pages/[PAGE_ID]/field/[BLUEPRINT_KEY]/[FIELD_NAME]/ajax/var1/var2 164 | ``` 165 | 166 | **Note** 167 | 168 | Personally I prefer to use the `kirby()->routes()` function even for fields, because I find them more simple and reliable. 169 | 170 | **Source** 171 | 172 | https://forum.getkirby.com/t/routing-in-custom-form-field/3101/7 173 | 174 | ## Get fields object from another field 175 | 176 | When making a field, it is sometimes needed to get the field object from another field. It's not super simple, but it's possible. 177 | 178 | **First in the field file** 179 | 180 | ```php 181 | use Kirby\Panel\Models\Page\Blueprint; 182 | ``` 183 | 184 | **Inside your field** 185 | 186 | In this case I use the `default` blueprint. Then I print the `label` in the `text` field. 187 | 188 | ```php 189 | $blueprint = new Blueprint('default'); 190 | $fields = $blueprint->fields(null); 191 | 192 | print_r($fields->text()->label()); 193 | ``` 194 | 195 | **Source** 196 | 197 | https://forum.getkirby.com/t/get-panel-field-object-from-another-field-within-a-field/3758 -------------------------------------------------------------------------------- /docs/plugin/best-practices.md: -------------------------------------------------------------------------------- 1 | # Plugin development - Best practices 2 | 3 | These best practices are, like everything else in this repository, unofficial recommendations. 4 | 5 | ## Table of contents 6 | 7 | - [Collisions](#collisions) 8 | - [Security](#security) 9 | - [Github](#github) 10 | 11 | ## Security 12 | 13 | ### Routes 14 | 15 | When you create a route, **always** think about where it will be used. 16 | 17 | **Panel** 18 | 19 | Maybe it's only for the panel. Then make sure the panel exists first: 20 | 21 | ```php 22 | if(class_exists('Panel') { 23 | // Route 24 | } 25 | ``` 26 | 27 | **Logged in users** 28 | 29 | Maybe it's for logged in users. Then make sure the user is logged in: 30 | 31 | ```php 32 | if(site()->user()) { 33 | // Route 34 | } 35 | ``` 36 | 37 | It's also possible to combine these two. 38 | 39 | ### Ajax 40 | 41 | When using ajax on the page or in the panel you can sometimes see a `CSRF` value. To protect against false requests you can check that value against a PHP string. 42 | 43 | One of these should probably match that `CSRF` value: 44 | 45 | ```php 46 | echo csrf(); 47 | echo s::get('csrf'); 48 | ``` 49 | 50 | **Read more:** 51 | 52 | - https://forum.getkirby.com/t/csrf-in-a-working-post-route-do-i-need-to-worry/4284/3 53 | - https://getkirby.com/docs/cheatsheet/helpers/csrf 54 | - https://getkirby.com/docs/toolkit/api/helpers/csrf 55 | 56 | ## Collisions 57 | 58 | ### Components and models 59 | 60 | Components and models have on thing in common. They both works as extended classes. It means that only one plugin can use that particular class. Therefor you need to be extra careful before using them. 61 | 62 | If you really need to extend one of these classes, add an config option for it. Then the site admin can in some cases disable that extended feature and handle it differently, to make it work with all the other plugins. 63 | 64 | ### Page methods and pages methods 65 | 66 | If you are having a page method or a pages method, make sure to think of a name that can't collide with other plugins or with the fields. It's not as sensitive as components and models, but the collision risk is still present. 67 | 68 | I would also recommend to by a config option, set a custom name and a disable config option. If it's disabled, the site admin can choose to have the page method or not. 69 | 70 | https://forum.getkirby.com/t/page-field-key-in-collision-with-page-method-name/1359/3 71 | 72 | **Protected page methods by the core:** 73 | 74 | https://getkirby.com/docs/cheatsheet#page 75 | 76 | **Protected pages methods by the core** 77 | 78 | https://getkirby.com/docs/cheatsheet#pages 79 | 80 | ### Config options 81 | 82 | If you are having config options, make sure to think of a name that can't collide with other plugins or with the core. 83 | 84 | **One way is to prefix the options like this:** 85 | 86 | ```php 87 | c::set('plugin.[plugin-name].[option-key]'); 88 | ``` 89 | 90 | **Protected options by the core:** 91 | 92 | https://getkirby.com/docs/cheatsheet#options 93 | 94 | ### Blueprint options 95 | 96 | In most cases, try to use keys that might not be used for anything else. The key `template` is for example already used by the panel. 97 | 98 | If you really need to use a protected name, in some cases this will work inside a field: 99 | 100 | ```php 101 | echo $field->__call('template', null); 102 | ``` 103 | 104 | **Source** 105 | 106 | https://github.com/jenstornell/kirby-secrets/wiki/Use-already-taken-panel-field-keys 107 | 108 | ### Plugin name 109 | 110 | To make sure you have an unique plugin name, you can search the [Kirby Plugins repository](https://github.com/jenstornell/kirby-plugins/issues). 111 | 112 | ### Namespaces 113 | 114 | To not have a collision with other classes or methods you need to prefix or use a namespace. I think namespaces is the way to go. 115 | 116 | **Example** 117 | 118 | ```php 119 | image(c::get('plugin.test.cover')); 126 | } 127 | } 128 | 129 | $kirby->set('page::model', 'project', 'JensTornell\Bricks\\ProjectPage'); 130 | ``` 131 | 132 | **Source** 133 | 134 | https://forum.getkirby.com/t/model-class-is-defined-or-can-be-autoloaded/6255/4 135 | 136 | ### Fields 137 | 138 | **Naming** 139 | 140 | To make sure you have an unique field name, you can search the field in the [Kirby Plugins repository](https://github.com/jenstornell/kirby-plugins/labels/Field). 141 | 142 | **Make sure to get the field** 143 | 144 | When using fields in plugins, to be extra careful, you can make sure you get the field value: 145 | 146 | ```php 147 | echo $page->content()->get('url'); 148 | ``` 149 | 150 | If you use `echo $page->url()` instead of the above, you will **not** get the field value. Instead you will get the built in page url. 151 | 152 | ## Github 153 | 154 | ### Readme 155 | 156 | The frontpage of the plugin is controlled by the `readme.md` file. 157 | 158 | To get started, there is a brilliant [Kirby boiler readme](Boiler-readme) file. It contains a starting point for almost everything you need in your readme file. 159 | 160 | ### License 161 | 162 | **MIT** 163 | 164 | If your plugin should be free, a great license for that is [MIT](https://opensource.org/licenses/MIT). 165 | 166 | **Kirby license** 167 | 168 | If your plugin should have a license fee, the [Kirby license](https://getkirby.com/license) is a good example. In short it says, [try it](https://getkirby.com/try) and when you are happy with it, buy it. 169 | 170 | The greatest thing about it is that the code is totally open to read and to try. Very honest that way. There should not be much refunds with this license, because the user buys it when everything works well. 171 | 172 | **LICENSE file** 173 | 174 | In Github you can add a [LICENSE](https://help.github.com/articles/adding-a-license-to-a-repository/) file and Github will extract some useful information from it. 175 | 176 | **Kirby CLI** 177 | 178 | [Kirby CLI](https://github.com/getkirby/cli) is, among other things, a plugin installer. 179 | 180 | For it to work with your plugin you need a `package.json` file. Only `type` is required. 181 | 182 | An example: 183 | 184 | ```php 185 | { 186 | "name": "kirby-reveal", 187 | "description": "Splitscreen preview of the site in the panel", 188 | "author": "Jens Törnell ", 189 | "version": "0.5", 190 | "type": "kirby-plugin", 191 | "license": "MIT" 192 | } 193 | ``` --------------------------------------------------------------------------------