├── .env ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── docker-compose.yml └── src ├── Api └── Data │ └── ManifestInterface.php ├── Block └── Register.php ├── Controller ├── Index │ └── Json.php └── Router.php ├── Helper └── Config.php ├── Model ├── Config │ └── Source │ │ ├── Displaytype.php │ │ └── Orientation.php └── Manifest.php ├── etc ├── adminhtml │ └── system.xml ├── config.xml ├── di.xml ├── frontend │ ├── di.xml │ └── routes.xml └── module.xml ├── registration.php └── view └── frontend └── layout └── default.xml /.env: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=m2_meanbee_webappmanifest 2 | 3 | PROJECT_HOSTNAME=m2-meanbee-webappmanifest.dev.docker 4 | PROJECT_CERT=dev.docker 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /magento 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Meanbee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Meanbee_WebAppManifest 2 | 3 | A Magento 2 extension that adds a [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) to the store. 4 | 5 | ## Installation 6 | 7 | Install this extension via Composer: 8 | 9 | composer require meanbee/magento2-webappmanifest 10 | 11 | ## Usage 12 | 13 | Configure the information displayed in the manifest and enable it in * Stores > Configuration > General > Web > Web App Manifest Settings *. 14 | 15 | ## Development 16 | 17 | ### Setting up a development environment 18 | 19 | A Docker development environment is included with the project: 20 | 21 | docker-compose run --rm cli magento-extension-installer Meanbee_WebAppManifest \ 22 | && docker-compose up -d 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meanbee/magento2-webappmanifest", 3 | "description": "A Magento 2 extension that adds a Web App Manifest to the store.", 4 | "type": "magento2-module", 5 | "version": "1.1.0", 6 | "license": [ 7 | "MIT" 8 | ], 9 | "authors": [ 10 | { 11 | "name": "Tomas Gerulaitis", 12 | "email": "tomas.gerulaitis@meanbee.com" 13 | } 14 | ], 15 | "repositories": { 16 | "magento": { 17 | "type": "composer", 18 | "url": "https://repo.magento.com/" 19 | } 20 | }, 21 | "require": { 22 | "magento/framework": "^101.0.0", 23 | "magento/module-backend": "^100.1.2", 24 | "magento/module-config": "^101.0.0", 25 | "magento/module-store": "^100.1.3" 26 | }, 27 | "autoload": { 28 | "files": [ 29 | "src/registration.php" 30 | ], 31 | "psr-4": { 32 | "Meanbee\\WebAppManifest\\": "src/" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | varnish: 4 | image: meanbee/magento2-varnish:latest 5 | hostname: ${PROJECT_HOSTNAME} 6 | ports: 7 | - 80 8 | environment: 9 | VIRTUAL_HOST: ${PROJECT_HOSTNAME} 10 | VIRTUAL_PORT: 80 11 | HTTPS_METHOD: noredirect 12 | CERT_NAME: ${PROJECT_CERT} 13 | links: 14 | - web 15 | 16 | web: 17 | image: meanbee/magento2-nginx:1.9 18 | hostname: web.${PROJECT_HOSTNAME} 19 | ports: 20 | - 80 21 | volumes_from: 22 | - magento 23 | links: 24 | - fpm 25 | 26 | fpm: 27 | image: meanbee/magento2-php:7.0-fpm 28 | hostname: fpm.${PROJECT_HOSTNAME} 29 | ports: 30 | - 9000 31 | volumes_from: 32 | - magento 33 | environment: 34 | ENABLE_SENDMAIL: "true" 35 | PHP_ENABLE_XDEBUG: 36 | links: 37 | - db 38 | 39 | cron: 40 | image: meanbee/magento2-php:7.0-cli 41 | hostname: cron.${PROJECT_HOSTNAME} 42 | command: run-cron 43 | volumes_from: 44 | - magento 45 | environment: 46 | ENABLE_SENDMAIL: "true" 47 | links: 48 | - db 49 | 50 | cli: 51 | image: meanbee/magento2-php:7.0-cli 52 | volumes_from: 53 | - magento 54 | environment: 55 | COMPOSER_HOME: /root/.composer 56 | COMPOSER_ALLOW_SUPERUSER: 1 57 | M2SETUP_INSTALL_DB: "true" 58 | M2SETUP_VERSION: 2.2.* 59 | M2SETUP_USE_SAMPLE_DATA: "true" 60 | M2SETUP_DB_HOST: db 61 | M2SETUP_DB_NAME: magento2 62 | M2SETUP_DB_USER: magento2 63 | M2SETUP_DB_PASSWORD: magento2 64 | M2SETUP_BASE_URL: https://${PROJECT_HOSTNAME}/ 65 | M2SETUP_BACKEND_FRONTNAME: admin 66 | M2SETUP_ADMIN_FIRSTNAME: Admin 67 | M2SETUP_ADMIN_LASTNAME: User 68 | M2SETUP_ADMIN_EMAIL: admin@example.com 69 | M2SETUP_ADMIN_USER: admin 70 | M2SETUP_ADMIN_PASSWORD: password123 71 | links: 72 | - db 73 | 74 | db: 75 | image: mariadb:10 76 | ports: 77 | - 3306 78 | volumes: 79 | - dbdata:/var/lib/mysql 80 | environment: 81 | MYSQL_ROOT_PASSWORD: magento2 82 | MYSQL_USER: magento2 83 | MYSQL_PASSWORD: magento2 84 | MYSQL_DATABASE: magento2 85 | TERM: dumb 86 | 87 | magento: 88 | image: meanbee/magento2-data:2.2-sample 89 | volumes: 90 | - .:/extensions/Meanbee_WebAppManifest 91 | environment: 92 | SYNC_DESTINATION: /extensions/Meanbee_WebAppManifest/magento 93 | privileged: true 94 | 95 | volumes: 96 | dbdata: 97 | # Database tables 98 | 99 | -------------------------------------------------------------------------------- /src/Api/Data/ManifestInterface.php: -------------------------------------------------------------------------------- 1 | config = $config; 27 | $this->template = $template; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | protected function _toHtml() 34 | { 35 | if ($this->config->isEnabled()) { 36 | return sprintf( 37 | $this->template, 38 | $this->_urlBuilder->getDirectUrl(\Meanbee\WebAppManifest\Controller\Router::MANIFEST_ENDPOINT) 39 | ); 40 | } else { 41 | return ''; 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/Controller/Index/Json.php: -------------------------------------------------------------------------------- 1 | jsonFactory = $jsonFactory; 23 | $this->manifest = $manifest; 24 | } 25 | 26 | /** 27 | * @inheritdoc 28 | */ 29 | public function execute() 30 | { 31 | return $this->jsonFactory->create()->setData($this->manifest->getData()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Controller/Router.php: -------------------------------------------------------------------------------- 1 | actionFactory = $actionFactory; 20 | $this->config = $config; 21 | } 22 | 23 | public function match(\Magento\Framework\App\RequestInterface $request) 24 | { 25 | if ($this->config->isEnabled() && trim($request->getPathInfo(), "/") == static::MANIFEST_ENDPOINT) { 26 | $request 27 | ->setModuleName("webappmanifest") 28 | ->setControllerName("index") 29 | ->setActionName("json"); 30 | 31 | return $this->actionFactory->create('Magento\Framework\App\Action\Forward'); 32 | } 33 | 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Helper/Config.php: -------------------------------------------------------------------------------- 1 | scopeConfig->isSetFlag(static::XML_PATH_ENABLE, ScopeInterface::SCOPE_STORE, $scope); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Model/Config/Source/Displaytype.php: -------------------------------------------------------------------------------- 1 | toArray() as $value => $label) { 14 | $options[] = ["value" => $value, "label" => $label]; 15 | } 16 | 17 | return $options; 18 | } 19 | 20 | /** 21 | * Get options in "key=>value" format. 22 | * 23 | * @return array 24 | */ 25 | public function toArray() 26 | { 27 | return [ 28 | "browser" => __("Web Page"), 29 | "minimal-ui" => __("Minimal UI"), 30 | "standalone" => __("Standalone App"), 31 | "fullscreen" => __("Fullscreen App"), 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Model/Config/Source/Orientation.php: -------------------------------------------------------------------------------- 1 | toArray() as $value => $label) { 14 | $options[] = ["value" => $value, "label" => $label]; 15 | } 16 | 17 | return $options; 18 | } 19 | 20 | /** 21 | * Get options in "key=>value" format. 22 | * 23 | * @return array 24 | */ 25 | public function toArray() 26 | { 27 | return [ 28 | "any" => __("Any"), 29 | "natural" => __("Natural"), 30 | "portrait" => __("Portrait"), 31 | "landscape" => __("Landscape"), 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Model/Manifest.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 36 | $this->urlBuilder = $urlBuilder; 37 | $this->data = []; 38 | 39 | $this->populate(); 40 | } 41 | 42 | /** 43 | * @inheritdoc 44 | */ 45 | public function getData() 46 | { 47 | return $this->data; 48 | } 49 | 50 | /** 51 | * Populate the Manifest data from configuration. 52 | * 53 | * @return $this 54 | */ 55 | public function populate() 56 | { 57 | $this->populateStoreInformation(); 58 | $this->populateDisplayOptions(); 59 | $this->populateIcons(); 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Populate the manifest with store information. 66 | * 67 | * @return $this 68 | */ 69 | protected function populateStoreInformation() 70 | { 71 | $this->populateFromConfig("short_name", static::XML_PATH_STORE_INFO_SHORT_NAME); 72 | $this->populateFromConfig("name", static::XML_PATH_STORE_INFO_NAME); 73 | $this->populateFromConfig("description", static::XML_PATH_STORE_INFO_DESCRIPTION, true); 74 | 75 | if ($path = $this->scopeConfig->getValue(static::XML_PATH_STORE_INFO_START_URL, ScopeInterface::SCOPE_STORE)) { 76 | $start_url = $this->urlBuilder->getDirectUrl($path); 77 | } else { 78 | $start_url = $this->urlBuilder->getBaseUrl(); 79 | } 80 | $this->data["start_url"] = $start_url; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * Populate the manifest with display settings. 87 | * 88 | * @return $this 89 | */ 90 | protected function populateDisplayOptions() 91 | { 92 | $this->populateFromConfig("theme_color", static::XML_PATH_DISPLAY_THEME_COLOR, true); 93 | $this->populateFromConfig("background_color", static::XML_PATH_DISPLAY_BACKGROUND_COLOR, true); 94 | $this->populateFromConfig("display", static::XML_PATH_DISPLAY_DISPLAY_TYPE); 95 | $this->populateFromConfig("orientation", static::XML_PATH_DISPLAY_ORIENTATION); 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Populate the manifest with app icon definitions. 102 | * 103 | * @return $this 104 | */ 105 | protected function populateIcons() 106 | { 107 | if ($icon = $this->scopeConfig->getValue(static::XML_PATH_ICONS_ICON, ScopeInterface::SCOPE_STORE)) { 108 | $url = implode("", [ 109 | $this->urlBuilder->getBaseUrl(["_type" => UrlInterface::URL_TYPE_MEDIA]), 110 | "webappmanifest/icons/", 111 | $icon, 112 | ]); 113 | 114 | $sizes = $this->scopeConfig->getValue(static::XML_PATH_ICONS_SIZES, ScopeInterface::SCOPE_STORE); 115 | 116 | $this->data["icons"] = [["src" => $url, "sizes" => $sizes]]; 117 | } 118 | 119 | return $this; 120 | } 121 | 122 | /** 123 | * Populate a manifest value from System Configration. 124 | * 125 | * @param $key 126 | * @param $config_path 127 | * @param bool $if_exists Only populate the value if it's not empty (default: false) 128 | * 129 | * @return $this 130 | */ 131 | protected function populateFromConfig($key, $config_path, $if_exists = false) 132 | { 133 | $value = $this->scopeConfig->getValue($config_path, ScopeInterface::SCOPE_STORE); 134 | 135 | if (!$if_exists || !empty($value)) { 136 | $this->data[$key] = $value; 137 | } 138 | 139 | return $this; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | Magento\Config\Model\Config\Source\Yesno 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Meanbee\WebAppManifest\Model\Config\Source\Displaytype 36 | 37 | 38 | 39 | 40 | Meanbee\WebAppManifest\Model\Config\Source\Orientation 41 | 42 | 43 | 44 | 45 | Magento\Config\Model\Config\Backend\Image 46 | webappmanifest/icons 47 | webappmanifest/icons 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 |
56 |
57 | -------------------------------------------------------------------------------- /src/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 0 8 | browser 9 | any 10 | 48x48 72x72 128x128 256x256 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/etc/frontend/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Meanbee\WebAppManifest\Controller\Router 8 | false 9 | 55 10 | 11 | 12 | 13 | 14 | 15 | 16 | ]]> 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------