├── .gitignore ├── .gitattributes ├── composer.json ├── .editorconfig ├── SECURITY.md ├── blueprints └── pages │ └── product.yml ├── LICENSE ├── index.php ├── README.md ├── models └── products.php ├── composer.lock └── src └── classes └── LemonSqueezy.php /.gitignore: -------------------------------------------------------------------------------- 1 | # OS files 2 | .DS_Store 3 | 4 | # npm modules 5 | /node_modules 6 | 7 | # Composer files 8 | /vendor -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Note: You need to uncomment the lines you want to use; the other lines can be deleted 2 | 3 | # Git 4 | # .gitattributes export-ignore 5 | # .gitignore export-ignore 6 | 7 | # Tests 8 | # /.coveralls.yml export-ignore 9 | # /.travis.yml export-ignore 10 | # /phpunit.xml.dist export-ignore 11 | # /tests/ export-ignore 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hashandsalt/lemonsqueezy", 3 | "description": "Lemon Squeezy E-Commerce plugin", 4 | "license": "MIT", 5 | "type": "kirby-plugin", 6 | "version": "0.6.0.0", 7 | "authors": [ 8 | { 9 | "name": "Hash&Salt", 10 | "email": "hello@hashandsalt.com" 11 | } 12 | ], 13 | "require": { 14 | "getkirby/composer-installer": "^1.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.php] 13 | indent_size = 4 14 | 15 | [*.md,*.txt] 16 | trim_trailing_whitespace = false 17 | insert_final_newline = false 18 | 19 | [composer.json] 20 | indent_size = 4 21 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | *Use this section to tell people about which versions of your project are currently being supported with security updates.* 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 5.1.x | :white_check_mark: | 10 | | 5.0.x | :x: | 11 | | 4.0.x | :white_check_mark: | 12 | | < 4.0 | :x: | 13 | 14 | ## Reporting a Vulnerability 15 | 16 | *Use this section to tell people how to report a vulnerability.* 17 | 18 | *Tell them where to go, how often they can expect to get an update on a reported vulnerability, what to expect if the vulnerability is accepted or declined, etc.* 19 | -------------------------------------------------------------------------------- /blueprints/pages/product.yml: -------------------------------------------------------------------------------- 1 | title: Product 2 | 3 | columns: 4 | # MAIN 5 | left: 6 | width: 2/3 7 | sections: 8 | # IMAGE FILES 9 | pdescription: 10 | headline: description 11 | type: fields 12 | fields: 13 | description: 14 | type: writer 15 | disabled: true 16 | 17 | right: 18 | width: 1/3 19 | sections: 20 | # IMAGE FILES 21 | details: 22 | headline: Details 23 | type: fields 24 | fields: 25 | productstatus: 26 | type: text 27 | label: Lemon Squeezy Status 28 | disabled: true 29 | 30 | formattedprice: 31 | type: text 32 | label: Price 33 | disabled: true 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hash&Salt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 'src/classes/LemonSqueezy.php', 7 | ], __DIR__); 8 | 9 | 10 | use HashAndSalt\Lemon\Squeezy; 11 | 12 | require __DIR__ . '/models/products.php'; 13 | 14 | Kirby::plugin('hashandsalt/lemonsqueezy', [ 15 | // Options 16 | 17 | 18 | 'options' => [ 19 | 'cache.products' => true, 20 | 'cache.product' => true, 21 | 'cache.stores' => true, 22 | 'cache.store' => true, 23 | 'template' => kirby()->option('hashandsalt.lemonsqueezy.template'), 24 | 'model' => kirby()->option('hashandsalt.lemonsqueezy.model') 25 | ], 26 | 27 | 'blueprints' => [ 28 | 'product' => __DIR__ . '/blueprints/pages/product.yml', 29 | 30 | ], 31 | 32 | 'pageModels' => [ 33 | 'products' => 'ProductsPage' 34 | 35 | ], 36 | 37 | 38 | # Page methods 39 | 'siteMethods' => [ 40 | 'stores' => function () { 41 | $init = new Squeezy(); 42 | return $init->stores(); 43 | }, 44 | 'store' => function ($id) { 45 | $init = new Squeezy(); 46 | return $init->store($id); 47 | }, 48 | 49 | 'products' => function ($id = null) { 50 | $init = new Squeezy(); 51 | return $init->products($id, 'products'); 52 | }, 53 | 'product' => function ($id) { 54 | $init = new Squeezy(); 55 | return $init->product($id); 56 | }, 57 | 58 | 59 | ], 60 | 61 | 62 | ]); 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WARNING This plugin is shiny new beta! Use with caution and please feedback any issues via Github issues if you have any problems. 2 | 3 | # Kirby3 Lemon Squeezy 4 | 5 | A plugin for working with the Lemon Squeezy API. 6 | 7 | Features 8 | 9 | * Fetch Store(s) 10 | * Fetch Product(s) 11 | * Turns products into virtual pages 12 | 13 | ææ Install 14 | 15 | ``` 16 | composer require hashandsalt/lemonsqueezy 17 | ``` 18 | 19 | You can also install manually by placing the folder inside your plugins folder. 20 | 21 | ## Config 22 | 23 | Add your API keys to the `Config.php` 24 | 25 | ``` 26 | // API Keys 27 | 'hashandsalt.lemonsqueezy.testmode' => true, // flick to false in to use the live API 28 | 'hashandsalt.lemonsqueezy.testapikey' => 'XXX', 29 | 'hashandsalt.lemonsqueezy.liveapikey' => 'XXX' 30 | ``` 31 | 32 | Change the default template and model for the virtual pages (optional) 33 | 34 | ``` 35 | // Virtual Pages 36 | 'hashandsalt.lemonsqueezy.template' => 'products', 37 | 'hashandsalt.lemonsqueezy.model' => 'products', 38 | ``` 39 | 40 | ## Usage 41 | 42 | ### Fetching store data 43 | 44 | An array of all stores 45 | 46 | ``` 47 | $stores = $site->stores(); 48 | ``` 49 | 50 | A specific store by ID 51 | 52 | ``` 53 | $store = $site->store('11087'); 54 | ``` 55 | 56 | ### Fetching product data 57 | 58 | 59 | An array of all products 60 | 61 | ``` 62 | $products = $site->products(); 63 | ``` 64 | 65 | A specific product by ID 66 | 67 | ``` 68 | $product = $site->product('22352'); 69 | ``` 70 | 71 | ## Virtual Pages 72 | 73 | Available fields in the virtual pages 74 | 75 | ``` 76 | 'title' => $productitem->attributes->name, 77 | 'description' => $productitem->attributes->description, 78 | 'product_status' => $productitem->attributes->status, 79 | 'thumb_url' => $productitem->attributes->thumb_url, 80 | 'large_thumb_url' => $productitem->attributes->large_thumb_url, 81 | 'price' => $productitem->attributes->price, 82 | 'formatted_price' => $productitem->attributes->price_formatted, 83 | 'buy_now_url' => $productitem->attributes->buy_now_url 84 | ``` -------------------------------------------------------------------------------- /models/products.php: -------------------------------------------------------------------------------- 1 | inventory()['children'], $this); 10 | } 11 | 12 | 13 | public function children() 14 | { 15 | 16 | 17 | $apiCache = kirby()->cache('hashandsalt.lemonsqueezy.products'); 18 | $apiData = $apiCache->get('hashandsalt.lemonsqueezy.products'); 19 | site()->products(null); 20 | 21 | 22 | foreach ($apiData['data'] as $key => $productitem) { 23 | 24 | if ($productitem['attributes']['status'] === 'published') { 25 | 26 | $key++; 27 | 28 | $slug = $productitem['attributes']['slug']; 29 | $page = $this->subpages()->find($slug); 30 | 31 | $pages[] = [ 32 | 'slug' => $productitem['attributes']['slug'], 33 | 34 | 35 | 'template' => kirby()->option('hashandsalt.lemonsqueezy.template'), 36 | 'model' => kirby()->option('hashandsalt.model'), 37 | // 'dirname' => $key.'_'.$productitem->attributes->slug, 38 | 'num' => $key, 39 | 'files' => $page ? $page->files()->toArray() : null, 40 | 'content' => [ 41 | 'title' => $productitem['attributes']['name'], 42 | 'description' => $productitem['attributes']['description'], 43 | 'product_status' => $productitem['attributes']['status'], 44 | 'thumburl' => $productitem['attributes']['thumb_url'], 45 | 'largethumburl' => $productitem['attributes']['large_thumb_url'], 46 | 'price' => $productitem['attributes']['price'], 47 | 'formattedprice' => $productitem['attributes']['price_formatted'], 48 | 'buynowurl' => $productitem['attributes']['buy_now_url'] 49 | ] 50 | ]; 51 | 52 | 53 | } 54 | 55 | 56 | 57 | } 58 | return Pages::factory($pages, $this); 59 | } 60 | 61 | 62 | } -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "37a8e61308b9b6f49cb9835f477f0c64", 8 | "packages": [ 9 | { 10 | "name": "getkirby/composer-installer", 11 | "version": "1.2.1", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/getkirby/composer-installer.git", 15 | "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/getkirby/composer-installer/zipball/c98ece30bfba45be7ce457e1102d1b169d922f3d", 20 | "reference": "c98ece30bfba45be7ce457e1102d1b169d922f3d", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "composer-plugin-api": "^1.0 || ^2.0" 25 | }, 26 | "require-dev": { 27 | "composer/composer": "^1.8 || ^2.0" 28 | }, 29 | "type": "composer-plugin", 30 | "extra": { 31 | "class": "Kirby\\ComposerInstaller\\Plugin" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "Kirby\\": "src/" 36 | } 37 | }, 38 | "notification-url": "https://packagist.org/downloads/", 39 | "license": [ 40 | "MIT" 41 | ], 42 | "description": "Kirby's custom Composer installer for the Kirby CMS and for Kirby plugins", 43 | "homepage": "https://getkirby.com", 44 | "support": { 45 | "issues": "https://github.com/getkirby/composer-installer/issues", 46 | "source": "https://github.com/getkirby/composer-installer/tree/1.2.1" 47 | }, 48 | "funding": [ 49 | { 50 | "url": "https://getkirby.com/buy", 51 | "type": "custom" 52 | } 53 | ], 54 | "time": "2020-12-28T12:54:39+00:00" 55 | } 56 | ], 57 | "packages-dev": [], 58 | "aliases": [], 59 | "minimum-stability": "stable", 60 | "stability-flags": [], 61 | "prefer-stable": false, 62 | "prefer-lowest": false, 63 | "platform": [], 64 | "platform-dev": [], 65 | "plugin-api-version": "2.3.0" 66 | } 67 | -------------------------------------------------------------------------------- /src/classes/LemonSqueezy.php: -------------------------------------------------------------------------------- 1 | option('hashandsalt.lemonsqueezy.testmode') === true ? kirby()->option('hashandsalt.lemonsqueezy.testapikey') : kirby()->option('hashandsalt.lemonsqueezy.liveapikey') ; 21 | 22 | $data = null; 23 | $options = [ 24 | 'headers' => [ 25 | 'Authorization: Bearer ' . $key, 26 | 'Accept: application/vnd.api+json', 27 | 'Content-Type: application/vnd.api+json' 28 | ], 29 | 'method' => 'GET', 30 | 'data' => json_encode($data) 31 | ]; 32 | 33 | $cacheName = 'hashandsalt.lemonsqueezy.' . $cacheName; 34 | 35 | 36 | $apiCache = kirby()->cache($cacheName); 37 | $apiData = $apiCache->get($cacheName); 38 | 39 | 40 | 41 | 42 | 43 | if ($apiData === null) { 44 | $request = Remote::request($url, $options); 45 | 46 | if ($request->code() === 200) { 47 | $data = $request; 48 | $data = json_decode($data->content); 49 | $apiCache->set($cacheName, $data); 50 | } 51 | 52 | 53 | } 54 | 55 | 56 | return $apiData; 57 | 58 | } 59 | 60 | /** 61 | * Fetches Lsst of Stores 62 | * 63 | 64 | * @return array 65 | */ 66 | public function stores() 67 | { 68 | 69 | $stores = self::endpoint('stores', 'stores'); 70 | 71 | return $stores; 72 | 73 | } 74 | 75 | /** 76 | * Fetch Single Store 77 | * 78 | 79 | * @return array 80 | */ 81 | public function store($id) 82 | { 83 | 84 | $store = self::endpoint('stores/'. $id, 'store'); 85 | 86 | return $store; 87 | 88 | } 89 | 90 | 91 | /** 92 | * Fetches Lsst of Products 93 | * 94 | 95 | * @return mixed 96 | */ 97 | public function products($id, $cacheName) 98 | { 99 | if ($id === null) { 100 | $products = self::endpoint('products', $cacheName); 101 | } else { 102 | $end = '?filter[store_id]='.$id; 103 | $products = self::endpoint($end, $cacheName); 104 | } 105 | return $products; 106 | } 107 | 108 | /** 109 | * Fetch Single Product 110 | * 111 | 112 | * @return array 113 | */ 114 | public function product($id) 115 | { 116 | $cache = 'product'; 117 | $product = self::endpoint('products/'.$id, $cache); 118 | 119 | return $product; 120 | 121 | } 122 | } 123 | --------------------------------------------------------------------------------