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