{"id":26682969,"url":"https://github.com/dark-kitt/wordpress-theme-vue","last_synced_at":"2025-03-26T08:28:45.859Z","repository":{"id":225293834,"uuid":"765053333","full_name":"dark-kitt/wordpress-theme-vue","owner":"dark-kitt","description":"A base Vue.js theme for WordPress.","archived":false,"fork":false,"pushed_at":"2024-04-29T07:43:17.000Z","size":710,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-09T23:41:00.741Z","etag":null,"topics":["typescript","typescript5","vue","vue3","webpack","webpack5","wordpress","wordpress6"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc-by-sa-4.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dark-kitt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-29T07:38:00.000Z","updated_at":"2024-04-29T07:43:06.000Z","dependencies_parsed_at":"2024-04-27T06:41:47.721Z","dependency_job_id":null,"html_url":"https://github.com/dark-kitt/wordpress-theme-vue","commit_stats":null,"previous_names":["dark-kitt/wordpress-theme-vue"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dark-kitt%2Fwordpress-theme-vue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dark-kitt%2Fwordpress-theme-vue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dark-kitt%2Fwordpress-theme-vue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dark-kitt%2Fwordpress-theme-vue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dark-kitt","download_url":"https://codeload.github.com/dark-kitt/wordpress-theme-vue/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245617910,"owners_count":20644896,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["typescript","typescript5","vue","vue3","webpack","webpack5","wordpress","wordpress6"],"created_at":"2025-03-26T08:28:45.267Z","updated_at":"2025-03-26T08:28:45.851Z","avatar_url":"https://github.com/dark-kitt.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WordPress - Vue 3 / TypeScript 5 / Webpack 5\nProject: [Part 1](https://github.com/dark-kitt/wordpress-boilerplate/tree/main), [Part 2](https://github.com/dark-kitt/wordpress-theme-configuration), [**Part 3**](https://github.com/dark-kitt/wordpress-theme-vue)\n\n---\n\n## Introduction\n\nThis is an example **Vue/TypeScript** project bundled with Webpack, based on [**Part 1**](https://github.com/dark-kitt/wordpress-boilerplate/tree/main) and [**Part 2**](https://github.com/dark-kitt/wordpress-theme-configuration) of the WordPress Boilerplate, which can be used to create a custom WordPress theme.\n\nYou can work with the **WordPress** backend system in two different ways. The first way would be to separate both systems from each other so that you have a **headless backend** with an unattached front-end system. The second way would be to use both systems together for an \"[**Islands Architecture**](https://www.patterns.dev/vanilla/islands-architecture)\" so that you are still able to use the **PHP** files from WordPress and **hydrate dynamic Vue** components inside of your DOM structure.\n\nIn my case, I used the second option and configured all the necessary stuff to make it usable for the \"[**Islands Architecture**](https://www.patterns.dev/vanilla/islands-architecture)\", but it's easy to modify the project to handle the first way and separate both systems. Just install the [HtmlWebpackPlugin](https://webpack.js.org/plugins/html-webpack-plugin/), and a template engine like [Handlebars](https://handlebarsjs.com/) to render the output. Afterward, it's just necessary to modify the Webpack and the Apache configuration.\n\n### Requirements\n\n* [Yarn: ^1.*](https://yarnpkg.com/) || [npm: 10.*](https://npmjs.com/)\n\n## Installation\n```shell\ncomposer require dark-kitt/wordpress-theme-vue\n```\n\nIf you have a specific path to your `/themes` directory, please add the following lines to your composer.json file.\n```json\n\"extra\": {\n  \"installer-paths\": {\n    \"path/to/themes/{$name}/\": [\n      \"type:wordpress-theme\"\n    ]\n  },\n  \"wordpress-install-dir\": \"path/to/wordpress\"\n},\n```\n\n**common composer cmds**\n```shell\ncomposer install\ncomposer update\n# package control\ncomposer require verdor/package\ncomposer remove verdor/package\n\ncomposer clear-cache\ncomposer show -i # installed packages\n```\n\n\n## Quick start\n\nInstall all necessary node modules.\n```shell\nyarn || npm i\n```\n\nFor development mode.\n```shell\nyarn dev || npm run dev\n```\n\nFor production mode.\n```shell\nyarn prod || npm run prod\n```\n\nAs described before I create only the output for the \"[**Islands Architecture**](https://www.patterns.dev/vanilla/islands-architecture)\", which means that you only see the JS, the CSS, and the necessary assets files inside of the (`/www`) output directory. So, the output must be included with PHP, e.g. by WordPress with [**wp_enqueue_script**](https://developer.wordpress.org/reference/functions/wp_enqueue_script/).\n\n---\n\n# Getting started!\n\nI guess the best way to understand the project is to create an example project together. The following instructions are based on a macOS system, but it could be possible, with some troubleshooting, that it will also work on Windows.\n\nAs always, let's create a folder and change the directory.\n```shell\nmkdir example \u0026\u0026 cd example\n```\n## Set up the environment\n\nKeep it simple as it is. Go to [**Part 1**](https://github.com/dark-kitt/wordpress-boilerplate/tree/main) of the WordPress Boilerplate download the project as ZIP, and open and copy-paste the composer.json file in your project root directory (`/example`). If you have a GitHub account and want to fetch the file by **curl** you can use the following command.\n\n#### composer.json\n```shell\ncurl --header \"PRIVATE-TOKEN: \u003cgithub_access_token\u003e\" \"https://raw.githubusercontent.com/dark-kitt/wordpress-boilerplate/main/composer.json\" \u003e composer.json\n```\n\nOr save your private access token in a curl header file, e.g. `~/.curl/github`, and include your specific header in your command.\n```text\n# ~/.curl/github\nPRIVATE-TOKEN: \u003cgithub_access_token\u003e\n```\n```shell\ncurl -H @\"$HOME/.curl/github\" \"https://raw.githubusercontent.com/dark-kitt/wordpress-boilerplate/main/composer.json\" \u003e composer.json\n```\n\n### Composer\nLet's continue. If you have an ACF Pro key, please add it manually inside of the **composer.json** file [25](replace `\u003c\u003cACF_KEY\u003e\u003e` with your key) and call **`composer update`**. Otherwise, we will remove ACF Pro and get forward. Let's keep it quickly and remove ACF Pro. To do so, call the following command.\n```shell\ncomposer config --unset repositories.advanced-custom-fields/advanced-custom-fields-pro \u0026\u0026 composer remove advanced-custom-fields/advanced-custom-fields-pro\n```\n\nNow, your folder/file structure should be like this.\n```text\n/example\n├── .env\n├── composer.json\n├── composer.lock\n├── /vendor\n├── ├── /...\n├── /web\n├── ├── /...\n```\n\n### Docker\n\nIn the next step, we need a local server. Let's work with [Docker](https://www.docker.com/products/docker-desktop/). If you don't have Docker you can download it [here](https://www.docker.com/products/docker-desktop/). We need only 3 files to set up the environment for Docker. Please, copy and paste the following snippets and create each file in the root directory (`/example`) of our new project.\n\n#### compose.yml\n```yml\nversion: \"3.9\"\nservices:\n  webserver:\n    container_name: wp-webserver\n    build:\n      context: .\n      dockerfile: Dockerfile\n    ports:\n      - 80:80\n    volumes:\n      - ./web:/var/www/html/web\n    depends_on:\n      - mysql-db\n    environment:\n      XDEBUG_CONFIG: remote_host=host.docker.internal\n\n  mysql-db:\n    container_name: wp-mysql\n    image: mysql:8.0\n    environment:\n      MYSQL_ROOT_PASSWORD: ro_password\n      MYSQL_USER: db_user\n      MYSQL_PASSWORD: db_password\n    ports:\n      - \"3306:3306\"\n```\n\n#### Dockerfile\n```Dockerfile\n# Use an official PHP runtime\nFROM php:8.2-apache\n# Install necessary packages\nRUN apt-get update \u0026\u0026 apt-get install -y \\\n  vim \\\n  iputils-ping \\\n  libzip-dev \\\n  zip \\\n  libpng-dev \\\n  libicu-dev \\\n  libmagickwand-dev\nRUN pecl install imagick\n# Install any extensions you need\nRUN docker-php-ext-install mysqli pdo pdo_mysql zip gd exif intl\n# Enable any extensions you need\nRUN docker-php-ext-enable imagick\n# Set the working directory to /var/www/html\nWORKDIR /var/www/html\n# Copy the required source code in the container at /var/www/html\nCOPY --chown=www-data:www-data --chmod=755 ./web ./web\nCOPY --chown=root:root --chmod=755 ./vendor ./vendor\nCOPY --chown=root:root --chmod=755 ./.env ./.env\n# --- APACHE | set up ---\n# Enable APACHE modules\nRUN a2enmod rewrite \u0026\u0026 a2enmod ssl \u0026\u0026 a2enmod socache_shmcb\n# Copy new vhosts config file into the root dir\nCOPY --chown=root:root --chmod=711 ./vhosts.conf ./vhosts.conf\n# Insert custom vhosts file\nRUN echo \"Include /var/www/html/vhosts.conf\" \u003e\u003e /etc/apache2/sites-available/vhosts.conf\n# Disable old default config file\nRUN a2dissite 000-default.conf\n# Enable new config file\nRUN a2ensite vhosts.conf\n# Docker PHP-APACHE container logs =\u003e docker logs wp-webserver\n# Set the 'ServerName' directive globally to suppress this message\n# NOTE: https://stackoverflow.com/questions/48868357/docker-php-apache-container-set-the-servername-directive-globally\nRUN echo \"ServerName localhost\" \u003e\u003e /etc/apache2/apache2.conf\nCMD [\"/usr/sbin/apache2ctl\", \"-D\", \"FOREGROUND\"]\n# Describe which ports your application is listening on\nEXPOSE 80\n# Get the Xdebug extension\nRUN pecl install xdebug \\\n  # Enable the installed Xdebug\n  \u0026\u0026 docker-php-ext-enable xdebug\n```\n\n#### vhosts.conf\n```xml\n\u003cVirtualHost *:80\u003e\n  ServerName api.example.kitt\n  ServerAlias www.api.example.kitt\n  ServerAdmin webmaster@localhost\n\n  DocumentRoot /var/www/html/web\n  \u003cDirectory /var/www/html/web\u003e\n    Options Indexes FollowSymlinks\n    AllowOverride All\n    Require all granted\n  \u003c/Directory\u003e\n\n  # deny the access for the theme config files (.env)\n  \u003cDirectory  /var/www/html/web/app/themes/example/config\u003e\n    Order deny,allow\n    Deny from all\n  \u003c/Directory\u003e\n\n  ErrorLog ${APACHE_LOG_DIR}/error.log\n  CustomLog ${APACHE_LOG_DIR}/access.log combined\n\u003c/VirtualHost\u003e\n\n\u003cVirtualHost *:80\u003e\n  ServerName example.kitt\n  ServerAlias www.example.kitt\n  ServerAdmin webmaster@localhost\n\n  DocumentRoot /var/www/html/web/app/themes/example\n  \u003cDirectory /var/www/html/web/app/themes/example\u003e\n    Options Indexes FollowSymlinks\n    AllowOverride All\n    Require all granted\n  \u003c/Directory\u003e\n\n  # deny the access for the theme config files (.env)\n  \u003cDirectory  /var/www/html/web/app/themes/example/config\u003e\n    Order deny,allow\n    Deny from all\n  \u003c/Directory\u003e\n\n  ErrorLog ${APACHE_LOG_DIR}/error.log\n  CustomLog ${APACHE_LOG_DIR}/access.log combined\n\u003c/VirtualHost\u003e\n```\n\nAs you can see we deny the access for the `./web/app/themes/example/config` directory in the **vhosts.conf** file. This is important because we need a save area to configure our front-end project. But there is also another way to do it. If you don't prefer to extend your Apache `vhosts.conf` file, you can also add a `.htaccess` file that includes `Deny from all` inside of the `./web/app/themes/example/config` directory.\n\nAfterward, your folder/file structure should look like this.\n```text\n/example\n├── .env\n├── compose.yml\n├── composer.json\n├── composer.lock\n├── Dockerfile\n├── /vendor\n├── ├── /...\n├── vhosts.conf\n├── /web\n├── ├── /...\n```\n\n⚠️ **Necessary local configuration to resolve the custom domain.**\n\nNext, we need to add our local domain to our local hosts file to resolve the custom local domain in our browser. For this, you need to add the localhost IP (`127.0.0.1`) to your `/etc/hosts` file on your machine.\n\nOpen a new terminal window and call the following command.\n```shell\nsudo vim /etc/hosts\n```\n\nEnter your machine password and open the hosts file. Add at the end of the file the following line.\n```shell\n# docker\n127.0.0.1       example.kitt api.example.kitt\n```\n\n### MySQL\n\nBefore we can go ahead and configure the backend system, it is necessary to set the permissions for our database user. Open/Start your (downloaded) Docker application and call `docker compose up` in a terminal window.\n```shell\ndocker compose up\n```\nAfter all necessary packages are installed and the containers are running, open another terminal window and connect to the MySQL container.\n```shell\ndocker exec -it wp-mysql bash\n```\nLog in as root user. The password is defined in the **compose.yml** file, in our case it is `ro_password`.\n```shell\nmysql -u root -p\n```\nNow, set the privileges for the `db_user`.\n```shell\nGRANT ALL PRIVILEGES ON *.* TO 'db_user'@'%' WITH GRANT OPTION;\n```\nFlush the privileges.\n```shell\nFLUSH PRIVILEGES;\n```\nLogout.\n```shell\nquit\n```\n\nCancel the connection to the MySQL container by pressing `ctrl + P` and `ctrl + Q`. Close the new terminal window so that we have only one window again, where the containers are running.\n\n## Configure WordPress\n\nFinally, we can start to configure the WordPress backend system and dive into the interesting part to start working with our new custom WordPress theme. But before we start and try to access the `api.example.kitt` domain to open the backend system, we will go one step back. Stop the running containers with `ctrl + C` inside of our terminal window.\n\nAfter the containers are stopped we need to set up the `.env` and the `./web/.htaccess` file. Please update the following values.\n\n#### .env\n```shell\nDB_HOST=\"wp-mysql\" // same name as the container\n...\nDB_NAME=\"wp_test\"\nDB_USER=\"db_user\"\nDB_PASSWORD=\"db_password\"\n...\nWP_HOME=\"http://example.kitt\"\nENV_SITEURL=\"http://api.example.kitt\"\n...\nWP_DEBUG_LOG=\"/dev/stderr\" // docker error log dir\n...\nJWT_AUTH_CORS_ENABLE=true\n```\n\nIf you already have an email account that is usable for PHPMailer you can also set up the following values.\n```shell\nSMTP_HOST=\"smtp.domain.com\" // \"smtp.gmail.com\"\nSMTP_AUTH=true\nSMTP_PORT=587\nSMTP_SECURE=\"tls\"\nSMTP_USERNAME=\"your@username.com\" // \"your@gmail.com\"\nSMTP_PASSWORD=\"password\" // your gmail password or app password\nSMTP_FROM=\"your@username.com\" // \"your@gmail.com\"\nSMTP_FROMNAME=\"WordPress\"\n```\n\n#### .htaccess\n```shell\nSetEnvIf Host ^ KITT_TLD=.kitt\nSetEnvIf Host ^ KITT_SLD=example\n```\n\nNow, it is necessary to rebuild the containers. Call the following command.\n```shell\ndocker compose build\n```\nAfterward, we will run the new containers.\n```shell\ndocker compose up\n```\n\n⚠️ **Keep in mind, that every time you edit your environment, you need to rebuild your containers.** ⚠️\n\nLet's try to access our configured backend system. Open your browser and enter the following domain.\n```shell\napi.example.kitt\n```\nYou should see a mask from WordPress where you have to enter the first values of your custom backend system. We will enter the following data.\n```shell\nSite Title =\u003e example.kitt\nUsername =\u003e admin\nPassword =\u003e admin\nConfirm use of weak password =\u003e check\nYour Email =\u003e your@email.com\nSearch engine visibility =\u003e check\n```\nPress the button **`Install WordPress`**! And login as admin. Before we start to configure the theme, we need to activate our new custom theme, you'll find it under `Appearance`. Additionally, we need to activate all `plugins`, too.\n\n## The Front-End\n\nLet's dive into the front-end directory `./web/app/themes/example` and configure the last part for WordPress. I'll take some parts of the snippets from the `example.functions.php` file to handle some configurations. Please add the following lines below inside of the `functions.php` file.\n\n#### functions.php / theme configuration\n```PHP\n/** debug */\nini_set('display_errors', 1);\nini_set('display_startup_errors', 1);\nerror_reporting(E_ALL);\n\nglobal $wpdb,\n  $wp_rewrite,\n  $pagenow;\n\n$kitt_instance = KiTT\\ThemeSetUp::get_instance();\n$kitt_instance-\u003eset_up_theme(\n  $wpdb,\n  /** reqiured */\n  $wp_rewrite,\n  /** reqiured */\n  $pagenow,\n  /** reqiured */\n  [\n    'set_up' =\u003e [\n      /** custom favicon, logos and login logo url */\n      'favicon' =\u003e $kitt_instance-\u003etheme_url . '/src/assets/icons/vue-icon.png',\n      'login_logo' =\u003e $kitt_instance-\u003etheme_url . '/src/assets/icons/vue-icon.svg',\n      'login_logo_url' =\u003e WP_HOME,\n      'admin_bar_logo' =\u003e $kitt_instance-\u003etheme_url . '/src/assets/icons/vue-icon.svg',\n      'permalink_structure' =\u003e '/%postname%/',\n      'default_user_role' =\u003e 'editor',\n      /** add or remove company settings menu page */\n      'company_settings' =\u003e false\n    ]\n  ]\n);\n\n$kitt_instance-\u003epost([\n  /** removes completely the default post section */\n  'remove_post' =\u003e true\n]);\n\n$kitt_instance-\u003epage([\n  'page' =\u003e [\n    /**\n     * info:\n     * https://developer.wordpress.org/reference/functions/remove_post_type_support/\n     * \n     * NOTE:\n     * Gutenberg editor is always disabled\n     */\n    'remove_support' =\u003e ['excerpt', 'comments', 'trackbacks', 'author'],\n    /** inspect the label attribute for=\"\" in the screen options panel */\n    'remove_meta_box' =\u003e ['commentsdiv', 'slugdiv'],\n    /** en- or disable the SEO meta box */\n    'SEO' =\u003e true,\n    /** to enable tag support */\n    'tag' =\u003e true,\n    /** to enable category support */\n    'category' =\u003e false\n  ]\n]);\n\n$kitt_instance-\u003eattachment([\n  'attachment' =\u003e [\n    /** to enable tag support */\n    'tag' =\u003e false,\n    /** to enable category support */\n    'category' =\u003e false,\n    /** enable search duplicates support */\n    'search_duplicates' =\u003e true\n  ],\n  /** \n   * set custom upload mimes\n   * \n   * extend_defaults = true|false\n   * true = merges the default upload mimes\n   * false = replaces the default upload mimes\n   * \n   * list of defaulst:\n   * https://developer.wordpress.org/reference/functions/get_allowed_mime_types/\n   */\n  'upload_mimes' =\u003e [\n    'extend_defaults' =\u003e true,\n    'jpg|jpeg|jpe' =\u003e 'image/jpeg',\n    'gif' =\u003e 'image/gif',\n    'png' =\u003e 'image/png',\n    /**\n     * NOTE:\n     * the XML declaration is required\n     * in each SVG file, otherwise\n     * the SVG upload is not accepted\n     * \n     * enter the version and the encoding\n     * charset at the top of each SVG file \n     * \n     * \u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n     * \u003csvg xmlns=\"http://www.w3.org/2000/svg\" ... viewBox=\"0 0 100 57\"\u003e\n     *     ...\n     * \u003c/svg\u003e\n     */\n    'svg' =\u003e 'image/svg+xml',\n    'pdf' =\u003e 'application/pdf',\n    'mp3|m4a|m4b' =\u003e 'audio/mpeg',\n    'mp4|m4v' =\u003e 'video/mp4',\n    'zip' =\u003e 'application/zip'\n  ],\n  'options_media' =\u003e [\n    /** WP default 150x150px */\n    'thumbnail_size' =\u003e [\n      'thumbnail_size_w' =\u003e 150,\n      'thumbnail_size_h' =\u003e 150\n    ],\n    /** WP default 1 */\n    'thumbnail_crop' =\u003e 1,\n    /** WP default 300x300px */\n    'medium_size' =\u003e [\n      'medium_size_w' =\u003e 300,\n      'medium_size_h' =\u003e 300\n    ],\n    /** WP default 768x768px */\n    'medium_large_size' =\u003e [\n      'medium_large_size_w' =\u003e 768,\n      'medium_large_size_h' =\u003e 768\n    ],\n    /** WP default 1024x1024px */\n    'large_size' =\u003e [\n      'large_size_w' =\u003e 1024,\n      'large_size_h' =\u003e 1024\n    ],\n    /** WP default 0 */\n    'uploads_yearmonth' =\u003e 1,\n    /** WP default open */\n    'ping_status' =\u003e 'closed',\n    /** WP default open */\n    'comment_status' =\u003e 'closed',\n    /** /wp-content/uploads */\n    'upload_path' =\u003e constant('WP_UPLOAD_DIR'),\n    /** http://127.0.0.1/uploads */\n    'upload_url_path' =\u003e constant('WP_UPLOAD_URL')\n  ]\n]);\n\n$kitt_instance-\u003ecomments([\n  /** removes completely the default comments section */\n  'remove_comments' =\u003e true\n]);\n\n$kitt_instance-\u003emenu([\n  /** register main menu locations */\n  'menu' =\u003e [\n    'locations'  =\u003e [\n      'header' =\u003e 'Header'\n    ]\n  ]\n]);\n```\n\n### REST-API\n\nIn this example project we want to use the REST API to get some data from the backend system that's why we have also to configure it. Please add the following snippet for it.\n\n#### functions.php / REST-API configuration\n```PHP\n$kitt_instance-\u003eREST_API([\n  'rest_api' =\u003e [\n    /**\n     * set the namespace for your routes\n     * =\u003e api.example.com/wp-json/-\u003enamespace\u003c-/endpoint\n     */\n    'namespace' =\u003e explode('.', parse_url(WP_HOME)['host'])[0],\n    /** removes the default REST API */\n    'remove_default' =\u003e true,\n    /**\n     * examples:\n     * 'Access-Control-Allow-Origin: ' . WP_HOME\n     * 'Access-Control-Allow-Methods: POST, GET'\n     * 'Access-Control-Allow-Credentials: true'\n     * 'Access-Control-Max-Age: 600'\n     */\n    'headers' =\u003e [\n      'Access-Control-Allow-Headers: Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type',\n      'Access-Control-Allow-Origin: ' . WP_HOME,\n      'Access-Control-Allow-Methods: POST, GET',\n      'Access-Control-Allow-Credentials: true',\n      'Access-Control-Max-Age: 600'\n    ],\n    /** JWT token arguments */\n    'token' =\u003e [\n      'expiration_time' =\u003e time() + (DAY_IN_SECONDS * 7),\n      'header' =\u003e 'Access-Control-Allow-Headers, Access-Control-Allow-Origin, Content-Type, Authorization'\n    ]\n  ]\n]);\n```\n\nAs you can see, I set the `Access-Control-Allow-Origin` header to `WP_HOME`, this means that requests are only allowed from `example.kitt`. This is important because we don't want, that other websites can access the data. The namespace is set to `example` by `explode('.', parse_url(WP_HOME)['host'])[0]`, so if you want to make requests to the REST-API you need to call `api.example.com/wp-json/example/endpoint`.\n\nAfter we added the REST-API configuration snippet and reloaded the backend system, we need to create a **REST-API user**. Go to `Users` and create a user with the credentials of our `.env` file. In this case, it is important to set the **`Username === REST_USER`**, the **`Password === admin`**, and the **`Role === REST API User`**.\n\n\n### JWT Token Handling\n\nObviously, we need a token for each request. To retrieve a token we will add now a small snippet to the `functions.php` file. Let's extend the instance and add a new endpoint and a callback function to handle the request.\n\n#### functions.php / adding REST-API endpoint\n```PHP\n/**\n * register the /token endpoint to retrieve\n * the token from JWT Authentication for WP REST API\n */\n$kitt_instance-\u003erest_routes['token'] = [\n  /**\n   * class WP_REST_Server {\n   * ...\n   *   const READABLE = 'GET';\n   *   const CREATABLE = 'POST';\n   * ...\n   * }\n   * \n   * \\WP_REST_Server::READABLE === GET\n   * \n   * documentation\n   * https://developer.wordpress.org/reference/classes/wp_rest_server/\n   */\n  'methods'  =\u003e \\WP_REST_Server::READABLE,\n  'callback' =\u003e 'get_token',\n  // set the permission to public\n  'permission_callback' =\u003e '__return_true',\n  // the args key is required even if the array is empty\n  'args' =\u003e []\n];\n\n/**\n * define a custom callback function\n * to handle the request\n */\n$kitt_instance-\u003eget_token = function () {\n  $response= null;\n  // create a simple curl request\n  try {\n    $ch = curl_init();\n\n    curl_setopt($ch, CURLOPT_URL, ENV_SITEURL . '/wp-json/jwt-auth/v1/token');\n    curl_setopt($ch, CURLOPT_POST, 1);\n    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([\n      'username' =\u003e constant('REST_USER'),\n      'password' =\u003e constant('REST_PASSWORD')\n    ]));\n\n    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n\n    $response = curl_exec($ch);\n\n    curl_close($ch);\n  } catch (Exception $e) {\n    $response = $e-\u003egetMessage();\n  }\n  // return the data\n  return new \\WP_REST_Response(json_decode($response), 200);\n};\n```\n\nWhat have we done? We added a new endpoint to `$kitt_instance-\u003erest_routes` which is callable with `token` (`api.example.com/wp-json/example/token`). The method is set to `GET` by `\\WP_REST_Server::READABLE`. Every endpoint needs a permission callback. With the [**WordPress Theme Configuration**](https://github.com/dark-kitt/wordpress-theme-configuration) plugin, it is only possible to set the permission to `rest_api_user` (protected) or like in our case `__return_true` (public). Afterward, it is necessary to handle the request by a callback function, which is defined underneath the `$kitt_instance-\u003erest_routes` configuration. You can also add some arguments in the last array, but in our case, it is not necessary.\n\n### PHPMailer\n\nIf you have entered email configurations in the `.env` file before, you can add the following snippet to configure PHPMailer, otherwise, you can ignore this step. Just add the snippet below and test the endpoint by calling a request to `api.example.com/wp-json/example/email`. Afterward, you should receive an email to your account by yourself.\n\n#### functions.php / PHPMailer configuration\n```PHP\n/**\n * update email route arguments\n * set server settings\n *\n * update values with WP constants\n * or set your custom settings\n */\n$kitt_instance-\u003erest_routes['email']['args']['host'] = ['default' =\u003e constant('SMTP_HOST')]; // 'smtp.gmail.com'\n$kitt_instance-\u003erest_routes['email']['args']['SMTP_auth'] = ['default' =\u003e constant('SMTP_AUTH')]; // boolean\n$kitt_instance-\u003erest_routes['email']['args']['username'] = ['default' =\u003e constant('SMTP_USERNAME')]; // 'your@username.com'\n/** \n * use google app password:\n * https://support.google.com/accounts/answer/185833?hl=en\n */\n$kitt_instance-\u003erest_routes['email']['args']['password'] = ['default' =\u003e constant('SMTP_PASSWORD')]; // 'app-password'\n$kitt_instance-\u003erest_routes['email']['args']['SMTP_secure'] = ['default' =\u003e constant('SMTP_SECURE')]; // 'tls'\n$kitt_instance-\u003erest_routes['email']['args']['port'] = ['default' =\u003e constant('SMTP_PORT')]; // 587\n/** PHPMailer debug */\n$kitt_instance-\u003erest_routes['email']['args']['debug'] = ['default' =\u003e false];\n/**\n * test PHPMailer and send a mail to your own account via\n * http://api.example.com/wp-json/-\u003enamespace\u003c-/email\n */\n$kitt_instance-\u003erest_routes['email']['args']['set_from'] = ['default' =\u003e [\n  'address' =\u003e constant('SMTP_USERNAME'),\n  'name' =\u003e 'Foo'\n]];\n$kitt_instance-\u003erest_routes['email']['args']['add_address'] = ['default' =\u003e [[\n  'address' =\u003e constant('SMTP_USERNAME'),\n  'name' =\u003e 'Bar'\n]]];\n```\n\n### Add the output\n\nAs described before this example project used the second option to handle the \"[**Islands Architecture**](https://www.patterns.dev/vanilla/islands-architecture)\". So we need to add the output files to the DOM by WordPress. Let's add another snippet. At this time, we will open and edit the `index.php` file.\n\n#### index.php / enqueue scripts and styles\n```PHP\n// enqueue scripts and styles\nadd_action('wp_enqueue_scripts', function () {\n  if (file_exists('./www/assets-manifest.json')) {\n    $manifest = json_decode(file_get_contents('./www/assets-manifest.json'));\n    foreach ($manifest as $key =\u003e $value) {\n      if ($key == 'entrypoints') {\n        foreach ($value-\u003emain-\u003eassets-\u003ejs as $js_file) {\n          $js_file_info = pathinfo($js_file);\n          // replace [hash].bundle.min for tag \u003cscript id=\"$id\" ...\n          $id = preg_replace('/(|\\.\\w+)\\.bundle\\.min/', '', $js_file_info['filename']);\n          // enqueue the main.bundle.js file at the end of the DOM\n          wp_enqueue_script($id, WP_HOME . '/www/' . $js_file, [], false, str_contains($js_file_info['filename'], 'main'));\n        }\n\n        foreach ($value-\u003emain-\u003eassets-\u003ecss as $css_file) {\n          $css_file_info = pathinfo($css_file);\n          // replace [hash].bundle.min for tag \u003clink id=\"$id\" ...\n          $id = preg_replace('/(|\\.\\w+)\\.bundle\\.min/', '', $css_file_info['filename']);\n          wp_enqueue_style($id, WP_HOME . '/www/' . $css_file, [], false, 'screen');\n        }\n      }\n    }\n  }\n});\n```\n\nAs you can see, I create a manifest.json file inside of the output directory (`/www`) by **`Webpack`** and read and add all scripts and styles that are listed in the JSON file. It is required to add an ID for each file, so, I remove the hash to have a readable ID name. I also create an exception for the `main.bundle.js` file, that this file is always included at the end of the DOM.\n\nThe last point is to request a token and hand over it to the front-end system. For this, I created just a global constant.\n\n```PHP\n\u003cscript\u003e\nconst TOKEN_DATA = \u003c?= json_encode($kitt_instance-\u003eget_token()-\u003edata, JSON_PRETTY_PRINT) ?\u003e;\n\u003c/script\u003e\n```\n\nSo, in the end, my `index.php` file is looking like this.\n\n#### index.php\n```PHP\n\u003c?php\n// Load WordPress for access of internal functions\nrequire_once('../../../wp/wp-load.php');\n// enqueue scripts and styles\nadd_action('wp_enqueue_scripts', function () {\n  if (file_exists('./www/assets-manifest.json')) {\n    $manifest = json_decode(file_get_contents('./www/assets-manifest.json'));\n    foreach ($manifest as $key =\u003e $value) {\n      if ($key == 'entrypoints') {\n        foreach ($value-\u003emain-\u003eassets-\u003ejs as $js_file) {\n          $js_file_info = pathinfo($js_file);\n          // replace [hash].bundle.min for tag \u003cscript id=\"$id\" ...\n          $id = preg_replace('/(|\\.\\w+)\\.bundle\\.min/', '', $js_file_info['filename']);\n          // enqueue the main.bundle.js file at the end of the DOM\n          wp_enqueue_script($id, WP_HOME . '/www/' . $js_file, [], false, str_contains($js_file_info['filename'], 'main'));\n        }\n\n        foreach ($value-\u003emain-\u003eassets-\u003ecss as $css_file) {\n          $css_file_info = pathinfo($css_file);\n          // replace [hash].bundle.min for tag \u003clink id=\"$id\" ...\n          $id = preg_replace('/(|\\.\\w+)\\.bundle\\.min/', '', $css_file_info['filename']);\n          wp_enqueue_style($id, WP_HOME . '/www/' . $css_file, [], false, 'screen');\n        }\n      }\n    }\n  }\n});\n\nget_header();\n?\u003e\n\n\u003cmain id=\"theme\"\u003eWordPress index.php\u003c/main\u003e\n\n\u003cscript\u003e\nconst TOKEN_DATA = \u003c?= json_encode($kitt_instance-\u003eget_token()-\u003edata, JSON_PRETTY_PRINT) ?\u003e;\n\u003c/script\u003e\n\n\u003c?php get_footer(); ?\u003e\n```\n\n#### .env\n\nThe last step is to create the `.env` file inside of the `/configs` theme directory. Please copy and paste the `.example.env` file inside of the `./web/app/themes/example/configs` directory.\n```shell\ncp ./configs/.example.env ./configs/.env\n```\n\nOk, that was a lot of instructions, but now you are done! Just install all necessary packages with `yarn` and start the front-end system by calling `yarn dev`. Afterward, all the necessary output should be created inside of the `/www` directory to make our example project visible at `example.kitt`.\n\nNow it is up to you. Be creative and start coding. Just place your scripts and styles inside of the `/src` directory and create your own custom front-end system.\n\n**Happy coding!**\n\n---\n---\n\n## License\n\n[![](https://upload.wikimedia.org/wikipedia/commons/e/e5/CC_BY-SA_icon.svg)](https://creativecommons.org/licenses/by-sa/4.0)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdark-kitt%2Fwordpress-theme-vue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdark-kitt%2Fwordpress-theme-vue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdark-kitt%2Fwordpress-theme-vue/lists"}