add my module
This commit is contained in:
		
							parent
							
								
									e4b66e4508
								
							
						
					
					
						commit
						d738ce62b6
					
				
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,177 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Banner\Api; | ||||||
|  | 
 | ||||||
|  | use Kai\Banner\Api\BannerRepositoryInterface; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @api | ||||||
|  |  */ | ||||||
|  | class BannerRepository implements BannerRepositoryInterface | ||||||
|  | { | ||||||
|  |     protected $kaiBannerModel; | ||||||
|  |     protected $kaiBannerResourceModel; | ||||||
|  |     protected $kaiBannerCollection; | ||||||
|  | 
 | ||||||
|  |     function __construct( | ||||||
|  |         \Kai\Banner\Model\KaiBanner $kaiBannerModel, | ||||||
|  |         \Kai\Banner\Model\KaiBannerResourceModel $kaiBannerResourceModel, | ||||||
|  |         \Kai\Banner\Model\KaiBannerCollection $kaiBannerCollection, | ||||||
|  |     ) | ||||||
|  |     { | ||||||
|  |         $this->kaiBannerModel = $kaiBannerModel; | ||||||
|  |         $this->kaiBannerResourceModel = $kaiBannerResourceModel; | ||||||
|  |         $this->kaiBannerCollection = $kaiBannerCollection; | ||||||
|  |         $this->authorization(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function authorization() | ||||||
|  |     { | ||||||
|  |         $headers = apache_request_headers(); | ||||||
|  |         $apiKey = \Kai\Banner\Api\Helper::API_KEY; | ||||||
|  | 
 | ||||||
|  |         foreach ($headers as $key => $value) { | ||||||
|  |             $key = strtolower($key); | ||||||
|  |             if ('api_key' === $key && $value === $apiKey) { | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         header('HTTP/1.1 401 Unauthorized'); | ||||||
|  |         header('Accept: application/json'); | ||||||
|  |         header('Content-Type: application/json'); | ||||||
|  |         die( | ||||||
|  |             json_encode(['message' => 'unauthorized']) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function responseOk(array $data) | ||||||
|  |     { | ||||||
|  |         header('HTTP/1.1 200 Ok'); | ||||||
|  |         header('Accept: application/json'); | ||||||
|  |         header('Content-Type: application/json'); | ||||||
|  |         die(json_encode($data)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function responseFail(array $data) | ||||||
|  |     { | ||||||
|  |         header('HTTP/1.1 400 Bad request'); | ||||||
|  |         header('Accept: application/json'); | ||||||
|  |         header('Content-Type: application/json'); | ||||||
|  |         die(json_encode($data)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function responseMethodFail() | ||||||
|  |     { | ||||||
|  |         header('HTTP/1.1 400 bad request'); | ||||||
|  |         header('Accept: application/json'); | ||||||
|  |         header('Content-Type: application/json'); | ||||||
|  |         die(json_encode([ | ||||||
|  |             'status' => false, | ||||||
|  |             'message' => 'Param ?method=... not exist!' | ||||||
|  |         ])); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getData() | ||||||
|  |     { | ||||||
|  |         $method = $_GET['method'] ?? null; | ||||||
|  | 
 | ||||||
|  |         if ($method === 'show') { | ||||||
|  |             $id = $_GET['id'] ?? 0; | ||||||
|  |             return $this->responseOk([ | ||||||
|  |                 'status' => true, | ||||||
|  |                 'data' => $this | ||||||
|  |                     ->kaiBannerCollection | ||||||
|  |                     ->getItemById($id) | ||||||
|  |                     ->getData() | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ($method === 'all') { | ||||||
|  |             return $this->responseOk([ | ||||||
|  |                 'status' => true, | ||||||
|  |                 'data' => $this | ||||||
|  |                     ->kaiBannerCollection | ||||||
|  |                     ->getData() | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ($method === 'delete') { | ||||||
|  |             $id = $_GET['id'] ?? 0; | ||||||
|  |             $model = $this->kaiBannerModel->setId($id); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 $this->kaiBannerResourceModel->delete($model); | ||||||
|  |                 return $this->responseOk([ | ||||||
|  |                     'status' => true, | ||||||
|  |                 ]); | ||||||
|  |             } catch (\Exception $ex) { | ||||||
|  |                 $this->kaiBannerResourceModel->rollBack(); | ||||||
|  |                 return $this->responseFail([ | ||||||
|  |                     'status' => false, | ||||||
|  |                     'message' => $ex->getMessage() | ||||||
|  |                 ]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this->responseMethodFail(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function postData() | ||||||
|  |     { | ||||||
|  |         $method = $_GET['method'] ?? null; | ||||||
|  |         parse_str( | ||||||
|  |             string: file_get_contents('php://input'), | ||||||
|  |             result: $payload | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         if ($method === 'create') { | ||||||
|  |             $model = $this->kaiBannerModel; | ||||||
|  |             try { | ||||||
|  |                 foreach ($payload as $key => $value) { | ||||||
|  |                     $model->setData($key, $value); | ||||||
|  |                 } | ||||||
|  |                 $this->kaiBannerResourceModel->save($model); | ||||||
|  | 
 | ||||||
|  |                 return $this->responseOk([ | ||||||
|  |                     'status' => true, | ||||||
|  |                     'data' => $this | ||||||
|  |                         ->kaiBannerCollection | ||||||
|  |                         ->getItemById($model->getId()) | ||||||
|  |                         ->getData() | ||||||
|  |                 ]); | ||||||
|  |             } catch (\Exception $ex) { | ||||||
|  |                 return $this->responseFail([ | ||||||
|  |                     'status' => false, | ||||||
|  |                     'message' => $ex->getMessage() | ||||||
|  |                 ]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ($method === 'update') { | ||||||
|  |             $id = $_GET['id'] ?? 0; | ||||||
|  |             $model = $this->kaiBannerModel->setId($id); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 foreach ($payload as $key => $value) { | ||||||
|  |                     $model->setData($key, $value); | ||||||
|  |                 } | ||||||
|  |                 $this->kaiBannerResourceModel->save($model); | ||||||
|  | 
 | ||||||
|  |                 return $this->responseOk([ | ||||||
|  |                     'status' => true, | ||||||
|  |                     'data' => $this | ||||||
|  |                     ->kaiBannerCollection | ||||||
|  |                     ->getItemById($model->getId()) | ||||||
|  |                     ->getData() | ||||||
|  |                 ]); | ||||||
|  |             } catch (\Exception $ex) { | ||||||
|  |                 return $this->responseFail([ | ||||||
|  |                     'status' => false, | ||||||
|  |                     'message' => $ex->getMessage() | ||||||
|  |                 ]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $this->responseMethodFail(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Banner\Api; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @api | ||||||
|  |  */ | ||||||
|  | interface BannerRepositoryInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * method: GET | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getData(); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * methot: POST | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function postData(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Banner\Api; | ||||||
|  | 
 | ||||||
|  | final class Helper { | ||||||
|  |     public const API_KEY = 'KAI_BANNER_@_123'; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,43 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Banner\Block\Adminhtml; | ||||||
|  | 
 | ||||||
|  | use Magento\Backend\Block\Template; | ||||||
|  | 
 | ||||||
|  | class Index extends Template | ||||||
|  | { | ||||||
|  |     protected $urlInterface; | ||||||
|  |     protected $kaiBanner; | ||||||
|  |     protected $kaiBannerCollection; | ||||||
|  |     protected $kaiBannerResourceModel; | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         \Magento\Backend\Block\Template\Context $context, | ||||||
|  |         \Magento\Backend\Model\UrlInterface $urlInterface, | ||||||
|  |         \Kai\Banner\Model\KaiBanner $kaiBanner, | ||||||
|  |         \Kai\Banner\Model\KaiBannerResourceModel $kaiBannerResourceModel, | ||||||
|  |         \Kai\Banner\Model\KaiBannerCollection $kaiBannerCollection, | ||||||
|  |         $data = [] | ||||||
|  |     ) | ||||||
|  |     { | ||||||
|  |         $this->urlInterface = $urlInterface; | ||||||
|  |         $this->kaiBanner = $kaiBanner; | ||||||
|  |         $this->kaiBannerResourceModel = $kaiBannerResourceModel; | ||||||
|  |         $this->kaiBannerCollection = $kaiBannerCollection; | ||||||
|  |         parent::__construct($context, $data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getSecretKey() | ||||||
|  |     { | ||||||
|  |         return $this->urlInterface->getSecretKey(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getApiKey() | ||||||
|  |     { | ||||||
|  |         return \Kai\Banner\Api\Helper::API_KEY; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getAll() | ||||||
|  |     { | ||||||
|  |         return $this->kaiBannerCollection->getData(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Banner\Controller\Adminhtml\Index; | ||||||
|  | 
 | ||||||
|  | use Magento\Backend\App\Action; | ||||||
|  | 
 | ||||||
|  | class Index extends Action | ||||||
|  | { | ||||||
|  |     protected $resultPageFactory = false; | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         \Magento\Backend\App\Action\Context $context, | ||||||
|  |         \Magento\Framework\View\Result\PageFactory $resultPageFactory | ||||||
|  |     ) { | ||||||
|  |         $this->resultPageFactory = $resultPageFactory; | ||||||
|  |         parent::__construct($context); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute() | ||||||
|  |     { | ||||||
|  |         $resultPage = $this->resultPageFactory->create(); | ||||||
|  |         $resultPage->getConfig()->getTitle()->prepend(__('Banner')); | ||||||
|  |         return $resultPage; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,36 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Banner\Model; | ||||||
|  | 
 | ||||||
|  | use Kai\Banner\Model\KaiBannerResourceModel; | ||||||
|  | use Magento\Backend\Model\Menu\Item\Factory; | ||||||
|  | use Magento\Framework\Model\AbstractModel; | ||||||
|  | use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; | ||||||
|  | use Magento\Framework\ObjectManagerInterface; | ||||||
|  | 
 | ||||||
|  | class KaiBanner extends AbstractModel | ||||||
|  | { | ||||||
|  |     public function _construct() | ||||||
|  |     { | ||||||
|  |         $this->_init( | ||||||
|  |             resourceModel: KaiBannerResourceModel::class | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | final class KaiBannerFactory extends Factory | ||||||
|  | { | ||||||
|  |     protected $objectManager; | ||||||
|  |     protected $instanceName; | ||||||
|  | 
 | ||||||
|  |     public function __construct(ObjectManagerInterface $objectManager, $instanceName = KaiBanner::class) | ||||||
|  |     { | ||||||
|  |         $this->objectManager = $objectManager; | ||||||
|  |         $this->instanceName = $instanceName; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function create(array $arguments = [], AbstractDb $resource = null) | ||||||
|  |     { | ||||||
|  |         return $this->objectManager->create($this->instanceName, $arguments, $resource); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Banner\Model; | ||||||
|  | 
 | ||||||
|  | use Kai\Banner\Model\KaiBanner; | ||||||
|  | use Kai\Banner\Model\KaiBannerResourceModel; | ||||||
|  | use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; | ||||||
|  | 
 | ||||||
|  | class KaiBannerCollection extends AbstractCollection | ||||||
|  | { | ||||||
|  |     public function _construct() | ||||||
|  |     { | ||||||
|  |         $this->_init( | ||||||
|  |             model: KaiBanner::class, | ||||||
|  |             resourceModel: KaiBannerResourceModel::class | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Banner\Model; | ||||||
|  | 
 | ||||||
|  | use Magento\Framework\Model\ResourceModel\Db\AbstractDb; | ||||||
|  | 
 | ||||||
|  | class KaiBannerResourceModel extends AbstractDb | ||||||
|  | { | ||||||
|  |     public function _construct() | ||||||
|  |     { | ||||||
|  |         $this->_init( | ||||||
|  |             mainTable:'kai_banner', | ||||||
|  |             idFieldName:'id' | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,64 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Banner\Model; | ||||||
|  | 
 | ||||||
|  | use Kai\Banner\Model\KaiBannerCollection; | ||||||
|  | use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource; | ||||||
|  | use Magento\Framework\DB\Ddl\Table; | ||||||
|  | 
 | ||||||
|  | class KaiBannerValues extends AbstractSource | ||||||
|  | { | ||||||
|  |     protected $_optionFactory; | ||||||
|  |     protected $collection; | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         KaiBannerCollection $collection | ||||||
|  |     ) { | ||||||
|  |         $this->collection = $collection; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getAllOptions() | ||||||
|  |     { | ||||||
|  |         $data = $this->collection->getData(); | ||||||
|  |         $options = [ | ||||||
|  |             [ | ||||||
|  |                 'label' => 'Select option!', | ||||||
|  |                 'value' => '', | ||||||
|  |             ] | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         foreach ($data as $record) { | ||||||
|  |             $options[] = [ | ||||||
|  |                 'label' => $record['id'], | ||||||
|  |                 'value' => $record['title'], | ||||||
|  |             ]; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         $this->_options = $options; | ||||||
|  |         return $options; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getOptionText($value) | ||||||
|  |     { | ||||||
|  |         foreach ($this->getAllOptions() as $option) { | ||||||
|  |             if ($option['value'] == $value) { | ||||||
|  |                 return $option['label']; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getFlatColumns() | ||||||
|  |     { | ||||||
|  |         $attributeCode = $this->getAttribute()->getAttributeCode(); | ||||||
|  |         return [ | ||||||
|  |             $attributeCode => [ | ||||||
|  |                 'unsigned' => false, | ||||||
|  |                 'default' => null, | ||||||
|  |                 'extra' => null, | ||||||
|  |                 'type' => Table::TYPE_INTEGER, | ||||||
|  |                 'nullable' => true, | ||||||
|  |                 'comment' => 'Kai Banner ' . $attributeCode . ' column', | ||||||
|  |             ], | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,36 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Banner\Model\Serialize\Serializer; | ||||||
|  | 
 | ||||||
|  | use Magento\Framework\Serialize\Serializer\Json as SerializerJson; | ||||||
|  | 
 | ||||||
|  | class Json extends SerializerJson | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @inheritDoc | ||||||
|  |      * @since 101.0.0 | ||||||
|  |      */ | ||||||
|  |     public function unserialize($string) | ||||||
|  |     { | ||||||
|  |         if ($string === null) { | ||||||
|  |             throw new \InvalidArgumentException( | ||||||
|  |                 'Unable to unserialize value. Error: Parameter must be a string type, null given.' | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $result = json_decode($string, true); | ||||||
|  | 
 | ||||||
|  |         if (json_last_error() !== JSON_ERROR_NONE) { | ||||||
|  |             parse_str($string, $result); | ||||||
|  |             if (is_array($result)) { | ||||||
|  |                 return $result; | ||||||
|  |             } else { | ||||||
|  |                 throw new \InvalidArgumentException( | ||||||
|  |                     $string . " - Unable to unserialize value. Error: " . json_last_error_msg() | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Banner\Setup; | ||||||
|  | 
 | ||||||
|  | use Magento\Catalog\Model\Product; | ||||||
|  | use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; | ||||||
|  | use Magento\Framework\Setup\ModuleContextInterface; | ||||||
|  | use Magento\Framework\Setup\ModuleDataSetupInterface; | ||||||
|  | use Magento\Framework\Setup\UpgradeDataInterface; | ||||||
|  | 
 | ||||||
|  | class UpgradeData implements UpgradeDataInterface | ||||||
|  | { | ||||||
|  |     protected $_eavSetupFactory; | ||||||
|  |     protected $_attributeRepositoryInterface; | ||||||
|  |     protected $_attributeSetupFactory; | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory, | ||||||
|  |         \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepositoryInterface, | ||||||
|  |         \Magento\Catalog\Setup\CategorySetupFactory $attributeSetupFactory | ||||||
|  |     ) { | ||||||
|  |         $this->_eavSetupFactory = $eavSetupFactory; | ||||||
|  |         $this->_attributeRepositoryInterface = $attributeRepositoryInterface; | ||||||
|  |         $this->_attributeSetupFactory = $attributeSetupFactory; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $this->_attributeRepositoryInterface->get(Product::ENTITY, 'kai_banner'); | ||||||
|  |         } catch (\Exception $ex) { | ||||||
|  | 
 | ||||||
|  |             $setup->startSetup(); | ||||||
|  |             $eavSetup = $this->_eavSetupFactory->create(['setup' => $setup]); | ||||||
|  |             $eavSetup->addAttribute( | ||||||
|  |                 Product::ENTITY, | ||||||
|  |                 'kai_banner', | ||||||
|  |                 [ | ||||||
|  |                     'input' => 'select', | ||||||
|  |                     'type' => 'varchar', | ||||||
|  |                     'label' => 'Banner', | ||||||
|  |                     'required' => false, | ||||||
|  |                     'visible' => true, | ||||||
|  |                     'user_defined' => true, | ||||||
|  |                     'searchable' => false, | ||||||
|  |                     'filterable' => false, | ||||||
|  |                     'comparable' => false, | ||||||
|  |                     'used_in_product_listing' => true, | ||||||
|  |                     'apply_to' => '', | ||||||
|  |                     'source' => \Kai\Banner\Model\KaiBannerValues::class, | ||||||
|  |                     'global' => ScopedAttributeInterface::SCOPE_GLOBAL, | ||||||
|  |                     'group' => 'General', | ||||||
|  |                 ] | ||||||
|  |             ); | ||||||
|  |             $setup->endSetup(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,94 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Banner\Setup; | ||||||
|  | 
 | ||||||
|  | use Magento\Framework\DB\Ddl\Table; | ||||||
|  | use Magento\Framework\Setup\ModuleContextInterface; | ||||||
|  | use Magento\Framework\Setup\SchemaSetupInterface; | ||||||
|  | use Magento\Framework\Setup\UpgradeSchemaInterface; | ||||||
|  | 
 | ||||||
|  | class UpgradeSchema implements UpgradeSchemaInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context) | ||||||
|  |     { | ||||||
|  |         $installer = $setup; | ||||||
|  |         $installer->startSetup(); | ||||||
|  | 
 | ||||||
|  |         $tableName = $installer->getTable('kai_banner'); | ||||||
|  | 
 | ||||||
|  |         if ($installer->tableExists($tableName)) { | ||||||
|  |             $installer->getConnection()->dropTable($tableName); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $table = $installer->getConnection() | ||||||
|  |             ->newTable($tableName) | ||||||
|  |             ->addColumn( | ||||||
|  |                 'id', | ||||||
|  |                 Table::TYPE_INTEGER, | ||||||
|  |                 null, | ||||||
|  |                 [ | ||||||
|  |                     'identity' => true, | ||||||
|  |                     'unsigned' => true, | ||||||
|  |                     'nullable' => false, | ||||||
|  |                     'primary' => true, | ||||||
|  |                 ], | ||||||
|  |                 'ID' | ||||||
|  |             ) | ||||||
|  |             ->addColumn( | ||||||
|  |                 'title', | ||||||
|  |                 Table::TYPE_TEXT, | ||||||
|  |                 null, | ||||||
|  |                 ['nullable' => false, 'default' => ''], | ||||||
|  |                 'Title' | ||||||
|  |             ) | ||||||
|  |             ->addColumn( | ||||||
|  |                 'html', | ||||||
|  |                 Table::TYPE_TEXT, | ||||||
|  |                 null, | ||||||
|  |                 ['nullable' => true, 'default' => ''], | ||||||
|  |                 'htmlentities($str)' | ||||||
|  |             ) | ||||||
|  |             ->addColumn( | ||||||
|  |                 'redirect', | ||||||
|  |                 Table::TYPE_TEXT, | ||||||
|  |                 null, | ||||||
|  |                 ['nullable' => true, 'default' => ''], | ||||||
|  |                 'URL redirect' | ||||||
|  |             ) | ||||||
|  |             ->addColumn( | ||||||
|  |                 'created_at', | ||||||
|  |                 Table::TYPE_TIMESTAMP, | ||||||
|  |                 null, | ||||||
|  |                 [ | ||||||
|  |                     'nullable' => true, | ||||||
|  |                     'default' => Table::TIMESTAMP_INIT, | ||||||
|  |                 ], | ||||||
|  |                 'Created At' | ||||||
|  |             ) | ||||||
|  |             ->addColumn( | ||||||
|  |                 'updated_at', | ||||||
|  |                 Table::TYPE_TIMESTAMP, | ||||||
|  |                 null, | ||||||
|  |                 [ | ||||||
|  |                     'nullable' => true, | ||||||
|  |                     'default' => Table::TIMESTAMP_INIT_UPDATE, | ||||||
|  |                 ], | ||||||
|  |                 'Updated At' | ||||||
|  |             ) | ||||||
|  |             ->addColumn( | ||||||
|  |                 'status', | ||||||
|  |                 Table::TYPE_SMALLINT, | ||||||
|  |                 null, | ||||||
|  |                 [ | ||||||
|  |                     'nullable' => false, | ||||||
|  |                     'default' => '0', | ||||||
|  |                 ], | ||||||
|  |                 'Status' | ||||||
|  |             )->setComment('Kai Banner Module'); | ||||||
|  |         $installer->getConnection()->createTable($table); | ||||||
|  |         $installer->endSetup(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,25 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <config | ||||||
|  |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |     xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd" | ||||||
|  | > | ||||||
|  |     <acl> | ||||||
|  |         <resources> | ||||||
|  |             <resource id="Magento_Backend::admin"> | ||||||
|  |                 <resource | ||||||
|  |                     id="Kai_Banner::parent" | ||||||
|  |                     title="Kai Banner Module" | ||||||
|  |                     translate="title" | ||||||
|  |                     sortOrder="10" | ||||||
|  |                 > | ||||||
|  |                     <resource | ||||||
|  |                         id="Kai_Banner::index" | ||||||
|  |                         title="Index" | ||||||
|  |                         translate="title" | ||||||
|  |                         sortOrder="10" | ||||||
|  |                     /> | ||||||
|  |                 </resource> | ||||||
|  |             </resource> | ||||||
|  |         </resources> | ||||||
|  |     </acl> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <config | ||||||
|  |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |     xsi:noNamespaceSchemaLocation="urn:magento:module:Kai_Banner:etc/menu.xsd" | ||||||
|  | > | ||||||
|  |     <menu> | ||||||
|  |         <add | ||||||
|  |             id="Kai_Banner::parent" | ||||||
|  |             title="Kai Module" | ||||||
|  |             module="Kai_Banner" | ||||||
|  |             sortOrder="1" | ||||||
|  |             resource="Magento_Backend::content" | ||||||
|  |             parent="Magento_Backend::content" | ||||||
|  |         /> | ||||||
|  | 
 | ||||||
|  |         <!-- Banner --> | ||||||
|  |         <add | ||||||
|  |             id="Kai_Banner::index" | ||||||
|  |             title="Kai Banner" | ||||||
|  |             module="Kai_Banner" | ||||||
|  |             sortOrder="1" | ||||||
|  |             action="kai_banner/index" | ||||||
|  |             resource="Kai_Banner::parent" | ||||||
|  |             parent="Kai_Banner::parent" | ||||||
|  |         /> | ||||||
|  |     </menu> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,11 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <config | ||||||
|  |     xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd" | ||||||
|  |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  | > | ||||||
|  |     <router id="admin"> | ||||||
|  |         <route id="kai_banner" frontName="kai_banner"> | ||||||
|  |             <module name="Kai_Banner" before="Magento_Backend" /> | ||||||
|  |         </route> | ||||||
|  |     </router> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> | ||||||
|  |     <!-- Repository --> | ||||||
|  |     <preference | ||||||
|  |         for="Kai\Banner\Api\BannerRepositoryInterface" | ||||||
|  |         type="Kai\Banner\Api\BannerRepository" | ||||||
|  |     /> | ||||||
|  |     <preference | ||||||
|  |         for="Magento\Framework\Serialize\Serializer\Json" | ||||||
|  |         type="Kai\Banner\Model\Serialize\Serializer\Json" | ||||||
|  |     /> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> | ||||||
|  |     <module name="Kai_Banner" setup_version="1.0.5"/> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd"> | ||||||
|  |     <route url="V1/banner" method="GET"> | ||||||
|  |         <service class="Kai\Banner\Api\BannerRepositoryInterface" method="getData"/> | ||||||
|  |         <resources> | ||||||
|  |             <resource ref="anonymous"/> | ||||||
|  |         </resources> | ||||||
|  |     </route> | ||||||
|  |     <route url="V1/banner" method="POST"> | ||||||
|  |         <service class="Kai\Banner\Api\BannerRepositoryInterface" method="postData"/> | ||||||
|  |         <resources> | ||||||
|  |             <resource ref="anonymous"/> | ||||||
|  |         </resources> | ||||||
|  |     </route> | ||||||
|  | </routes> | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | <?php | ||||||
|  | \Magento\Framework\Component\ComponentRegistrar::register( | ||||||
|  |     \Magento\Framework\Component\ComponentRegistrar::MODULE, | ||||||
|  |     'Kai_Banner', | ||||||
|  |     __DIR__ | ||||||
|  | ); | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <page | ||||||
|  |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |     xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" | ||||||
|  | > | ||||||
|  |     <body> | ||||||
|  |         <referenceContainer name="content"> | ||||||
|  |             <block | ||||||
|  |                 class="Kai\Banner\Block\Adminhtml\Index" | ||||||
|  |                 template="Kai_Banner::index.phtml" | ||||||
|  |             /> | ||||||
|  |         </referenceContainer> | ||||||
|  |     </body> | ||||||
|  | </page> | ||||||
|  | @ -0,0 +1,299 @@ | ||||||
|  | <?php | ||||||
|  | $theads = [ | ||||||
|  |     [ | ||||||
|  |         "label" => "ID", | ||||||
|  |         "name" => "id", | ||||||
|  |         "type" => "text", | ||||||
|  |         "hidden" => false, | ||||||
|  |         "disabled" => true, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |         "label" => "Title", | ||||||
|  |         "name" => "title", | ||||||
|  |         "type" => "text", | ||||||
|  |         "hidden" => false, | ||||||
|  |         "disabled" => false, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |         "label" => "HTML", | ||||||
|  |         "name" => "html", | ||||||
|  |         "type" => "textarea", | ||||||
|  |         "hidden" => false, | ||||||
|  |         "disabled" => false, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |         "label" => "Redirect", | ||||||
|  | 
 | ||||||
|  |         "name" => "redirect", | ||||||
|  |         "type" => "text", | ||||||
|  |         "hidden" => false, | ||||||
|  |         "disabled" => false, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |         "label" => "Created At", | ||||||
|  |         "name" => "created_at", | ||||||
|  |         "type" => "text", | ||||||
|  |         "hidden" => false, | ||||||
|  |         "disabled" => true, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |         "label" => "Updated At", | ||||||
|  |         "name" => "updated_at", | ||||||
|  |         "type" => "text", | ||||||
|  |         "hidden" => false, | ||||||
|  |         "disabled" => true, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |         "label" => "Status", | ||||||
|  |         "name" => "status", | ||||||
|  |         "type" => "text", | ||||||
|  |         "hidden" => false, | ||||||
|  |         "disabled" => true, | ||||||
|  |     ], | ||||||
|  |     [ | ||||||
|  |         "label" => "Operation", | ||||||
|  |         "type" => "text", | ||||||
|  |         "hidden" => true, | ||||||
|  |         "disabled" => true, | ||||||
|  |     ], | ||||||
|  | ]; | ||||||
|  | ?> | ||||||
|  | <head> | ||||||
|  |     <script src="https://cdn.tailwindcss.com"></script> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |     <div class="relative overflow-x-auto"> | ||||||
|  |         <caption class="px-6 flex items-start"> | ||||||
|  |             <button | ||||||
|  |                 data-action="add" | ||||||
|  |                 class="show-modal bg-green-700 text-white py-2 px-5 border-none" | ||||||
|  |             > | ||||||
|  |                 Add | ||||||
|  |             </button> | ||||||
|  |         </caption> | ||||||
|  |         <table | ||||||
|  |             class="w-ful text-left rtl:text-right text-gray-7000 dark:text-gray-400" | ||||||
|  |         > | ||||||
|  |             <thead | ||||||
|  |                 class="text-gray-700 uppercase bg-gray-700 dark:bg-gray-700 dark:text-gray-400" | ||||||
|  |             > | ||||||
|  |                 <tr> | ||||||
|  |                     <?php foreach ($theads as $thead): ?> | ||||||
|  |                     <th scope="col" class="px-6 py-3"><?=$thead['label'] ?></th> | ||||||
|  |                     <?php endforeach; ?> | ||||||
|  |                 </tr> | ||||||
|  |             </thead> | ||||||
|  |             <tbody> | ||||||
|  |                 <?php foreach ($block->getAll() as $row): ?> | ||||||
|  |                 <tr | ||||||
|  |                     class="bg-white border-b dark:bg-gray-800 dark:border-gray-700" | ||||||
|  |                     id="row-<?=$row['id'] ?>" | ||||||
|  |                 > | ||||||
|  |                     <th data-name="id" data-value="<?= $row['id'] ?>" class="px-6 py-4"><?=$row['id'] ?></th> | ||||||
|  |                     <td data-name="title" data-value="<?= $row['title'] ?>" class="px-6 py-4"> | ||||||
|  |                         <?=$row['title'] ?> | ||||||
|  |                     </td> | ||||||
|  |                     <td data-name="html" data-value="<?= htmlentities($row['html']) ?>" class="px-6 py-4"> | ||||||
|  |                         <code> | ||||||
|  |                             <?=html_entity_decode($row['html']) ?> | ||||||
|  |                         </code> | ||||||
|  |                     </td> | ||||||
|  |                     <td data-name="redirect" data-value="<?= $row['redirect'] ?>" class="px-6 py-4"> | ||||||
|  |                         <?=$row['redirect'] ?> | ||||||
|  |                     </td> | ||||||
|  |                     <td data-name="created_at" data-value="<?= $row['created_at'] ?>" class="px-6 py-4"> | ||||||
|  |                         <?=$row['created_at'] ?> | ||||||
|  |                     </td> | ||||||
|  |                     <td data-name="updated_at" data-value="<?= $row['updated_at'] ?>" class="px-6 py-4"> | ||||||
|  |                         <?=$row['updated_at'] ?> | ||||||
|  |                     </td> | ||||||
|  |                     <td data-name="status" data-value="<?= $row['status'] ?>" class="px-6 py-4"> | ||||||
|  |                         <?=$row['status'] ?> | ||||||
|  |                     </td> | ||||||
|  |                     <td class="px-6"> | ||||||
|  |                         <div class="flex items-end"> | ||||||
|  |                             <button | ||||||
|  |                                 data-action="edit" | ||||||
|  |                                 data-id="<?=$row['id'] ?>" | ||||||
|  |                                 class="show-modal bg-blue-700 text-white py-2 px-5 border-none" | ||||||
|  |                             > | ||||||
|  |                                 Edit | ||||||
|  |                             </button> | ||||||
|  |                             <button | ||||||
|  |                                 data-action="delete" | ||||||
|  |                                 data-id="<?=$row['id'] ?>" | ||||||
|  |                                 class="show-modal bg-red-700 text-white py-2 px-5 border-none" | ||||||
|  |                             > | ||||||
|  |                                 Delete | ||||||
|  |                             </button> | ||||||
|  |                         </div> | ||||||
|  |                     </td> | ||||||
|  |                 </tr> | ||||||
|  |                 <?php endforeach; ?> | ||||||
|  |             </tbody> | ||||||
|  |         </table> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <!-- Modal --> | ||||||
|  |     <form id="modal_form" class="w-full p-5" style="display: none"> | ||||||
|  |         <?php foreach ($theads as $thead): ?> | ||||||
|  |         <?php if (false === $thead['hidden']): ?> | ||||||
|  |         <div class="flex items-center justify-center mb-6"> | ||||||
|  |             <div class="md:w-1/3 min-w-[20%]"> | ||||||
|  |                 <label | ||||||
|  |                     class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" | ||||||
|  |                     ><?=$thead['label'] ?></label | ||||||
|  |                 > | ||||||
|  |             </div> | ||||||
|  |             <div class="md:w-2/3"> | ||||||
|  |                 <?php if ('text' === $thead['type']): ?> | ||||||
|  |                 <input class="appearance-none border-2 rounded w-full py-2 px-4 | ||||||
|  |                 text-gray-700 leading-tight focus:outline-none focus:bg-white | ||||||
|  |                 focus:border-purple-500" type="text" name="<?=$thead['name'] ?>" | ||||||
|  |                 <?=$thead['disabled'] ? 'disabled' : '' ?> | ||||||
|  |                 /> | ||||||
|  |                 <?php endif ?> | ||||||
|  |                 <?php if ('textarea' === $thead['type']): ?> | ||||||
|  |                 <textarea | ||||||
|  |                     rows="4" | ||||||
|  |                     class="appearance-none border-2 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500" | ||||||
|  |                     name="<?=$thead['name'] ?>" | ||||||
|  |                 ></textarea> | ||||||
|  |                 <?php endif ?> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <?php endif; ?> | ||||||
|  |         <?php endforeach; ?> | ||||||
|  |         <div class="flex items-center justify-center"> | ||||||
|  |             <div class="md:w-1/3 min-w-[20%]"></div> | ||||||
|  |             <div class="md:w-2/3"> | ||||||
|  |                 <button | ||||||
|  |                     class="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded" | ||||||
|  |                     type="submit" | ||||||
|  |                 > | ||||||
|  |                     Submit | ||||||
|  |                 </button> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </form> | ||||||
|  | 
 | ||||||
|  |     <script> | ||||||
|  |     const URL_API = location.origin + "/rest/V1/banner"; | ||||||
|  |     const MODAL_OPTION = { | ||||||
|  |         type: "popup", | ||||||
|  |         responsive: true, | ||||||
|  |         innerScroll: true, | ||||||
|  |         buttons: [{ | ||||||
|  |             class: "", | ||||||
|  |             click: function() { | ||||||
|  |                 this.closeModal(); | ||||||
|  |             }, | ||||||
|  |         }, ], | ||||||
|  |     }; | ||||||
|  |     require([ | ||||||
|  |         "jquery", | ||||||
|  |         "mage/translate", | ||||||
|  |         "uiComponent", | ||||||
|  |         "ko", | ||||||
|  |         "Magento_Ui/js/modal/alert", | ||||||
|  |         "Magento_Ui/js/modal/confirm", | ||||||
|  |         "Magento_Ui/js/modal/modal", | ||||||
|  |     ], function($, $t, Component, ko, alertModal, confirmModal, modal) { | ||||||
|  |         "use strict"; | ||||||
|  |         (function init() { | ||||||
|  |             $.ajaxSetup({ | ||||||
|  |                 contentType: "application/json;", | ||||||
|  |                 headers: { | ||||||
|  |                     API_KEY: "<?=$block->getApiKey() ?>", | ||||||
|  |                 }, | ||||||
|  |                 success: function(data) { | ||||||
|  |                     // do something before xhr | ||||||
|  |                 }, | ||||||
|  |                 fail: function(error) { | ||||||
|  |                     console.error(error) | ||||||
|  |                     alertModal({ | ||||||
|  |                         content: error.message, | ||||||
|  |                     }); | ||||||
|  |                 }, | ||||||
|  |             }); | ||||||
|  |         })($); | ||||||
|  |         $(document).ready(function($) { | ||||||
|  |             const MODAL = modal(MODAL_OPTION, $("#modal_form")); | ||||||
|  |             let action = ""; | ||||||
|  |             $(document).on("click", ".show-modal[data-action]", function() { | ||||||
|  |                 action = $(this).attr("data-action"); | ||||||
|  |                 if (action == "add") { | ||||||
|  |                     $("#modal_form")[0].reset(); | ||||||
|  |                     $("#modal_form").modal("openModal"); | ||||||
|  |                 } | ||||||
|  |                 if (action == "edit") { | ||||||
|  |                     const id = $(this).attr("data-id"); | ||||||
|  |                     $(`#row-${id} [data-name]`) | ||||||
|  |                         .each((i, el) => { | ||||||
|  |                             const name = $(el).attr('data-name'); | ||||||
|  |                             const value = $(el).attr('data-value'); | ||||||
|  |                             $(`#modal_form [name="${name}"]`)?.val(value); | ||||||
|  |                         }) | ||||||
|  | 
 | ||||||
|  |                     $("#modal_form").modal("openModal"); | ||||||
|  |                 } | ||||||
|  |                 if (action === 'delete') { | ||||||
|  |                     confirmModal({ | ||||||
|  |                         title: "Are you sure?", | ||||||
|  |                         // content: '', | ||||||
|  |                         actions: { | ||||||
|  |                             confirm: () => { | ||||||
|  |                                 $.get(URL_API + '?method=delete&id=' + $(this).attr('data-id')) | ||||||
|  |                                     .then(_ => window.location.reload()) | ||||||
|  |                             }, | ||||||
|  | 
 | ||||||
|  |                             cancel: () => { | ||||||
|  |                                 // do something choose "no" | ||||||
|  |                             }, | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |             $(document).on("submit", "#modal_form", function(e) { | ||||||
|  |                 e.preventDefault(); | ||||||
|  |                 if (action === "add") { | ||||||
|  |                     $.post(URL_API + "?method=create", $(this).serialize()) | ||||||
|  |                         .then((res) => { | ||||||
|  |                             res.status ? | ||||||
|  |                                 alertModal({ | ||||||
|  |                                     content: "Added new record!", | ||||||
|  |                                     actions: { | ||||||
|  |                                         always: () => window.location.reload() | ||||||
|  |                                     } | ||||||
|  |                                 }) : | ||||||
|  |                                 alertModal({ | ||||||
|  |                                     content: "Some errors: " + data.message, | ||||||
|  |                                 }); | ||||||
|  |                         }) | ||||||
|  |                         .then(() => $("#modal_form").modal("closeModal")); | ||||||
|  |                 } | ||||||
|  |                 if (action === "edit") { | ||||||
|  |                     const id = $(this).find("[name=id").val(); | ||||||
|  |                     $.post( | ||||||
|  |                             URL_API + "?method=update&id=" + id, | ||||||
|  |                             $("#modal_form").serialize() | ||||||
|  |                         ) | ||||||
|  |                         .then((res) => { | ||||||
|  |                             res.status ? | ||||||
|  |                                 alertModal({ | ||||||
|  |                                     content: "Edited new record!", | ||||||
|  |                                     actions: { | ||||||
|  |                                         always: () => window.location.reload() | ||||||
|  |                                     } | ||||||
|  |                                 }) : | ||||||
|  |                                 alertModal({ | ||||||
|  |                                     content: "Some errors: " + data.message, | ||||||
|  |                                 }); | ||||||
|  |                         }) | ||||||
|  |                         .then(() => $("#modal_form").modal("closeModal")); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | </script> | ||||||
|  | </body> | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | <!-- app/code/Vendor/Module/view/frontend/layout/default.xml --> | ||||||
|  | <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> | ||||||
|  |     <body> | ||||||
|  |         <referenceBlock name="catalog.topnav"> | ||||||
|  |             <block class="Magento\Framework\View\Element\Html\Link\Current" name="kai.banner.item"> | ||||||
|  |                 <arguments> | ||||||
|  |                     <argument name="label" xsi:type="string" translate="true">Kai - Banner</argument> | ||||||
|  |                     <argument name="path" xsi:type="string">kai/banner/index</argument> | ||||||
|  |                 </arguments> | ||||||
|  |             </block> | ||||||
|  |         </referenceBlock> | ||||||
|  |     </body> | ||||||
|  | </page> | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | <?php | ||||||
|  | namespace Vendor\Module\Controller\Index; | ||||||
|  | 
 | ||||||
|  | use Magento\Framework\App\Action\Action; | ||||||
|  | use Magento\Framework\App\Action\Context; | ||||||
|  | use Magento\Framework\View\Result\PageFactory; | ||||||
|  | 
 | ||||||
|  | class Index extends Action | ||||||
|  | { | ||||||
|  |     protected $resultPageFactory; | ||||||
|  | 
 | ||||||
|  |     public function __construct(Context $context, PageFactory $resultPageFactory) | ||||||
|  |     { | ||||||
|  |         parent::__construct($context); | ||||||
|  |         $this->resultPageFactory = $resultPageFactory; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute() | ||||||
|  |     { | ||||||
|  |         $resultPage = $this->resultPageFactory->create(); | ||||||
|  |         return $resultPage; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  | /** | ||||||
|  |  * module | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright © 2023 Kai. All rights reserved. | ||||||
|  |  */ | ||||||
|  | --> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> | ||||||
|  |     <module name="Kai_Helloworld" setup_version="1.0.0"> | ||||||
|  |     </module> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | <?php | ||||||
|  | \Magento\Framework\Component\ComponentRegistrar::register( | ||||||
|  |     \Magento\Framework\Component\ComponentRegistrar::MODULE, | ||||||
|  |     'Kai_Helloworld', | ||||||
|  |     __DIR__ | ||||||
|  | ); | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  | /** | ||||||
|  |  * routes | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | --> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> | ||||||
|  |     <router id="standard"> <!-- standard or admin --> | ||||||
|  |         <route id="hello" frontName="hello"> | ||||||
|  |             <module name="Kai_Helloworld" /> | ||||||
|  |         </route> | ||||||
|  |     </router> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> | ||||||
|  |     <body> | ||||||
|  |         <referenceContainer name="content"> | ||||||
|  |             <block class="Magento\Framework\View\Element\Template" name="kai_module.helloworld" template="Kai_Helloworld::module_index_index.phtml"/> | ||||||
|  |         </referenceContainer> | ||||||
|  |     </body> | ||||||
|  | </page> | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | <h1>Hello from Kai_Helloworld!</h1> | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Product\Block; | ||||||
|  | 
 | ||||||
|  | use Magento\Framework\Registry; | ||||||
|  | use Magento\Framework\View\Element\Template; | ||||||
|  | 
 | ||||||
|  | class Custom extends Template | ||||||
|  | { | ||||||
|  |     protected $registry; | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         \Magento\Framework\View\Element\Template\Context $context, | ||||||
|  |         Registry $registry, | ||||||
|  |         array $data = [] | ||||||
|  |     ) { | ||||||
|  |         parent::__construct($context, $data); | ||||||
|  |         $this->registry = $registry; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getCustomAttribute() | ||||||
|  |     { | ||||||
|  |         $product = $this->registry->registry('current_product'); | ||||||
|  |         // Replace 'your_custom_attribute_code' with your actual attribute code
 | ||||||
|  |         return $product->getData('kai_attribute'); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,59 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Product\Block\Product\View; | ||||||
|  | 
 | ||||||
|  | use Magento\Catalog\Block\Product\View\Description; | ||||||
|  | 
 | ||||||
|  | class CustomTab extends Description | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     public function headerHTML() | ||||||
|  |     { | ||||||
|  |         return $this->getLayout() | ||||||
|  |             ->createBlock("Magento\Framework\View\Element\Template") | ||||||
|  |             ->setTemplate("Kai_Product::product/view/header.phtml") | ||||||
|  |             ->toHtml(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getProductName() | ||||||
|  |     { | ||||||
|  |         $product = $this->getProduct(); | ||||||
|  |         if ($product) { | ||||||
|  |             $product->getName(); | ||||||
|  |         } | ||||||
|  |         return $product; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getImage() | ||||||
|  |     { | ||||||
|  |         $product = $this->getProduct(); | ||||||
|  | 
 | ||||||
|  |         if ($product) { | ||||||
|  |             $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); | ||||||
|  |             $helperImport = $objectManager->get('\Magento\Catalog\Helper\Image'); | ||||||
|  | 
 | ||||||
|  |             $imageUrl = $helperImport->init($product, 'product_page_image_small') | ||||||
|  |                 ->setImageFile($product->getSmallImage()) // image,small_image,thumbnail
 | ||||||
|  |                 ->resize(380) | ||||||
|  |                 ->getUrl(); | ||||||
|  |             return $imageUrl; | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getPrice() | ||||||
|  |     { | ||||||
|  |         $product = $this->getProduct(); | ||||||
|  |         if ($product) { | ||||||
|  |             return $product->getFormattedPrice(); | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getCustomAttribute() | ||||||
|  |     { | ||||||
|  |         $product = $this->getProduct(); | ||||||
|  |         // Replace 'your_custom_attribute_code' with your actual attribute code
 | ||||||
|  |         return $product->getData('kai_attribute'); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Product\Controller\Index; | ||||||
|  | 
 | ||||||
|  | use Magento\Framework\App\Action\Action; | ||||||
|  | use Magento\Framework\App\Action\Context; | ||||||
|  | use Magento\Framework\View\Result\PageFactory; | ||||||
|  | 
 | ||||||
|  | class Index extends Action | ||||||
|  | { | ||||||
|  |     protected $resultPageFactory; | ||||||
|  | 
 | ||||||
|  |     public function __construct(Context $context, PageFactory $resultPageFactory) | ||||||
|  |     { | ||||||
|  |         parent::__construct($context); | ||||||
|  |         $this->resultPageFactory = $resultPageFactory; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function execute() | ||||||
|  |     { | ||||||
|  |         $resultPage = $this->resultPageFactory->create(); | ||||||
|  |         return $resultPage; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,52 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Kai\Product\Setup; | ||||||
|  | 
 | ||||||
|  | use Magento\Catalog\Model\Product; | ||||||
|  | use Magento\Catalog\Setup\CategorySetupFactory; | ||||||
|  | use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; | ||||||
|  | use Magento\Eav\Setup\EavSetupFactory; | ||||||
|  | use Magento\Framework\Setup\InstallDataInterface; | ||||||
|  | use Magento\Framework\Setup\ModuleContextInterface; | ||||||
|  | use Magento\Framework\Setup\ModuleDataSetupInterface; | ||||||
|  | 
 | ||||||
|  | class InstallData implements InstallDataInterface | ||||||
|  | { | ||||||
|  |     protected $eavSetupFactory; | ||||||
|  |     protected $attributeSetupFactory; | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory, | ||||||
|  |         \Magento\Catalog\Setup\CategorySetupFactory $attributeSetupFactory) | ||||||
|  |     { | ||||||
|  |         $this->eavSetupFactory = $eavSetupFactory; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) | ||||||
|  |     { | ||||||
|  |         $setup->startSetup(); | ||||||
|  | 
 | ||||||
|  |         $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); | ||||||
|  |         $eavSetup->addAttribute( | ||||||
|  |             Product::ENTITY, | ||||||
|  |             'kai_attribute', | ||||||
|  |             [ | ||||||
|  |                 'type' => 'varchar', | ||||||
|  |                 'label' => 'Kai Attribute', | ||||||
|  |                 'input' => 'text', | ||||||
|  |                 'required' => false, | ||||||
|  |                 'visible' => true, | ||||||
|  |                 'user_defined' => true, | ||||||
|  |                 'searchable' => false, | ||||||
|  |                 'filterable' => false, | ||||||
|  |                 'comparable' => false, | ||||||
|  |                 'used_in_product_listing' => true, | ||||||
|  |                 'apply_to' => '', | ||||||
|  |                 'global' => ScopedAttributeInterface::SCOPE_GLOBAL, | ||||||
|  |                 'group' => 'General', | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         $setup->endSetup(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,10 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |         xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/catalog_attributes.xsd"> | ||||||
|  |     <group name="quote_item"> | ||||||
|  |         <attribute name="kai_attribute"/> | ||||||
|  |     </group> | ||||||
|  |     <group name="wishlist_item"> | ||||||
|  |         <attribute name="kai_attribute" /> | ||||||
|  |     </group> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> | ||||||
|  |     <router id="standard"> | ||||||
|  |         <route id="kai_product" frontName="kai_product"> | ||||||
|  |             <module name="Kai_Product"/> | ||||||
|  |         </route> | ||||||
|  |     </router> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  | /** | ||||||
|  |  * module | ||||||
|  |  * | ||||||
|  |  * @copyright Copyright © 2023 Kai. All rights reserved. | ||||||
|  |  */ | ||||||
|  | --> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> | ||||||
|  |     <module name="Kai_Product" setup_version="1.0.0"> | ||||||
|  |     </module> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | <?php | ||||||
|  | \Magento\Framework\Component\ComponentRegistrar::register( | ||||||
|  |     \Magento\Framework\Component\ComponentRegistrar::MODULE, | ||||||
|  |     'Kai_Product', | ||||||
|  |     __DIR__ | ||||||
|  | ); | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- | ||||||
|  | /** | ||||||
|  |  * routes | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | --> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> | ||||||
|  |     <router id="standard"> <!-- standard or admin --> | ||||||
|  |         <route id="kai_product" frontName="Kai_Product"> | ||||||
|  |             <module name="Kai_Product" /> | ||||||
|  |         </route> | ||||||
|  |     </router> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,20 @@ | ||||||
|  | <!-- app/code/Namespace/ModuleName/view/frontend/layout/catalog_product_view.xml --> | ||||||
|  | <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> | ||||||
|  |     <body> | ||||||
|  |         <referenceBlock name="product.info.details"> | ||||||
|  |             <block class="Kai\Product\Block\Product\View\CustomTab" name="custom.tab" template="Kai_Product::product/view/custom_tab.phtml" group="detailed_info"> | ||||||
|  |                 <arguments> | ||||||
|  |                     <argument translate="true" name="title" xsi:type="string"> | ||||||
|  |                         🛒🛒 Kai Tab | ||||||
|  |                     </argument> | ||||||
|  |                 </arguments> | ||||||
|  |             </block> | ||||||
|  |         </referenceBlock> | ||||||
|  |         <referenceContainer name="content"> | ||||||
|  |             <referenceBlock name="product.info.main"> | ||||||
|  |                 <!-- Add your custom block here --> | ||||||
|  |                 <block class="Kai\Product\Block\Custom" name="custom.block" template="Kai_Product::product/view/custom_attribute.phtml" after="product.info.price"/> | ||||||
|  |             </referenceBlock> | ||||||
|  |         </referenceContainer> | ||||||
|  |     </body> | ||||||
|  | </page> | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> | ||||||
|  |     <body> | ||||||
|  |         <referenceContainer name="content"> | ||||||
|  |             <block class="Magento\Framework\View\Element\Template" name="kai_module.product" template="Kai_Product::sample.phtml"/> | ||||||
|  |         </referenceContainer> | ||||||
|  |     </body> | ||||||
|  | </page> | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | 
 | ||||||
|  | <?php if ($block->getCustomAttribute()): ?> | ||||||
|  |     <div class="custom-attribute"> | ||||||
|  |         <strong><?= $block->escapeHtml(__('Custom Attribute Label hello')) ?>:</strong> | ||||||
|  |         <?= $block->escapeHtml($block->getCustomAttribute()) ?> | ||||||
|  |     </div> | ||||||
|  | <?php endif; ?> | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | <?= $block->headerHTML() ?> | ||||||
|  | 
 | ||||||
|  | <main class="kai_product"> | ||||||
|  |     <div class="card"> | ||||||
|  |         <div class="card__img"> | ||||||
|  |             <picture> | ||||||
|  |                 <img src="<?= $block->getImage() ?>" alt="<?= $block->getProduct()->getName() ?>"> | ||||||
|  |             </picture> | ||||||
|  |         </div> | ||||||
|  |         <div class="card__content"> | ||||||
|  |             <h1 class="card__title"><?= $block->getProduct()->getName() ?></h1> | ||||||
|  |             <p class="card__desc"><?= $block->getCustomAttribute() ?></p> | ||||||
|  |             <div class="card__price"> | ||||||
|  |                 <h1><?= $block->getPrice() ?></h1> | ||||||
|  |             </div> | ||||||
|  |             <button class="card__btn"> | ||||||
|  |                 <img src="https://rvs-product-preview-card-component.vercel.app/images/icon-cart.svg" alt=""> | ||||||
|  |                 Detail | ||||||
|  |             </button> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </main> | ||||||
|  | @ -0,0 +1,148 @@ | ||||||
|  | <style> | ||||||
|  |     :root { | ||||||
|  |         --dark-cyan: hsl(158, 36%, 37%); | ||||||
|  |         --cream: hsl(30, 38%, 92%); | ||||||
|  |         --very-dark-blue: hsl(157, 30%, 24%); | ||||||
|  |         --dark-grayish-blue: hsl(228, 12%, 48%); | ||||||
|  |         --white: hsl(0, 0%, 100%); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product * { | ||||||
|  |         margin: 0; | ||||||
|  |         padding: 0; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |         display: flex; | ||||||
|  |         justify-content: center; | ||||||
|  |         align-items: center; | ||||||
|  |         font-family: 'Montserrat', sans-serif; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card { | ||||||
|  |         width: 600px; | ||||||
|  |         display: flex; | ||||||
|  |         box-shadow: 1px 3px 3px #ccc; | ||||||
|  |         border-radius: 12px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__img { | ||||||
|  |         background-color: var(--white); | ||||||
|  |         border-top-left-radius: 12px; | ||||||
|  |         border-bottom-left-radius: 12px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content { | ||||||
|  |         background-color: var(--cream); | ||||||
|  |         border-top-right-radius: 12px; | ||||||
|  |         border-bottom-right-radius: 12px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__img, | ||||||
|  |     .kai_product .card .card__content { | ||||||
|  |         width: 50%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__img picture { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |         display: block; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__img picture img { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |         border-radius: 12px 0px 0px 12px; | ||||||
|  |         object-fit: cover; | ||||||
|  |         background-color: beige; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content { | ||||||
|  |         padding: 30px; | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         row-gap: 18px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__tag { | ||||||
|  |         text-transform: uppercase; | ||||||
|  |         letter-spacing: 3px; | ||||||
|  |         font-size: 14px; | ||||||
|  |         color: var(--dark-grayish-blue); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__title { | ||||||
|  |         font-family: 'Fraunces', serif; | ||||||
|  |         text-transform: capitalize; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__desc { | ||||||
|  |         font-size: 14px; | ||||||
|  |         color: var(--dark-grayish-blue); | ||||||
|  |         line-height: 24px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__price { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         column-gap: 20px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__price h1 { | ||||||
|  |         color: var(--dark-cyan); | ||||||
|  |         font-family: 'Fraunces', serif; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__price s { | ||||||
|  |         font-size: 14px; | ||||||
|  |         color: var(--dark-grayish-blue); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__btn { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         column-gap: 10px; | ||||||
|  |         background-color: var(--dark-cyan); | ||||||
|  |         padding: 14px; | ||||||
|  |         outline: none; | ||||||
|  |         border: 0; | ||||||
|  |         border-radius: 10px; | ||||||
|  |         color: var(--white); | ||||||
|  |         font-weight: 700; | ||||||
|  |         font-size: 16px; | ||||||
|  |         cursor: pointer; | ||||||
|  |         transition: background 200ms linear; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .kai_product .card .card__content .card__btn:hover { | ||||||
|  |         background-color: var(--very-dark-blue); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @media (max-width: 600px) { | ||||||
|  |         .kai_product { | ||||||
|  |             padding: 20px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .kai_product .card { | ||||||
|  |             flex-direction: column; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .kai_product .card .card__img, | ||||||
|  |         .kai_product .card .card__content { | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .kai_product .card .card__img picture img { | ||||||
|  |             border-radius: 12px 12px 0px 0px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .kai_product .card .card__content { | ||||||
|  |             padding: 20px; | ||||||
|  |             row-gap: 16px; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | </style> | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | <h1>Hello Product by Kai!</h1> | ||||||
|  | @ -0,0 +1,10 @@ | ||||||
|  | <?php | ||||||
|  | namespace Kai\Widget\Block\Widget; | ||||||
|  | 
 | ||||||
|  | use Magento\Framework\View\Element\Template; | ||||||
|  | use Magento\Widget\Block\BlockInterface; | ||||||
|  | 
 | ||||||
|  | class MyWidget extends Template implements BlockInterface | ||||||
|  | { | ||||||
|  |     protected $_template = 'mywidget.phtml'; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> | ||||||
|  |     <module name="Kai_Widget" setup_version="1.0.0"/> | ||||||
|  | </config> | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | <?xml version="1.0"?> | ||||||
|  | <widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd"> | ||||||
|  |     <widget id="kai_widget_mywidget" class="Kai\Widget\Block\Widget\MyWidget"> | ||||||
|  |         <label translate="true">My Custom Widget Of Kai</label> | ||||||
|  |         <description translate="true">Add widget.</description> | ||||||
|  |         <parameters> | ||||||
|  |             <parameter name="kai_widget__parameter_1" xsi:type="text" required="true" visible="true"> | ||||||
|  |                 <label translate="true">Parameter 1</label> | ||||||
|  |                 <description translate="true">Description of the parameter 1.</description> | ||||||
|  |             </parameter> | ||||||
|  |         </parameters> | ||||||
|  |     </widget> | ||||||
|  | </widgets> | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | <?php | ||||||
|  | \Magento\Framework\Component\ComponentRegistrar::register( | ||||||
|  |     \Magento\Framework\Component\ComponentRegistrar::MODULE, | ||||||
|  |     'Kai_Widget', | ||||||
|  |     __DIR__ | ||||||
|  | ); | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | <div> | ||||||
|  |     <!-- Your widget content goes here --> | ||||||
|  |     <p><strong>Kai Widget</strong> Hello, I am a custom widget!</p> | ||||||
|  | </div> | ||||||
|  | @ -0,0 +1,11 @@ | ||||||
|  | <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> | ||||||
|  |     <body> | ||||||
|  |         <referenceContainer name="content"> | ||||||
|  |             <block class="Magento\Widget\Block\BlockInterface" name="kai__widget_custom" template="mywidget.phtml"> | ||||||
|  |                 <arguments> | ||||||
|  |                     <argument name="widget_type" xsi:type="string">vendor_module_mywidget</argument> | ||||||
|  |                 </arguments> | ||||||
|  |             </block> | ||||||
|  |         </referenceContainer> | ||||||
|  |     </body> | ||||||
|  | </page> | ||||||
		Loading…
	
		Reference in New Issue