Initiating the Docs Information Architecture and committing the first major batch of documents

We've been quietly building a set of documentation in a private repo that we are ready to move over to the public monorepo so that we can continue our initiative to imrpove the documentation experience for Woo developers.
This commit is contained in:
Brent MacKinnon 2023-08-18 15:47:07 -03:00
parent 278366def9
commit 6dec084ab4
86 changed files with 4324 additions and 44 deletions

View File

@ -0,0 +1,30 @@
---
name: "\U0001F4C4 Request for New Document"
about: Suggest the creation of a new documentation topic that doesn't exist yet.
title: "[DOC-REQ]"
labels: 'type: documentation'
assignees: ''
---
## Description of the Document Requested
> Provide a detailed description of the topic you'd like to see documented.
## Why is this Document Important?
> Explain why this topic is crucial and how it can benefit the WooCommerce community.
## Potential Content
> If you have an idea about what the new document should cover, list the points or sub-topics here.
## Additional Context
> Add any other context, references, or information that can help in the creation of this new document.

View File

@ -0,0 +1,30 @@
---
name: "\U0001F4DD Suggestion for Documentation Improvement/Correction"
about: Propose a specific improvement or correction for an existing document.
title: "[DOC-BUG]"
labels: 'type: documentation'
assignees: ''
---
## Link to the Page/Section
> Provide a link to the specific page or section that you're referring to.
## Description of the Suggestion
> Describe the changes you suggest to improve or correct the documentation. Be specific about any errors or areas of confusion you've identified.
## Reason for the Suggestion
> Why do you believe this change will make the documentation clearer or more accurate?
## Additional Context
> Add any other context, references, or screenshots that support your suggestion.

23
.github/workflows/md-linting.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Markdown Linting
on:
pull_request:
push:
branches: [trunk]
jobs:
MDLintingCheck:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup node version and npm cache
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install Node dependencies
run: npm ci --no-optional
- name: Lint
run: npm run lint

View File

@ -1,59 +1,90 @@
# WooCommerce internal documentation
# WooCommerce Developer Documentation
This directory contains documentation about implementation details specific parts of the WooCommerce code base. This documentation is intended for developers.
> ⚠️ **Notice:*- This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
## Available documents
This is your go-to place to find everything you need to know to get started with WooCommerce development, including implementation details for specific parts of the WooCommerce code base.
* [HPOS](HPOS.md): Details of how the High Performance Order Storage works.
## Getting started
## Other documents
WooCommerce is a customizable, open-source eCommerce platform built on WordPress. It empowers businesses worldwide to sell anything from physical products and digital downloads to subscriptions, content, and even appointments.
Get familiar with [WordPress Plugin Development](https://developer.wordpress.org/plugins/).
Take a moment to familiarize yourself with our [Developer Resources](https://developer.wordpress.org/plugins/plugin-basics/).
Once you're ready to move forward, consider one of the following:
- [Tools for low code development](getting-started/tools-for-low-code-development.md)
- [Building your first extension](extension-development/building-your-first-extension.md)
- [How to design a simple extension](extension-development/how-to-design-a-simple-extension.md)
## Contributions
The WooCommerce ecosystem thrives on community contributions. Whether it's improving documentation, reporting bugs, or contributing code, we greatly appreciate every contribution from our community.
- To contribute to **the core WooCommerce project**, check out our [Contributing guide](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md).
- To contribute to **documentation*- please refer to the [documentation style guide](style-guide.md).
## Support
- To request a **new document, correction, or improvement**, [create an issue](https://github.com/woocommerce/woodocs/issues/new/choose).
- For development help, start with the [WooCommerce Community Forum](https://wordpress.org/support/plugin/woocommerce/), to see if someone else has already asked the same question. You can also pose your question in the `#developers` channel of our [Community Slack](https://woocommerce.com/community-slack/). If you're not sure where to ask your question, you can always [contact us](https://woocommerce.com/contact-us/), and our Happiness Engineers will be glad to point you in the right direction.
- For additional support with customizations, you might consider hiring from [WooExperts](https://woocommerce.com/experts/) or [Codeable](https://codeable.io/).
### Additional Resources
- [WooCommerce Official Website](https://woocommerce.com/)
- [Woo Marketplace](https://woocommerce.com/marketplace)
- All [WooCommerce Repositories on GitHub](https://woocommerce.github.io/)
### Other documentation
Some directories contain documentation about their own contents, in the form of README file. The available files are listed below, **if you create a new README file please add it to the corresponding list.**
Available READMe files for the WooCommerce plugin:
* [`Root README`](../plugins/woocommerce/README.md)
* [`i18n/languages`](../plugins/woocommerce/i18n/languages/README.md)
* [`includes`](../plugins/woocommerce/includes/README.md)
* [`lib`](../plugins/woocommerce/lib/README.md)
* [`packages`](../plugins/woocommerce/packages/README.md)
* [`src`](../plugins/woocommerce/src/README.md)
* [`src/Admin/RemoteInboxNotifications`](../plugins/woocommerce/src/Admin/RemoteInboxNotifications/README.md)
* [`src/Admin/RemoteInboxNotifications/Transformers`](../plugins/woocommerce/src/Admin/RemoteInboxNotifications/Transformers/README.md)
* [`src/Blocks`](../plugins/woocommerce/src/Blocks/README.md)
* [`src/Internal`](../plugins/woocommerce/src/Internal/README.md)
* [`src/Internal/Admin/ProductForm`](../plugins/woocommerce/src/Internal/Admin/ProductForm/README.md)
* [`tests`](../plugins/woocommerce/tests/README.md)
* [`tests/api-core-tests`](../plugins/woocommerce/tests/api-core-tests/README.md)
* [`tests/e2e`](../plugins/woocommerce/tests/e2e/README.md)
* [`tests/e2e-pw`](../plugins/woocommerce/tests/e2e-pw/README.md)
* [`tests/performance`](../plugins/woocommerce/tests/performance/README.md)
* [`tests/Tools/CodeHacking`](../plugins/woocommerce/tests/Tools/CodeHacking/README.md)
- [`Root README`](../plugins/woocommerce/README.md)
- [`i18n/languages`](../plugins/woocommerce/i18n/languages/README.md)
- [`includes`](../plugins/woocommerce/includes/README.md)
- [`lib`](../plugins/woocommerce/lib/README.md)
- [`packages`](../plugins/woocommerce/packages/README.md)
- [`src`](../plugins/woocommerce/src/README.md)
- [`src/Admin/RemoteInboxNotifications`](../plugins/woocommerce/src/Admin/RemoteInboxNotifications/README.md)
- [`src/Admin/RemoteInboxNotifications/Transformers`](../plugins/woocommerce/src/Admin/RemoteInboxNotifications/Transformers/README.md)
- [`src/Blocks`](../plugins/woocommerce/src/Blocks/README.md)
- [`src/Internal`](../plugins/woocommerce/src/Internal/README.md)
- [`src/Internal/Admin/ProductForm`](../plugins/woocommerce/src/Internal/Admin/ProductForm/README.md)
- [`tests`](../plugins/woocommerce/tests/README.md)
- [`tests/api-core-tests`](../plugins/woocommerce/tests/api-core-tests/README.md)
- [`tests/e2e`](../plugins/woocommerce/tests/e2e/README.md)
- [`tests/e2e-pw`](../plugins/woocommerce/tests/e2e-pw/README.md)
- [`tests/performance`](../plugins/woocommerce/tests/performance/README.md)
- [`tests/Tools/CodeHacking`](../plugins/woocommerce/tests/Tools/CodeHacking/README.md)
Available READMe files for the WooCommerce Admin plugin:
* [`Root README`](../plugins/woocommerce-admin/README.md)
* [`client/activity-panel`](../plugins/woocommerce-admin/client/activity-panel/README.md)
* [`client/activity-panel/activity-card`](../plugins/woocommerce-admin/client/activity-panel/activity-card/README.md)
* [`client/activity-panel/activity-header`](../plugins/woocommerce-admin/client/activity-panel/activity-header/README.md)
* [`client/analytics/report`](../plugins/woocommerce-admin/client/analytics/report/README.md)
* [`client/analytics/settings`](../plugins/woocommerce-admin/client/analytics/settings/README.md)
* [`client/dashboard`](../plugins/woocommerce-admin/client/dashboard/README.md)
* [`client/header`](../plugins/woocommerce-admin/client/header/README.md)
* [`client/marketing`](../plugins/woocommerce-admin/client/marketing/README.md)
* [`client/marketing/components/button`](../plugins/woocommerce-admin/client/marketing/components/button/README.md)
* [`client/marketing/components/card`](../plugins/woocommerce-admin/client/marketing/components/card/README.md)
* [`client/marketing/components/product-icon`](../plugins/woocommerce-admin/client/marketing/components/product-icon/README.md)
* [`client/utils`](../plugins/woocommerce-admin/client/utils/README.md)
* [`client/wp-admin-scripts`](../plugins/woocommerce-admin/client/wp-admin-scripts/README.md)
* [`docs`](../plugins/woocommerce-admin/docs/README.md)
* [`docs/examples`](../plugins/woocommerce-admin/docs/examples/README.md)
* [`docs/examples/extensions`](../plugins/woocommerce-admin/docs/examples/extensions/README.md)
* [`docs/features`](../plugins/woocommerce-admin/docs/features/README.md)
* [`docs/woocommerce.com`](../plugins/woocommerce-admin/docs/woocommerce.com/README.md)
- [`Root README`](../plugins/woocommerce-admin/README.md)
- [`client/activity-panel`](../plugins/woocommerce-admin/client/activity-panel/README.md)
- [`client/activity-panel/activity-card`](../plugins/woocommerce-admin/client/activity-panel/activity-card/README.md)
- [`client/activity-panel/activity-header`](../plugins/woocommerce-admin/client/activity-panel/activity-header/README.md)
- [`client/analytics/report`](../plugins/woocommerce-admin/client/analytics/report/README.md)
- [`client/analytics/settings`](../plugins/woocommerce-admin/client/analytics/settings/README.md)
- [`client/dashboard`](../plugins/woocommerce-admin/client/dashboard/README.md)
- [`client/header`](../plugins/woocommerce-admin/client/header/README.md)
- [`client/marketing`](../plugins/woocommerce-admin/client/marketing/README.md)
- [`client/marketing/components/button`](../plugins/woocommerce-admin/client/marketing/components/button/README.md)
- [`client/marketing/components/card`](../plugins/woocommerce-admin/client/marketing/components/card/README.md)
- [`client/marketing/components/product-icon`](../plugins/woocommerce-admin/client/marketing/components/product-icon/README.md)
- [`client/utils`](../plugins/woocommerce-admin/client/utils/README.md)
- [`client/wp-admin-scripts`](../plugins/woocommerce-admin/client/wp-admin-scripts/README.md)
- [`docs`](../plugins/woocommerce-admin/docs/README.md)
- [`docs/examples`](../plugins/woocommerce-admin/docs/examples/README.md)
- [`docs/examples/extensions`](../plugins/woocommerce-admin/docs/examples/extensions/README.md)
- [`docs/features`](../plugins/woocommerce-admin/docs/features/README.md)
- [`docs/woocommerce.com`](../plugins/woocommerce-admin/docs/woocommerce.com/README.md)
Available READMe files for the WooCommerce Beta Tested plugin:
* [`Root README`](../plugins/woocommerce-beta-tester/README.md)
* [`src/tools`](../plugins/woocommerce-beta-tester/src/tools/README.md)
* [`userscripts`](../plugins/woocommerce-beta-tester/userscripts/README.md)
- [`Root README`](../plugins/woocommerce-beta-tester/README.md)
- [`src/tools`](../plugins/woocommerce-beta-tester/src/tools/README.md)
- [`userscripts`](../plugins/woocommerce-beta-tester/userscripts/README.md)

View File

@ -0,0 +1,117 @@
# Building your first extension
The easiest way to get started building an extension is to use the built-in extension generator that is included alongside WooCommerce Admin. This utility is maintained as part of the codebase for WooCommerce Admin, so it includes up-to-date tools and many preconfigured settings for building modern extensions that take advantage of the [React-powered](https://react.dev/) user experience available in current versions of WordPress and WooCommerce.
## Using the extension generator
Browse to your local WooCommerce Admin repository
```sh
cd /your/server/wp-content/plugins/woocommerce-admin
```
Run the extension generator command
```sh
npm run create-wc-extension
```
The extension generator will scaffold out a basic extension and place it in its own plugin directory alongside WooCommerce on your local server.
The extension that the generator creates contains a simple [boilerplate](https://stackoverflow.com/questions/3992199/what-is-boilerplate-code) that handles much of the configuration needed for setting up a React-powered extension, which you can modify to fit your needs.
## The architecture of a basic WooCommerce extension
WooCommerce extensions use a combination of PHP and modern JavaScript to create a seamless user experience for merchants and shoppers that takes advantage of the features and functionality available in the [NodeJS](https://nodejs.org/en) ecosystem while still being a good neighbor within the underlying WordPress application environment.
WordPress plugins (of which WooCommerce extensions are a specialized subset), tend to follow a few common patterns. You can read more about common WordPress plugin architecture in the [Best Practices chapter of the WordPress Plugin Developer Handbook](https://developer.wordpress.org/plugins/plugin-basics/best-practices/#architecture-patterns).
In addition to the main PHP file that all WordPress plugins must contain, a WooCommerce extension will typically contain additional PHP files with classes that assist in server-side functionality.
It will also contain files that are JavaScript and CSS assets which shape the client-side behavior and appearance.
## File structure generated by the `create-wc-extension script`
When you run the built-in extension generator, it will output something that looks similar to the structure below.
```sh
.
├── README.md
├── my-great-extension.php
├── package.json
├── src
│ ├── index.js
│ └── index.scss
└── webpack.config.js
```
Heres a breakdown of what these files are and what purpose they serve:
`README.md`
This file is meant to have a high-level overview of your extension to make it easier for people to use and extend your project. The generator outputs a basic file with some minimal instructions in it to get you started, but you should replace the contents of the file with information specific to your project. Its important to keep in mind that this file is not the same as the readme.txt file required by WordPress.org plugin directory, which must adhere to specific file standads.
`[your-extension-name].php`
This is your extensions main PHP file. It functions as the entry point for your extension and is where youll likely include code that hooks your extension into WordPress and WooCommerce. You can read more about the purpose of this file in the Getting Started section of the WordPress Plugin Developer Handbook.
`package.json`
This is a manifest file that Node uses for a number of different purposes. It can store configuration settings for tools, lists of dependencies, aliases for common scripts, and even metadata about your extension. The WooCommerce extension generator outputs a package.json file that will bundle many helpful dependencies with your extension, as well as a variety of scripts you can use in conjunction with these dependencies to streamline your workflow and make sure your extension conforms to the same standards as other WordPress plugins and WooCommerce extensions. Heres an example of what your package.json file might look like initially:
```json
{
"name": "my-great-extension",
"title": "my-great-extension",
"license": "GPL-3.0-or-later",
"version": "0.1.0",
"description": "my-great-extension",
"scripts": {
"build": "wp-scripts build",
"check-engines": "wp-scripts check-engines",
"check-licenses": "wp-scripts check-licenses",
"format:js": "wp-scripts format-js",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"lint:md:docs": "wp-scripts lint-md-docs",
"lint:md:js": "wp-scripts lint-md-js",
"lint:pkg-json": "wp-scripts lint-pkg-json",
"packages-update": "wp-scripts packages-update",
"start": "wp-scripts start",
"test:e2e": "wp-scripts test-e2e",
"test:unit": "wp-scripts test-unit-js"
},
"devDependencies": {
"@wordpress/scripts": "^12.2.1",
"@woocommerce/eslint-plugin": "1.1.0",
"@woocommerce/dependency-extraction-webpack-plugin": "1.1.0"
}
}
```
The settings in this autogenerated file tell Webpack to use the default configuration included with the `@wordpress/scripts` package (listed in your `package.json` as a development dependency) and to override the plugin it uses for dependency extraction with one that is tailor-made for WooCommerce extensions.
## Try out your extension
If you used the extension generator to create your extension, youll need to complete a few final steps to see it in action.
First, navigate to your extensions root directory on your development server:
```sh
cd /your/server/wc-content/plugins/your-extension/
```
Then install the projects dependencies.
```sh
npm install
```
Finally, run the start script to generate an initial build of your extension. This script will also continuously watch your local files for changes.
```sh
npm start
```
Once your initial build is complete, you can browse to the administrative area of your local WordPress environment and activate your extension. If everything worked as it should, you should see a message in your browsers JavaScript console:
```sh
hello world
```

View File

@ -0,0 +1,205 @@
# Setting up your development environment
## Introduction
Building an extension for WooCommerce is a straightforward process, but there are a several moving parts and a few supporting software tools youll want to familiarize yourself with. This guide will walk you through the steps of getting a basic development environment set up for building WooCommerce extensions.
If you would like to contribute to the WooCommerce core platform; please read our [contributor documentation and guidelines](https://github.com/woocommerce/woocommerce/wiki/How-to-set-up-WooCommerce-development-environment).
## Prerequisites
### Recommended reading
WooCommerce extensions are a specialized type of WordPress plugin. If you are new to WordPress plugin development, take a look at a few of these articles in the [WordPress Plugin Developer Handbook](https://developer.wordpress.org/plugins/).
### Required software
[Git](https://git-scm.com/)
[nvm](https://github.com/nvm-sh/nvm/blob/master/README.md)
[NodeJS](https://nodejs.org/en)
[PNpm](https://pnpm.io/)
[Composer](https://getcomposer.org/download/)
Note: If youre working on a Windows machine, you may want to take a look at the Building Extensions in Windows Environments section of this guide before proceeding.
### Setting up your reusable WordPress development environment
In addition to the software listed above, youll also want to have some way of setting up a local development server stack. There are a number of different tools available for this, each with a certain set of functionality and limitations. We recommend choosing an option below that fits your preferred workflow best.
### WordPress-specific tools
[vvv](https://varyingvagrantvagrants.org/) A highly configurable, cross-platform, and robust environment management tool powered by VirtualBox and Vagrant. This is one the tool that the WooCommerce Core team recommends to contributors.
[wp-env](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) A command-line utility maintained by the WordPress community that allows you to set up and run custom WordPress environments with Docker and JSON manifests.
[LocalWP](https://localwp.com/) A cross-platform app that bills itself as a one-click WordPress installation.
### General PHP-based web stack tools
[MAMP](https://www.mamp.info/en/mac/) A local server environment that can be installed on Mac or Windows.
[WAMP](https://www.wampserver.com/en/) A Windows web development environment that lets you create applications with Apache2, PHP, and MySQL.
[XAMPP](https://www.apachefriends.org/index.html) An easy-to-install Apache distribution containing MariaDB, PHP, and Perl. Its available for Windows, Linux, and OS X.
### Minimum server requirements
Regardless of the tool you choose for managing your development environment, you should make sure it [meets the server recommendations](https://woocommerce.com/document/server-requirements/?utm_source=wooextdevguide) for WooCommerce as well as the [requirements for running WordPress](https://wordpress.org/about/requirements/).
## Anatomy of a WordPress development environment (public_html/)
While development environments can vary, the basic file structure for a WordPress environment should be consistent.
When developing a WooCommerce extension, youll usually be doing most of your work within the public_html directory of your local server. For now, take some time to familiarize yourself with a few key paths:
`wp-content/debug.log` This is the file where WordPress writes the important output such as errors and other messages useful for debugging.
`wp-content/plugins/` This is the directory on the server where WordPress plugin folders live.
`wp-content/themes/` This is the directory on the server where WordPress theme folders live.
## Adding WooCommerce Core to your environment
When developing an extension for WooCommerce, its helpful to install a development version of WooCommerce core.
### Clone the WC Core repo into `wp-content/plugins/`
```sh
cd /your/server/wp-content/plugins
git clone https://github.com/woocommerce/woocommerce.git
cd woocommerce
```
### Activate the required Node version
```sh
nvm use
Found '/path/to/woocommerce/.nvmrc' with version <v12>
Now using node v12.21.0 (npm v6.14.11)
```
Note: if you dont have the required version of Node installed, NVM will alert you so you can install it:
```sh
Found '/path/to/woocommerce/.nvmrc' with version <v12>
N/A: version "v12 -> N/A" is not yet installed.
You need to run "nvm install v12" to install it before using it.
```
### Install dependencies
```sh
pnpm install && composer install
```
### Build WooCommerce
```sh
pnpm run build
```
Running this script will compile the JavaScript and CSS that WooCommerce needs to operate. If you try to run WooCommerce on your server without generating the compiled assets, you may experience errors and other unwanted side-effects.
Note: In some environments, you may see an out-of-memory error when you try to build WooCommerce. If this happens, you simply need to adjust the memory_limit setting in your environments php.ini configuration to a higher value. The process for changing this value varies depending on the environment management tooling you use, so its best to consult your tools documentation before making any changes.
## Adding WooCommerce Admin to your environment
Installing a development version of WooCommerce Admin will give you access to some helpful utilities such as a built-in script for generating React-powered WooCommerce extensions.
### Clone the WC Admin repo into `wp-content/plugins/`
```sh
cd /your/server/wp-content/plugins
git clone https://github.com/woocommerce/woocommerce-admin.git
cd woocommerce-admin
```
### Activate the required Node version
```sh
nvm use
Found '/path/to/woocommerce-admin/.nvmrc' with version <lts/*>
Now using node v14.16.0 (npm v6.14.11)
```
Note: if you dont have the required version of Node installed, NVM will alert you so you can install it.
```sh
Found '/path/to/woocommerce-admin/.nvmrc' with version <v12>
N/A: version "lts/* -> N/A" is not yet installed.
You need to run "nvm install lts/*" to install it before using it.
```
Pro-tip: WooCommerce Admin may require a different version of Node than WooCommerce Core requires. Keep this in mind when navigating between directories using the same shell session. As a best practice, always make sure to activate the correct version of Node using nvm use before running any commands inside a cloned repository.
### Install dependencies
```sh
npm install && composer install
```
## Build a development version of WooCommerce Admin
Building a development version will compile unminified versions of asset files, which is useful when debugging extensions that interact with WooCommerce Admin features.
```sh
npm run dev
```
If you run into trouble when building WooCommerce Admin, take a look at this wiki article for troubleshooting help.
## Adding WooCommerce Blocks to your environment
Installing a development version of WooCommerce Blocks is not required in every case, but having a standalone installation of the feature-plugin version of this extension allows you to work with the latest features, which can be helpful for compatibility testing and future-proofing your extension.
### Clone the WC Blocks repo into `wp-content/plugins/`
```sh
cd /your/server/wp-content/plugins
git clone https://github.com/woocommerce/woocommerce-gutenberg-products-block.git
cd woocommerce-gutenberg-products-block
```
### Activate the required Node version
```sh
nvm use
Found '/path/to/woocommerce-gutenberg-products-block/.nvmrc' with version <lts/*>
Now using node v14.16.0 (npm v6.14.11)
```
Note: if you dont have the required version of Node installed, NVM will alert you so you can install it.
```sh
Found '/path/to/woocommerce-gutenberg-products-block/.nvmrc' with version <v12>
N/A: version "lts/* -> N/A" is not yet installed.
You need to run "nvm install lts/*" to install it before using it.
```
Pro-tip: WooCommerce Blocks may require a different version of Node than WooCommerce Core requires. Keep this in mind when navigating between directories using the same shell session. As a best practice, always make sure to activate the correct version of Node using nvm use before running any commands inside a cloned repository.
### Install dependencies
```sh
npm install && composer install
Build the assets
npm run build
```
This will compile and minify the JavaScript and CSS from the /assets directory to be served.
## Finishing up
Once you have WooCommerce and its sibling extensions installed in your WordPress environment, start up your server, browse to your site and handle any initial setup steps or importing youd like to do. This is a good time to load sample data and activate themes and plugins.
Depending on which extensions you installed in your environment you should have one or more of the following directories in your `public_html` directory:
- `wp-content/plugins/woocommerce`
- `wp-content/plugins/woocommerce-admin`
- `wp-content/plugins/woocommerce-gutenberg-products-block`
- `wp-content/themes/storefront`

View File

@ -0,0 +1,50 @@
# Handling deactivation and uninstallation
## Introduction
There are a number of cleanup tasks youll need to handle when a merchant deactivates or uninstalls your extension. This guide provides a brief overview of WooCommerce-specific items youll want to make sure you account for when defining your extensions deactivation and uninstallation logic.
## Removing Scheduled Actions
If your extension uses Action Scheduler to queue any background jobs, its important to unschedule those actions when your extension is uninstalled or deactivated.
`as_unschedule_all_actions( $hook, $args, $group );`
You can read more about using Action Scheduler for managing background processing in the [Action Scheduler API Reference](https://actionscheduler.org/api/).
## Removing Admin Notes
If you have created any Notes for merchants, you should delete those notes when your extension is deactivated or, at the very least, when it is uninstalled.
```php
function my_great_extension_deactivate() {
ExampleNote::possibly_delete_note();
}
register_deactivation_hook( __FILE__, 'my_great_extension_deactivate' );
```
The example above assumes that you have followed the pattern this guide recommends for creating Notes as dedicated classes that include the `NoteTraits` trait included with WooCommerce Admin. This approach provides your Note with some baked in functionality that streamlines note operations such as creation and deletion.
## Removing Admin Tasks
When your extension is deactivated or uninstalled, you should take care to unregister any tasks that your extension created for merchants.
```php
// Unregister task.
function my_extension_deactivate_task() {
remove_filter( 'woocommerce_get_registered_extended_tasks', 'my_extension_register_the_task', 10, 1 );
}
register_deactivation_hook( __FILE__, 'my_extension_deactivate_task' );
```
Keep in mind that merchant tasks are managed via a hybrid approach that involves both PHP and JavaScript, so the client-side registration only happens when your extensions JavaScript runs.
## Unregistering navigation
When your extension deactivates and uninstalls, any registration youve done with the WooCommerce Navigation will be handled automatically.
## WordPress cleanup tasks
There are additional measures you may need to consider when your extension is deactivated or uninstalled, depending on the types of modifications it makes to the underlying WordPress environment when it activates and runs. You can read more about handling deactivation and uninstallation in the [WordPress Plugin Developer Handbook](https://developer.wordpress.org/plugins/intro/).

View File

@ -0,0 +1,655 @@
# Handling merchant onboarding
## Introduction
Onboarding is a critical part of the merchants user experience. It helps set them up for success and ensures theyre not only using your extension correctly but also getting the most out of it. There are a few especially useful features that you can take advantage of as a developer to help onboard merchants who are using your extension:
- Setup tasks
- Store management links
- Admin notes
---
## Using setup tasks
Setup tasks appear on the WooCommerce Admin home screen and prompt a merchant to complete certain steps in order to set up your extension. Adding tasks is a two-step process that requires:
- Registering the task (and its JavaScript) using PHP
- Using JavaScript to build the task, set its configuration, and add it to the task list
### Registering the task with PHP
To register your task as an extended task list item, youll need to hook in to the `woocommerce_get_registered_extended_tasks` filter with a function that appends your task to the array the filter provides.
```php
// Task registration
function my_extension_register_the_task( $registered_tasks_list_items ) {
$new_task_name = 'your_task_name';
if ( ! in_array( $new_task_name, $registered_tasks_list_items, true ) ) {
array_push( $registered_tasks_list_items, $new_task_name );
}
return $registered_tasks_list_items;
}
add_filter( 'woocommerce_get_registered_extended_tasks', 'my_extension_register_the_task', 10, 1 );
```
### Registering the tasks JavaScript
In addition to registering the task name, youll also need to register and enqueue the transpiled JavaScript file containing your task component, its configuration, and its event-handlers. A common way to do this is to create a dedicated registration function that hooks into the `admin_enqueue_scripts` action in WordPress. If you do things this way, you can nest the `add_filter` call for `woocommerce_get_registered_extended_tasks` in this function as well. Below is an annotated example of how this registration might look:
```php
// Register the task list item and the JS.
function add_task_register_script() {
// Check to make sure that this is a request for an Admin page.
if (
! class_exists( 'Automattic\WooCommerce\Admin\Loader' ) ||
! \Automattic\WooCommerce\Admin\Loader::is_admin_page() ||
! Onboarding::should_show_tasks()
) {
return;
}
// Register a handle for your extension's transpiled JavaScript file.
wp_register_script(
'add-task',
plugins_url( '/dist/index.js', __FILE__ ),
array(
'wp-hooks',
'wp-element',
'wp-i18n',
'wc-components',
),
filemtime( dirname( __FILE__ ) . '/dist/index.js' ),
true
);
// Get server-side data via PHP and send it to the JavaScript using wp_localize_script
$client_data = array(
'isComplete' => get_option( 'woocommerce_admin_add_task_example_complete', false ),
);
wp_localize_script( 'add-task', 'addTaskData', $client_data );
// Enqueue the script in WordPress
wp_enqueue_script( 'add-task' );
// Hook your task registration script to the relevant extended tasks filter
add_filter( 'woocommerce_get_registered_extended_tasks', 'my_extension_register_the_task', 10, 1 );
}
```
### Unregistering the task upon deactivation
It is also helpful to define a function that will unregister your task when your extension is deactivated.
```php
// Unregister task.
function my_extension_deactivate_task() {
remove_filter( 'woocommerce_get_registered_extended_tasks', 'my_extension_register_the_task', 10, 1 );
}
register_deactivation_hook( __FILE__, 'my_extension_deactivate_task' );
```
### Adding the task using JavaScript
Once the task has been registered in WooCommerce, you need to build the task component, set its configuration, and add it to the task list. For example, the JavaScript file for a simple task might look something like this:
```js
// External dependencies.
import { addFilter } from '@wordpress/hooks';
import apiFetch from '@wordpress/api-fetch';
import { Card, CardBody } from '@wordpress/components';
// WooCommerce dependencies.
import { getHistory, getNewPath } from '@woocommerce/navigation';
// Event handler for handling mouse clicks that mark a task complete.
const markTaskComplete = () => {
// Here we're using apiFetch to set option values in WooCommerce.
apiFetch( {
path: '/wc-admin/options',
method: 'POST',
data: { woocommerce_admin_add_task_example_complete: true },
} )
.then( () => {
// Set the local `isComplete` to `true` so that task appears complete on the list.
addTaskData.isComplete = true;
// Redirect back to the root WooCommerce Admin page.
getHistory().push( getNewPath( {}, '/', {} ) );
} )
.catch( ( error ) => {
// Something went wrong with our update.
console.log( error );
} );
};
// Event handler for handling mouse clicks that mark a task incomplete.
const markTaskIncomplete = () => {
apiFetch( {
path: '/wc-admin/options',
method: 'POST',
data: { woocommerce_admin_add_task_example_complete: false },
} )
.then( () => {
addTaskData.isComplete = false;
getHistory().push( getNewPath( {}, '/', {} ) );
} )
.catch( ( error ) => {
console.log( error );
} );
};
// Build the Task component.
const Task = () => {
return (
<Card className="woocommerce-task-card">
<CardBody>
Example task card content.
<br />
<br />
<div>
{ addTaskData.isComplete ? (
<button onClick={ markTaskIncomplete }>
Mark task incomplete
</button>
) : (
<button onClick={ markTaskComplete }>
Mark task complete
</button>
) }
</div>
</CardBody>
</Card>
);
};
// Use the 'woocommerce_admin_onboarding_task_list' filter to add a task.
addFilter(
'woocommerce_admin_onboarding_task_list',
'plugin-domain',
( tasks ) => {
return [
...tasks,
{
key: 'example',
title: 'Example',
content: 'This is an example task.',
container: <Task />,
completed: addTaskData.isComplete,
visible: true,
additionalInfo: 'Additional info here',
time: '2 minutes',
isDismissable: true,
onDismiss: () => console.log( 'The task was dismissed' ),
},
];
}
);
```
In the example above, the extension does a few different things. Lets break it down:
#### Handle imports
First, import any functions, components, or other utilities from external dependencies. Weve kept WooCommerce-related dependencies separate from others for the sake of keeping things tidy. In a real-world extension, you may be importing other local modules. In those cases, we recommend creating a visually separate section for those imports as well.
```js
// External dependencies
import { addFilter } from '@wordpress/hooks'``;
import apiFetch from '@wordpress/api-fetch'``;
import { Card, CardBody } from '@wordpress/components'``;
// WooCommerce dependencies
import { getHistory, getNewPath } from '@woocommerce/navigation'``;
```
The `addFilter` function allows us to hook in to JavaScript filters the same way that the traditional PHP call to `add_filter()` does. The `apiFetch` utility allows our extension to query the WordPress REST API without needing to deal with keys or authentication. Finally, the `Card` and `CardBody` are predefined React components that well use as building blocks for our extensions Task component.
#### Create Event Handlers
Next we define the logic for the functions that will handle events for our task. In the example above, we created two functions to handle mouse clicks that toggle the completion status of our task.
```js
const markTaskComplete = () => {
apiFetch( {
path: '/wc-admin/options',
method: 'POST',
data: { woocommerce_admin_add_task_example_complete: true },
} )
.then( () => {
addTaskData.isComplete = true;
getHistory().push( getNewPath( {}, '/', {} ) );
} )
.catch( ( error ) => {
console.log( error );
} );
};
```
In the example above, the event handler uses `apiFetch` to set the `woocommerce_admin_add_task_example_complete` options value to `true` and then updates the components state data and redirects the browser to the Admin root. In the case of an error, were simply logging it to the console, but you may want to implement your own solution here.
The `markTaskIncomplete` function is more or less an inverse of `markTaskComplete` that toggles the tasks completion status in the opposite direction.
#### Construct the component
Next, we create a [functional component](https://reactjs.org/docs/components-and-props.html) that returns our task card. The intermixed JavaScript/HTML syntax were using here is called JSX. If youre unfamiliar with it, you can [read more about it in the React docs](https://reactjs.org/docs/introducing-jsx.html).
```js
const Task = () => {
return (
<Card className="woocommerce-task-card">
<CardBody>
Example task card content.
<br />
<br />
<div>
{ addTaskData.isComplete ? (
<button onClick={ markTaskIncomplete }>
Mark task incomplete
</button>
) : (
<button onClick={ markTaskComplete }>
Mark task complete
</button>
) }
</div>
</CardBody>
</Card>
);
};
```
In the example above, were using the `Card` and `CardBody` components to construct our tasks component. The `div` inside the `CardBody` uses a [JavaScript expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) (`{}`) to embed a ternary operator that uses the components state to determine whether to display the task as complete or incomplete.
#### Configure task and add it to the WooCommerce task list
Finally, well set some configuration values for our task and then use the `addFilter` function to append our task to the WooCommerce Admin Onboarding Task List.
```js
addFilter(
'woocommerce_admin_onboarding_task_list',
'plugin-domain',
( tasks ) => {
return [
...tasks,
{
key: 'example',
title: 'Example',
content: 'This is an example task.',
container: <Task />,
completed: addTaskData.isComplete,
visible: true,
additionalInfo: 'Additional info here',
time: '2 minutes',
isDismissable: true,
onDismiss: () => console.log( 'The task was dismissed' ),
},
];
}
);
```
In the example above, were setting our tasks configuration as we pass it into the filter for simplicity, but in a real-world extension, you might encapsulate this somewhere else for better separation of concerns. Below is a list of properties that the task-list component supports for tasks.
| Name | Type | Required | Description |
|----------------|------------|----------|-------------|
| key | String | Yes | Identifier |
| title | String | Yes | Task title |
| content | String | No | The content that will be visible in the Extensions setup list |
| container | Component | Yes | The task component that will be visible after selecting the item |
| completed | Boolean | Yes | Whether the task is completed or not |
| visible | Boolean | Yes | Whether the task is visible or not |
| additionalInfo | String | No | Additional information |
| time | String | Yes | Time it takes to finish up the task |
| isDismissable | Boolean | No | Whether the task is dismissable or not. If false the Dismiss button wont be visible |
| onDismiss | Function | No | Callback method that its triggered on dismission |
| type | String | Yes | Type of task list item, setup items will be in the store setup and extension in the extensions setup |
---
## Using Store Management Links
When a merchant completes all of the items on the onboarding task list, WooCommerce replaces it with a section containing a list of handy store management links. Discoverability can be a challenge for extensions, so this section is a great way to bring more attention to key features of your extension and help merchants navigate to them.
The store management section has a relatively narrow purpose, so this section does not currently support external links. Instead, it is meant for navigating quickly within WooCommerce.
Adding your own store management links is a simple process that involves:
- Installing dependencies for icon support
- Enqueuing an admin script in your PHP
- Hooking in via a JavaScript filter to provide your link object
### Installing the Icons package
Store management links use the `@wordpress/icons` package. If your extension isnt already using it, youll need to add it to your extensions list of dependencies.
`npm` `install` ` @wordpress``/icons ` `--save`
### Enqueuing the JavaScript
The logic that adds your custom link to the store management section will live in a JavaScript file. Well register and enqueue that file with WordPress in our PHP file:
```js
function custom_store_management_link() {
wp_enqueue_script(
'add-my-custom-link',
plugins_url( '/dist/add-my-custom-link.js', __FILE__ ),
array( 'wp-hooks' ),
10
);
}
add_action( 'admin_enqueue_scripts', 'custom_store_management_link' );
```
The first argument of this call is a handle, the name by which WordPress will refer to the script were enqueuing. The second argument is the URL where the script is located.
The third argument is an array of script dependencies. By supplying the `wp-hooks` handle in that array, were ensuring that our script will have access to the `addFilter` function well be using to add our link to WooCommerces list.
The fourth argument is a priority, which determines the order in which JavaScripts are loaded in WordPress. Were setting a priority of 10 in our example. Its important that your script runs before the store management section is rendered. With that in mind, make sure your priority value is lower than 15 to ensure your link is rendered properly.
### Supply your link via JavaScript
Finally, in the JavaScript file you enqueued above, hook in to the `woocommerce_admin_homescreen_quicklinks` filter and supply your task as a simple JavaScript object.
```js
import { megaphone } from '@wordpress/icons';
import { addFilter } from '@wordpress/hooks';
addFilter(
'woocommerce_admin_homescreen_quicklinks',
'my-extension',
( quickLinks ) => {
return [
...quickLinks,
{
title: 'My link',
href: 'link/to/something',
icon: megaphone,
},
];
}
);
```
---
## Using Admin Notes
Admin Notes are meant for displaying insightful information about your WooCommerce store, extensions, activity, and achievements. Theyre also useful for displaying information that can help with the day-to-day tasks of managing and optimizing a store. A good general rule is to use Admin Notes for information that is:
1. Timely
2. Relevant
3. Useful
With that in mind, you might consider using Admin Notes to celebrate a particular milestone that a merchant has passed, or to provide additional guidance about using a specific feature or flow. Conversely, you shouldnt use Admin Notes to send repeated messages about the same topic or target all users with a note that is only relevant to a subset of merchants. Its okay to use Admin Notes for specific promotions, but you shouldnt abuse the system. Use your best judgement and remember the home screen is meant to highlight a stores most important actionable tasks.
Despite being a part of the new React-powered admin experience in WooCommerce, Admin Notes are available to developers via a standard PHP interface.
The recommended approach for using Admin Notes is to encapsulate your note within its own class that uses the [NoteTraits](https://github.com/woocommerce/woocommerce-admin/blob/831c9ff13a862f22cf53d3ae676daeabbefe90ad/src/Notes/NoteTraits.php) trait included with WooCommerce Admin. Below is a simple example of what this might look like:
```php
<?php
/**
* Simple note provider
*
* Adds a note with a timestamp showing when the note was added.
*/
namespace My\Wonderfully\Namespaced\Extension\Area;
// Exit if this code is accessed outside of WordPress.
defined ( 'ABSPATH' ) || exit;
// Check for Admin Note support
if ( ! class_exists( 'Automattic\WooCommerce\Admin\Notes\Notes' ) ||
! class_exists( 'Automattic\WooCommerce\Admin\Notes\NoteTraits' )) {
return;
}
// Make sure the WooCommerce Data Store is available
if ( ! class_exists( 'WC_Data_Store' ) ) {
return;
}
/**
* Example note class.
*/
class ExampleNote {
// Use the Note class to create Admin Note objects
use Automatic\WooCommerce\Admin\Notes\Note;
// Use the NoteTraits trait, which handles common note operations.
use Automatic\WooCommerce\Admin\Notes\NoteTraits;
// Provide a note name.
const NOTE_NAME = 'my-prefix-example-note';
public static function get_note() {
// Our welcome note will include information about when the extension
// was activated. This is just for demonstration. You might include
// other logic here depending on what data your note should contain.
$activated_time = current_time( 'timestamp', 0 );
$activated_time_formatted = date( 'F jS', $activated_time );
// Instantiate a new Note object
$note = new Automattic\WooCommerce\Admin\Notes\Note();
// Set our note's title.
$note->set_title( 'Getting Started' );
// Set our note's content.
$note->set_content(
sprintf(
'Extension activated on %s.', $activated_time_formatted
)
);
// In addition to content, notes also support structured content.
// You can use this property to re-localize notes on the fly, but
// that is just one use. You can store other data here too. This
// is backed by a longtext column in the database.
$note->set_content_data( (object) array(
'getting_started' => true,
'activated' => $activated_time,
'activated_formatted' => $activated_time_formatted
) );
// Set the type of the note. Note types are defined as enum-style
// constants in the Note class. Available note types are:
// error, warning, update, info, marketing.
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
// Set the type of layout the note uses. Supported layout types are:
// 'banner', 'plain', 'thumbnail'
$note->set_layout( 'plain' );
// Set the image for the note. This property renders as the src
// attribute for an img tag, so use a string here.
$note->set_image( '' );
// Set the note name and source. You should store your extension's
// name (slug) in the source property of the note. You can use
// the name property of the note to support multiple sub-types of
// notes. This also gives you a handy way of namespacing your notes.
$note->set_source( 'inbox-note-example');
$note->set_name( self::NOTE_NAME );
// Add action buttons to the note. A note can support 0, 1, or 2 actions.
// The first parameter is the action name, which can be used for event handling.
// The second parameter renders as the label for the button.
// The third parameter is an optional URL for actions that require navigation.
$note->add_action(
'settings', 'Open Settings', '?page=wc-settings&tab=general'
);
$note->add_action(
'learn_more', 'Learn More', 'https://example.com'
);
return $note;
}
}
function my_great_extension_activate() {
// This uses the functionality from the NoteTraits trait to conditionally add your note if it passes all of the appropriate checks.
ExampleNote::possibly_add_note();
}
register_activation_hook( __FILE__, 'my_great_extension_activate' );
function my_great_extension_deactivate() {
// This uses the functionality from the NoteTraits trait to conditionally remove your note if it passes all of the appropriate checks.
ExampleNote::possibly_delete_note();
}
register_deactivation_hook( __FILE__, 'my_great_extension_deactivate' );
```
### Breaking it down
Lets break down the example above to examine what each section does.
#### Namespacing and feature availability checks
First, were doing some basic namespacing and feature availability checks, along with a safeguard to make sure this file only executes within the WordPress application space.
```php
namespace My\Wonderfully\Namespaced\Extension\Area;
defined ( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Automattic\WooCommerce\Admin\Notes\Notes') ||
! class_exists( 'Automattic\WooCommerce\Admin\Notes\NoteTraits') ) {
return;
}
if ( ! class_exists( 'WC_Data_Store' ) ) {
return;
}
```
#### Using Note and NoteTraits objects
Next, we define a simple class that will serve as a note provider for our note. To create and manage note objects, well import the `Note` and `NotesTraits` classes from WooCommerce Admin.
```php
class ExampleNote {
use Automatic\WooCommerce\Admin\Notes\Note;
use Automatic\WooCommerce\Admin\Notes\NoteTraits;
}
```
#### Provide a unique note name
Before proceeding, create a constant called `NOTE_NAME` and assign a unique note name to it. The `NoteTraits` class uses this constant for queries and note operations.
`const NOTE_NAME = 'my-prefix-example-note';`
#### Configure the notes details
Once youve set your notes name, you can define and configure your note. The `NoteTraits` class will call `self::get_note()` when performing operations, so you should encapsulate your notes instantiation and configuration in a static function called `get_note()` that returns a `Note` object.
```php
public static function get_note() {
// We'll fill this in with logic that instantiates a Note object
// and sets its properties.
}
```
Inside our `get_note()` function, well handle any logic for collecting data our Note may need to display. Our example note will include information about when the extension was activated, so this bit of code is just for demonstration. You might include other logic here depending on what data your note should contain.
```php
$activated_time = current_time( 'timestamp', 0);
$activated_time_formatted = date( 'F jS', $activated_time );
```
Next, well instantiate a new `Note` object.
`$note = new Note();`
Once we have an instance of the Note class, we can work with its API to set its properties, starting with its title.
`$note->set_title( 'Getting Started' );`
Then well use some of the timestamp data we collected above to set the notes content.
```php
$note->set_content(
sprintf(
'Extension activated on %s.', $activated_time_formatted
)
);
```
In addition to regular content, notes also support structured content using the `content_data` property. You can use this property to re-localize notes on the fly, but that is just one use case. You can store other data here too. This is backed by a `longtext` column in the database.
```php
$note->set_content_data( (object) array(
'getting_started' => true,
'activated' => $activated_time,
'activated_formatted' => $activated_time_formatted
) );
```
Next, well set the notes `type` property. Note types are defined as enum-style class constants in the `Note` class. Available note types are _error_, _warning_, _update_, _info_, and _marketing_. When selecting a note type, be aware that the _error_ and _update_ result in the note being shown as a Store Alert, not in the Inbox. Its best to avoid using these types of notes unless you absolutely need to.
`$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );`
Admin Notes also support a few different layouts. You can specify `banner`, `plain`, or `thumbnail` as the layout. If youre interested in seeing the different layouts in action, take a look at [this simple plugin](https://gist.github.com/octaedro/864315edaf9c6a2a6de71d297be1ed88) that you can install to experiment with them.
Well choose `plain` as our layout, but its also the default, so we could leave this property alone and the effect would be the same.
`$note->set_layout( 'plain' );`
If you have an image that you want to add to your Admin Note, you can specify it using the `set_image` function. This property ultimately renders as the `src` attribute on an `img` tag, so use a string here.
`$note->set_image( '' );`
Next, well set the values for our Admin Notes `name` and `source` properties. As a best practice, you should store your extensions name (i.e. its slug) in the `source` property of the note. You can use the `name` property to support multiple sub-types of notes. This gives you a handy way of namespacing your notes and managing them at both a high and low level.
```php
$note->set_source( 'inbox-note-example');
$note->set_name( self::NOTE_NAME );
```
Admin Notes can support 0, 1, or 2 actions (buttons). You can use these actions to capture events that trigger asynchronous processes or help the merchant navigate to a particular view to complete a step, or even simply to provide an external link for further information. The `add_action()` function takes up to three arguments. The first is the action name, which can be used for event handling, the second renders as a label for the actions button, and the third is an optional URL for actions that require navigation.
```php
$note->add_action(
'settings', 'Open Settings', '?page=wc-settings&tab=general'
);
$note->add_action(
'learn_more', 'Learn More', 'https://example.com'
);
```
Finally, remember to have the `get_note()` function return the configured Note object.
`return $note;`
#### Adding and deleting notes
To add and delete notes, you can use the helper functions that are part of the `NoteTraits` class: `possibly_add_note()` and its counterpart `possibly_delete_note()`. These functions will handle some of the repetitive logic related to note management and will also run checks to help you avoid creating duplicate notes.
Our example extension ties these calls to activation and deactivation hooks for the sake of simplicity. While there are many events for which you may want to add Notes to a merchants inbox, deleting notes upon deactivation and uninstallation is an important part of managing your extensions lifecycle.
```php
function my_great_extension_activate() {
ExampleNote::possibly_add_note();
}
register_activation_hook( __FILE__, 'my_great_extension_activate' );
function my_great_extension_deactivate() {
ExampleNote::possibly_delete_note();
}
register_deactivation_hook( __FILE__, 'my_great_extension_deactivate' );
```

View File

@ -0,0 +1,73 @@
# Adding store management links
## Introduction
In the new and improved WooCommerce home screen, there are two points of extensibility for plugin developers that have recently had some attention. The first is the setup task list, allowing you to remind the user of tasks they need to complete and keeping track of their progress for them.
The second is the store management links section. Once the user has completed the setup tasks this will display for them. This section consolidates a list of handy navigation links that merchants can use to quickly find features in WooCommerce.
Discoverability can be hard for users so this can be a great place to bring attention to the features of your plugin and allow users to easily find their way to the key functionality your plugin provides.
Adding your own store management links is a simple process.
## Add your own store management link
Before we start, let's outline a couple of restrictions on this feature.
Right now these links are designed to keep the user within WooCommerce, so it does not support external links.
All the links you add will fall under a special category in the list called "Extensions". There is not currently any support for custom categories.
With those things in mind, let's start.
## Step 1 - Enqueue JavaScript
Adding a store management link will all be done in JavaScript, so the first step is enqueuing your script that will add the store management link. The most important thing here is ensuring that your script runs before the store management link section is rendered.
To ensure that your script runs before ours you'll need to enqueue it with a priority higher than 15. You'll also need to depend on `wp-hooks` to get access to `addFilter`.
Example:
```php
function enqueue_management_link_script() {
wp_enqueue_script( $script_name, $script_url, array( 'wp-hooks' ), 10 );
}
add_action( 'admin_enqueue_scripts', 'enqueue_management_link_script' );
```
## Step 2 - Install @wordpress/icons
To provide an icon of your choice for your store management link, you'll need to install `@wordpress/icons` in your JavaScript project:
```sh
npm install @wordpress/icons --save
```
## Step 3 - Add your filter
Your script will need to use `addFilter` to provide your custom link to the store management link section. And you'll need to import your icon of choice from `@wordpress/icons`. Here's an example:
```js
import { megaphone } from "@wordpress/icons";
import { addFilter } from "@wordpress/hooks";
addFilter(
"woocommerce_admin_homescreen_quicklinks",
"my-extension",
(quickLinks) => {
return [
...quickLinks,
{
title: "My link",
href: "link/to/something",
icon: megaphone,
},
];
}
);
```
Here's a screen shot using our new custom store management link:
![screen shot of custom store management link in wp-admin](https://i.imgur.com/yvXeSya.png)

View File

@ -0,0 +1,394 @@
# How to design a simple extension
## Introduction
Building a WooCommerce extension that provides a first-class experience for merchants and shoppers requires a hybrid development approach combining PHP and modern JavaScript. The PHP handles the lifecycle and server-side operations of your extension, while the modern JavaScript lets you shape the appearance and behavior of its user interface.
## The main plugin file
Your extensions main PHP file is a bootstrapping file. It contains important metadata about your extension that WordPress and WooCommerce use for a number of ecosystem integration processes, and it serves as the primary entry point for your extensions functionality. While there is not a particular rule enforced around naming this file, using a hyphenated version of the plugin name is a common best practice. (i.e. my-extension.php)
## Declaring extension metadata
Your extensions main plugin file should have a header comment that includes a number of important pieces of metadata about your extension. WordPress has a list of header requirements to which all plugins must adhere, but there are additional considerations for WooCommerce extensions:
- The `Author` and `Developer` fields are required and should be set to
either your name or your company name.
- The `Developer URI` field should be your official webpage URL.
- The `Plugin URI` field should contain the URL of the extensions product page in the WooCommerce Marketplace or the extensions official landing page on your website.
- For extensions listed in the WooCommerce Marketplace, to help facilitate the update process, add a `Woo` field and an appropriate value. WooCommerce Marketplace vendors can find this snippet by logging in to the Vendors Dashboard and navigating to `Extensions > All Extensions`. Then, select the product and click Edit product page. This snippet will be in the upper-right-hand corner of the screen.
Below is an example of what the header content might look like for an extension listed in the WooCommerce Marketplace.
```php
/**
* Plugin Name: My Great WooCommerce Extension
* Plugin URI: http://woocommerce.com/products/woocommerce-extension/
* Description: Your extension's description text.
* Version: 1.0.0
* Author: Your Name
* Author URI: http://yourdomain.com/
* Developer: Your Name
* Developer URI: http://yourdomain.com/
* Text Domain: my-extension
* Domain Path: /languages
*
* Woo: 12345:342928dfsfhsf8429842374wdf4234sfd
*
* License: GNU General Public License v3.0
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
```
## Preventing data leaks
As a best practice, your extensions PHP files should contain a conditional statement at the top that checks for WordPress ABSPATH constant. If this constant is not defined, the script should exit.
`defined( 'ABSPATH' ) || exit;`
This check prevents your PHP files from being executed via direct browser access and instead only allows them to be executed from within the WordPress application environment.
## Managing extension lifecycle
Because your main PHP file is the primary point of coupling between your extension and WordPress, you should use it as a hub for managing your extensions lifecycle. At a very basic level, this means handling:
- Activation
- Execution
- Deactivation
Starting with these three broad lifecycle areas, you can begin to break your extensions functionality down further to help maintain a good separation of concerns.
## Handling activation and deactivation
A common pattern in WooCommerce extensions is to create dedicated functions in your main PHP file to serve as activation and deactivation hooks. You then register these hooks with WordPress using the applicable registration function. This tells WordPess to call the function when the plugin is activated or deactivated. Consider the following examples:
```php
function my_extension_activate() {
// Your activation logic goes here.
}
register_activation_hook( __FILE__, 'my_extension_activate' );
```
```php
function my_extension_deactivate() {
// Your deactivation logic goes here.
}
register_deactivation_hook( __FILE__, 'my_extension_deactivate' );
```
## Maintaining a separation of concerns
There are numerous ways to organize the code in your extension. You can find a good overview of best practices in the WordPress Plugin Developer Handbook. Regardless of the approach you use for organizing your code, the nature of WordPress shared application space makes it imperative that you build with an eye toward interoperability. There are a few common principles that will help you optimize your extension and ensure it is a good neighbor to others:
- Use namespacing and prefixing to avoid conflicts with other extensions.
- Use classes to encapsulate your extensions functionality.
- Check for existing declarations, assignments, and implementations.
## The core extension class
As mentioned above, encapsulating different parts of your extensions functionality using classes is an important measure that not only helps with interoperability, but which also makes your code easier to maintain and debug. Your extension may have many different classes, each shouldering some piece of functionality. At a minimum, your extension should define a central class which can handle the setup, initialization and management of a single instance of itself.
## Implementing a singleton pattern
Unless you have a specific reason to create multiple instances of your main class when your extension runs, you should ensure that only one instance exists in the global scope at any time. A common way of doing this is to use a Singleton pattern. There are several ways to go about setting up a singleton in a PHP class. Below is a basic example of a singleton that also implements some of the best practices mentioned above about namespacing and pre-declaration checks:
```php
if ( ! class_exists( 'My_Extension' ) ) :
/**
* My Extension core class
*/
class My_Extension {
/**
* The single instance of the class.
*/
protected static $_instance = null;
/**
* Constructor.
*/
protected function __construct() {
// Instantiation logic will go here.
}
/**
* Main Extension Instance.
* Ensures only one instance of the extension is loaded or can be loaded.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Cloning is forbidden.
*/
public function __clone() {
// Override this PHP function to prevent unwanted copies of your instance.
// Implement your own error or use `wc_doing_it_wrong()`
}
/**
* Unserializing instances of this class is forbidden.
*/
public function __wakeup() {
// Override this PHP function to prevent unwanted copies of your instance.
// Implement your own error or use `wc_doing_it_wrong()`
}
}
endif;
```
Notice that the example class above is designed to be instantiated by calling the static class method `instance()`, which will either return an existing instance of the class or create one and return it. In order to fully protect against unwanted instantiation, its also necessary to override the built-in magic methods `__clone()` and `__wakeup()`. You can implement your own error logging here or use something like `_doing_it_wrong()` which handles error logging for you. You can also use WooCommerces wrapper function `wc_doing_it_wrong()` here. Just be sure your code checks that the function exists first.
## Constructor
The example above includes an empty constructor for demonstration. In a real-world WooCommerce extension, however, this constructor should handle a few important tasks:
- Check for an active installation of WooCommerce & other sibling dependencies.
- Call a setup method that loads other files that your class depends on.
- Call an initialization method that gets your class and its dependencies ready to go.
If we build upon our example above, it might look something like this:
```php
protected function __construct() {
$this->includes();
$this->init();
// You might also include post-setup steps such as showing activation notices here.
}
```
## Loading dependencies
The includes() function above is where youll load other class dependencies, typically via an include or require constructs. A common way of managing and loading external dependencies is to use Composers autoload feature, but you can also load specific files individually. You can read more about how to autoload external dependencies in the Composer documentation. A basic example of a setup method that uses both Composer and internal inclusion is below.
```php
public function includes() {
$loader = include_once dirname( __FILE__ ) . '/' . 'vendor/autoload.php';
if ( ! $loader ) {
throw new Exception( 'vendor/autoload.php missing please run `composer install`' );
}
require_once dirname( __FILE__ ) . '/' . 'includes/my-extension-functions.php';
}
```
## Initialization
The `init()` function above is where you should handle any setup for the classes you loaded in the includes() method. This step is where youll often perform any initial registration with relevant actions or filters. Its also where you can register and enqueue your extensions JavaScripts and stylesheets.
Heres an example of what your initialization method might look like:
```php
private function init() {
// Set up cache management.
new My_Extension_Cache();
// Initialize REST API.
new My_Extension_REST_API();
// Set up email management.
new My_Extension_Email_Manager();
// Register with some-action hook
add_action( 'some-action', 'my-extension-function' );
}
```
There are many different ways that your core class initialization method might look, depending on the way that you choose to architect your extension. The important concept here is that this function serves as a central point for handling any initial registration and setup that your extension requires in order to respond to web requests going forward.
## Delaying initialization
The WordPress activation hook we set up above with register_activation_hook() may seem like a great place to instantiate our extensions main class, and in some cases it will work. By virtue of being a plugin for a plugin, however, WooCommerce extensions typically require WooCommerce to be loaded in order to function properly, so its often best to delay instantiation and initialization until after WordPress has loaded other plugins.
To do that, instead of hooking your instantiation to your extensions activation hook, use the plugins_loaded action in WordPress to instantiate your extensions core class and add its singleton to the $GLOBALS array.
```php
function my_extension_initialize() {
// This is also a great place to check for the existence of the WooCommerce class
if ( ! class_exists( 'WooCommerce' ) ) {
// You can handle this situation in a variety of ways,
// but adding a WordPress admin notice is often a good tactic.
return;
}
$GLOBALS['my_extension'] = My_Extension::instance();
}
add_action( 'plugins_loaded', 'my_extension_initialize', 10 );
```
In the example above, WordPress will wait until after all plugins have been loaded before trying to instantiate your core class. The third argument in add_action() represents the priority of the function, which ultimately determines the order of execution for functions that hook into the plugins_loaded action. Using a value of 10 here ensures that other WooCommerce-related functionality will run before our extension is instantiated.
## Handling execution
Once your extension is active and initialized, the possibilities are wide open. This is where the proverbial magic happens in an extension, and its largely up to you to define. While implementing specific functionality is outside the scope of this guide, there are some best practices to keep in mind as you think about how to build out your extensions functionality.
- Keep an event-driven mindset. Merchants and shoppers who use your extension will be interacting with WooCommerce using web requests, so it can be helpful to anchor your extension to some of the critical flows that users follow in WooCommerce.
- Keep business logic and presentation logic separate. This could be as simple as maintaining separate classes for handling back-end processing and front-end rendering.
- Where possible, break functionality into smaller parts and delegate responsibility to dedicated classes instead of building bloated classes and lengthy functions.
You can find detailed documentation of classes and hooks in the WooCommerce Core Code Reference and additional documentation of the REST API endpoints in the WooCommerce REST API Documentation.
## Handling deactivation
The WordPress deactivation hook we set up earlier in our main PHP file with register_deactivation_hook() is a great place to aggregate functionality for any cleanup that you need to handle when a merchant deactivates your extension. In addition to any WordPress-related deactivation tasks your extension needs to do, you should also account for WooCommerce-related cleanup, including:
- Removing Scheduled Actions
- Removing Notes in the Admin Inbox
- Removing Admin Tasks
## Uninstallation
While its certainly possible to completely reverse everything your extension has created when a merchant deactivates it, its not advisable nor practical in most cases. Instead, its best to reserve that behavior for uninstallation.
For handling uninstallation, its best to follow the guidelines in the WordPress Plugin Handbook.
## Putting it all together
Below is an example of what a main plugin file might look like for a very simple extension:
```php
/**
* Plugin Name: My Great WooCommerce Extension
* Plugin URI: http://woocommerce.com/products/woocommerce-extension/
* Description: Your extension's description text.
* Version: 1.0.0
* Author: Your Name
* Author URI: http://yourdomain.com/
* Developer: Your Name
* Developer URI: http://yourdomain.com/
* Text Domain: my-extension
* Domain Path: /languages
*
* Woo: 12345:342928dfsfhsf8429842374wdf4234sfd
*
* License: GNU General Public License v3.0
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
defined( 'ABSPATH' ) || exit;
/**
* Activation and deactivation hooks for WordPress
*/
function myPrefix_extension_activate() {
// Your activation logic goes here.
}
register_activation_hook( __FILE__, 'myPrefix_extension_activate' );
function myPrefix_extension_deactivate() {
// Your deactivation logic goes here.
// Don't forget to:
// Remove Scheduled Actions
// Remove Notes in the Admin Inbox
// Remove Admin Tasks
}
register_deactivation_hook( __FILE__, 'myPrefix_extension_deactivate' );
if ( ! class_exists( 'My_Extension' ) ) :
/**
* My Extension core class
*/
class My_Extension {
/**
* The single instance of the class.
*/
protected static $_instance = null;
/**
* Constructor.
*/
protected function __construct() {
$this->includes();
$this->init();
}
/**
* Main Extension Instance.
*/
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Cloning is forbidden.
*/
public function __clone() {
// Override this PHP function to prevent unwanted copies of your instance.
// Implement your own error or use `wc_doing_it_wrong()`
}
/**
* Unserializing instances of this class is forbidden.
*/
public function __wakeup() {
// Override this PHP function to prevent unwanted copies of your instance.
// Implement your own error or use `wc_doing_it_wrong()`
}
/**
* Function for loading dependencies.
*/
private function includes() {
$loader = include_once dirname( __FILE__ ) . '/' . 'vendor/autoload.php';
if ( ! $loader ) {
throw new Exception( 'vendor/autoload.php missing please run `composer install`' );
}
require_once dirname( __FILE__ ) . '/' . 'includes/my-extension-functions.php';
}
/**
* Function for getting everything set up and ready to run.
*/
private function init() {
// Examples include:
// Set up cache management.
// new My_Extension_Cache();
// Initialize REST API.
// new My_Extension_REST_API();
// Set up email management.
// new My_Extension_Email_Manager();
// Register with some-action hook
// add_action('some-action', 'my-extension-function');
}
}
endif;
/**
* Function for delaying initialization of the extension until after WooComerce is loaded.
*/
function my_extension_initialize() {
// This is also a great place to check for the existence of the WooCommerce class
if ( ! class_exists( 'WooCommerce' ) ) {
// You can handle this situation in a variety of ways,
// but adding a WordPress admin notice is often a good tactic.
return;
}
$GLOBALS['my_extension'] = My_Extension::instance();
}
```

View File

@ -0,0 +1,5 @@
# Extension Development
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
This section will provide comprehensive guidance on developing extensions for WooCommerce. You will be able to dive into methodologies, best practices, and discover tutorials to create robust, user-friendly extensions that enhance the capabilities of the WooCommerce platform.

View File

@ -0,0 +1,54 @@
# Building blocks for low code builders
## Introduction
This guide provides an introduction to low-code solutions, such as Gutenberg and WooCommerce Store Editing, as well as other page builders and pre-built components for creating WooCommerce stores without custom coding. By understanding and leveraging these tools, low code builders can assemble stores with minimal coding and focus on the design and user experience aspects of their e-commerce websites.
## Audience
This guide is intended for low code builders or anyone with a basic understanding of WordPress and WooCommerce who wants to create online stores without the need for extensive custom coding.
## Prerequisites
To follow this guide, you should have:
1. A basic understanding of WordPress and WooCommerce.
2. A WordPress website with WooCommerce installed and activated.
## Step 1 — Using Gutenberg and WooCommerce Store Editing
Gutenberg is the default block editor in WordPress that allows you to create and edit pages by adding and customizing blocks. WooCommerce has extended Gutenberg's functionality, enabling you to create and customize WooCommerce-specific elements, such as product pages and shop pages.
To use Gutenberg and WooCommerce Store Editing:
1. Ensure your WordPress installation is up-to-date to have the latest version of Gutenberg.
2. Install and activate a Block Theme to enable Store Editing features for WooCommerce.
With Gutenberg and WooCommerce Store Editing, you can create and customize your store's pages using a wide variety of blocks, such as text, images, buttons, and WooCommerce-specific blocks like product grids and shopping carts.
## Step 2 — Exploring alternative page builders
While Gutenberg and WooCommerce Store Editing are powerful options for building low-code WooCommerce stores, you may also consider using other page builders for more advanced features or specific use cases. Some popular page builders compatible with WooCommerce include:
1. Elementor
2. Beaver Builder
3. Divi Builder
4. WPBakery Page Builder
Choose a page builder that fits your needs and budget, then install and activate it on your WordPress website. These page builders typically offer a library of pre-built components that you can use to create a fully functional WooCommerce store without writing custom code.
## Step 3 — Utilizing pre-built components and templates
Many page builders, including Gutenberg, offer pre-built components or blocks that can be easily added to your pages. These components can include design elements like buttons, forms, and image galleries, as well as WooCommerce-specific components like product grids and shopping carts.
Additionally, some page builders and WooCommerce extensions offer pre-built store templates that you can import and customize to create a fully functional online store quickly. These templates can save you time and effort by providing a professionally designed starting point for your store.
To use pre-built components and templates:
1. Open your preferred page builder's editor (Gutenberg or another page builder).
2. Browse through the available components/blocks or templates and find the ones that suit your needs.
3. Add the components to your pages and customize them using the provided settings and options.
## Conclusion
By leveraging low-code solutions like Gutenberg, WooCommerce Store Editing, and other page builders, you can create a fully functional WooCommerce store without the need for custom coding. This guide has introduced you to the basics of using these tools, helping you understand the available options and assemble your store with minimal coding. With the right combination of tools and templates, you can create a professional, user-friendly e-commerce website that meets your business needs.

View File

@ -0,0 +1,102 @@
# WooCommerce Developer Resources
This guide is a great starting point for WooCommerce development. From setting up your first online store to diving deep into advanced features, you'll find what you need here. New to WooCommerce? Start with the basics. Experienced and looking for specific documentation or community discussions? We've got that covered too. Navigate through the sections below to find the resources tailored for you.
## Getting Started
There are a few different ways you might want to get started utilizing WooCommerce. Choose a path below to start developing based on your code comfort level!
### [Installing and setting up WooCommerce](https://woocommerce.com/document/build-online-store/)
If youre brand new to Woo, this guide will show you How to build an online store on WooCommerce. This is where you can learn the ins and outs of how WooCommerce works before you start developing.
### [Extension Development Quick Start](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/create-woo-extension)
This no-configuration quick-start package will scaffold a local copy of an extension template for you. Just open up your terminal and follow the steps in GitHub.
### [Building your first extension](/extension-development/building-your-first-extension.md)
This guide will have you building your first extension with best practices and helpful tips.
### [Marketplace Contribution Guidelines](https://woocommerce.com/document/marketplace-overview/)
Are you hoping to sell your extension in the [Woo Marketplace](https://woocommerce.com/marketplace/)? Read our guidelines to make sure your extension is marketplace-ready.
### [Contributor Guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md)
If you've ever wanted to contribute to the WooCommerce platform as a developer please read our guidelines for contribution first.
### [Contribution Environment Set-Up](https://github.com/woocommerce/woocommerce/tree/trunk)
Visit the WooCommerce home repository on GitHub to learn the first steps to environment set up and platform contribution expectations.
### [Developer tools](/getting-started/developer-tools.md)
Check out our guide to learn more about developer tools, libraries, and utilities.
---
## API & Reference Docs
The resources below contain low-level documentation about features, libraries, extensions, and other pieces of WooCommerce architecture. Use them as a reference when building extensions or integrating with WooCommerce.
## [REST API](https://woocommerce.github.io/woocommerce-rest-api-docs/)
The WooCommerce REST API lets you create, read, update, and delete WooCommerce data using HTTP requests, so you can integrate external applications with WooCommerce and build extensions that make use of asynchronous UI frameworks such as React.
### [Core API](https://docs.woocommerce.com/wc-apidocs/index.html)
The WooCommerce Core API code reference contains information about packages and classes that make up WooCommerce's core functionality.
### [Store API](https://github.com/woocommerce/woocommerce-blocks/tree/trunk/src/StoreApi)
The Store API provides public Rest API endpoints for the development of customer-facing cart, checkout, and product functionality. It follows many of the patterns used in the [WordPress REST API](https://developer.wordpress.org/rest-api/key-concepts/).
### [WooCommerce Blocks](https://github.com/woocommerce/woocommerce-gutenberg-products-block/#documentation)
WooCommerce Blocks give you the ability to integrate WooCommerce with Gutenberg. Use the documentation and resources here as a starting point for developing new block types for WooCommerce.
### [Core Action and Filter Hooks](https://docs.woocommerce.com/wc-apidocs/hooks/hooks.html)
This contains an index of hooks found across all template files, functions, shortcodes, widgets, data stores, and core classes. You can use these hooks to extend the core WooCommerce platform by introducing custom behavior or modifying data that WooCommerce passes around.
### [Shortcodes Included with WooCommerce](https://docs.woocommerce.com/document/woocommerce-shortcodes/)
While WooCommerce Blocks are now the easiest and most flexible way to display your products on posts and pages, WooCommerce still comes with several shortcodes to insert content.
---
## GitHub Repositories
### [WooCommerce on GitHub](https://github.com/woocommerce)
This is the official WooCommerce organization on GitHub. Here youll find the majority of development work that happens on open source projects that the WooCommerce team maintains.
### [Automattic on GitHub](https://github.com/automattic)
This is the official Automattic organization on GitHub. It is where you'll find the majority of development work that happens on open source projects that the Automattic team maintains.
### [WordPress on GitHub](https://github.com/wordpress)
This is the official WordPress organization on GitHub a go-to source for the development work that happens on open source projects that the WordPress community maintains.
---
## Ecosystem Resources
### [WordPress Developer Resources](https://developer.wordpress.org/)
All the resources you need for developing with WordPress. If youre not familiar with the WordPress development ecosystem, this is a great place to start.
### [WooCommerce Community Slack](https://woocommerce.com/community-slack)
Join our community on Slack. We hold regular sessions where we share information and field questions, but you can also connect with other developers to share challenges and ask questions.
### [WooCommerce Community Forum](https://wordpress.org/support/plugin/woocommerce/)
Use this forum to ask questions about WooCommerce. Our WooCommerce Happiness Engineers frequent this forum to answer questions, but there is also a wealth of knowledge that has been captured in these threads over the years.
### [WooCommerce on Reddit](https://www.reddit.com/r/woocommerce/)
Visit the WooCommerce subreddit to ask questions and share tips with other developers.

View File

@ -0,0 +1,89 @@
# WooCommerce Developer Tools
This guide provides an overview of essential tools and libraries for WooCommerce development. It's intended for developers looking to enhance their WooCommerce projects efficiently.
## Table of Contents
- [Productivity Tools](#productivity-tools)
- [Libraries](#libraries)
- [Utilities](#utilities)
### Productivity Tools
Use these resources to get a WooCommerce development environment up and running.
#### [wp-cli](https://wp-cli.org/)
This is the command-line interface for [WordPress](https://wordpress.org/). You can update plugins, configure multisite installations and much more, without using a web browser.
#### [wp-env](https://www.npmjs.com/package/@wordpress/env)
This command-line tool lets you easily set up a local WordPress environment for building and testing plugins and themes. Its simple to install and requires no configuration.
#### [eslint-plugin](https://www.npmjs.com/package/@woocommerce/eslint-plugin)
This is an [ESLint](https://eslint.org/) plugin including configurations and custom rules for WooCommerce development.
#### [e2e-environment](https://www.npmjs.com/package/@woocommerce/e2e-environment)
This is a reusable and extensible end-to-end testing environment for WooCommerce extensions. Additionally, it contains several files to serve as the base for a Docker container and Travis CI setup.
#### [WordPress Scripts](https://www.npmjs.com/package/@wordpress/scripts)
This is a collection of reusable scripts tailored for WordPress development.
---
### Libraries
Use these resources to help take some of the heavy lifting off of fetching and transforming data as well as creating UI elements.
#### API Clients
#### [WooCommerce REST API — JavaScript](https://www.npmjs.com/package/@woocommerce/woocommerce-rest-api)
The official JavaScript library for working with the WooCommerce REST API.
#### [api-fetch](https://www.npmjs.com/package/@wordpress/api-fetch)
This is a utility to make WordPress REST API requests. It's a wrapper around `window.fetch` that includes support for nonces, middleware, and custom fetch handlers.
#### Components
#### [WooCommerce Components](https://www.npmjs.com/package/@woocommerce/components)
This package includes a library of React components that can be used to create pages in the WooCommerce admin area.
#### [WordPress Components](https://www.npmjs.com/package/@wordpress/components)
This packages includes a library of generic WordPress components that can be used for creating common UI elements shared between screens and features of the WordPress dashboard.
---
### Utilities
#### [CSV Export](https://www.npmjs.com/package/@woocommerce/csv-export)
A set of functions to convert data into CSV values, and enable a browser download of the CSV data.
#### [Currency](https://www.npmjs.com/package/@woocommerce/currency)
A collection of utilities to display and work with currency values.
#### [Data](https://www.npmjs.com/package/@woocommerce/data)
Utilities for managing the WooCommerce Admin data store.
#### [Date](https://www.npmjs.com/package/@woocommerce/date)
A collection of utilities to display and work with date values.
#### [Navigation](https://www.npmjs.com/package/@woocommerce/navigation)
A collection of navigation-related functions for handling query parameter objects, serializing query parameters, updating query parameters, and triggering path changes.
#### [Number](https://www.npmjs.com/package/@woocommerce/number)
A collection of utilities to properly localize numerical values in WooCommerce.

View File

@ -0,0 +1,5 @@
# Getting-started
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
Jumpstart your journey with WooCommerce. This category will cover the basics and essentials, from installation to initial setup, ensuring you have a solid foundation to build upon.

View File

@ -0,0 +1,5 @@
# High Performance Order Storage
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
This section is where you can learn about High-Performance Order Storage (HPOS): a new database storage for orders to allow effortless scaling for large and high growth stores.

View File

@ -0,0 +1,67 @@
# Coding standards for the code snippets within the WooCommerce documentation
## Position of hooks
Position hooks below the function call, as this follows the common pattern in the WordPress and WooCommerce ecosystem.
### Example
```php
/**
* Add custom message.
*/
function YOUR_PREFIX_custom_message() {
echo 'This is a custom message';
}
add_action( 'wp_footer', 'YOUR_PREFIX_custom_message' );
```
## Prefixing function calls
Use a consistent prefix for all function calls. For the code snippets in this repo, use the prefix `YOUR_PREFIX`.
### Example
```php
/**
* Add custom discount.
*/
function YOUR_PREFIX_custom_discount( $price, $product ) {
return $price * 0.9; // 10% discount
}
add_filter( 'woocommerce_product_get_price', 'YOUR_PREFIX_custom_discount', 10, 2 );
```
## Translatable texts and text domains
Make all plain texts translatable, and use a consistent text domain. This aligns with the best practices for internationalisation. For the code snippets in this repo, use the textdomain `YOUR-TEXTDOMAIN`.
### Example
```php
/**
* Add custom message.
*/
function YOUR_PREFIX_welcome_message() {
echo __( 'Welcome to our website', 'YOUR-TEXTDOMAIN' );
}
add_action( 'wp_footer', 'YOUR_PREFIX_welcome_message' );
```
## Use of function_exists()
Wrap all function calls in a `function_exists()` call to prevent errors due to potential function redeclaration.
### Example
```php
/**
* Add thumbnail support.
*/
if ( ! function_exists( 'YOUR_PREFIX_theme_setup' ) ) {
function YOUR_PREFIX_theme_setup() {
add_theme_support( 'post-thumbnails' );
}
}
add_action( 'after_setup_theme', 'YOUR_PREFIX_theme_setup' );
```

View File

@ -0,0 +1,321 @@
# WooCommerce grammar, punctuation and capitalization guide
Following grammar, punctuation and style guidelines helps keep our presentation consistent. Users have a better experience if they know what to expect and where to find the information they need.
## Basics
**Be democratic**. Some people read every word. Some scan and search or prefer video. Help everyone.
**Be focused**. Lead with the most important information in sentences, paragraphs, and sections.
**Be concise**. Use plain language and brief sentences.
**Be consistent**. Follow our guidelines and style tips.
**Be specific**. Communicate crystal clear. Trim the fat.
## Guidelines
### Abbreviations and acronyms
Spell out the full version on first mention with abbreviation or acronym in parentheses. Use the short version on second and consecutive mentions.
- First use: Payment Card Industry Data Security Standard (PCI-DSS)
- Second use: PCI-DSS
If the abbreviation or acronym is widely known, use it as is. For example: API, FAQ, HTML, PHP, SQL, SSL.
### Active voice
With active voice, the subject in the sentence performs the action. With passive voice, the subject in the sentence has the action done unto it.
- Active: Jon downloaded his extension files.
- Passive: The extension files were downloaded by Jon.
### Capitalization
Cases when we capitalize:
- Blog post and documentation article titles: First word.
- Documentation headings (h2): Use sentence case (not title case) for docs titles and subheadings.
- Product names: Every word except prepositions and conjunctions.
- Sentences: First word.
- Unordered/Bulleted lists First word of each entry.
Cases when we use lower case:
- “ecommerce” (not “eCommerce”)
- email address — info@woocommerce.com
- website URL — developer.woocommerce.com
### Contractions
Use with discretion. Contractions, such as Im and theres, give writing an informal and conversational feel, but may be inappropriate if content is being translated. For example, sometimes the not in dont is ignored by online translators.
### Emoji
Emoji can add subtle emotion and humor or bring visual attention to your content. Use rarely and intentionally.
### Numbers
Spell out a number at the start of a sentence, and spell out numbers one through nine in all cases. Use numerals in all other cases.
- Ten products will launch in June. Not: 10 products will launch in June.
- Lance ran a marathon and won third place in his age group.
- I bought five hammers and 21 types of nails for the building project.
- There were 18 kinds of beer on tap at the pub.
Use a comma for numbers with more than three digits: 41,500, 170,000, 1,000,000 or 1 million.
#### Currency
Use currency codes and not only the symbol/sign when specifying dollars. Whole amounts need not have a decimal and two places.
- USD $20
- CAD $19.99
- AUD $39.50
When writing about other currencies, use the symbol/sign.
- €995
- ¥5,000
- £18.99
#### Dates
Spell out the day of the week and month, using the format:
- Monday, December 12, 2016
#### Decimals
Use decimal points when a number is difficult to convert to a fraction, such as 3.141 or 98.5 or 0.29.
#### Fractions
Spell out fractions: one-fourth
#### Percent
Spell out the word percent. Dont use % symbol unless space is limited, e.g., for use on social media.
#### Phone numbers
Use hyphens without spaces between numbers, not parentheses or periods. Use a [country code](https://countrycode.org/) for all countries.
- +1-555-867-5309
- +34-902-1899-00
#### Range and span
Use a hyphen to indicate a range or span of numbers: 20-30 days.
#### Temperature
Use the degree symbol and the capital C abbreviation for Celsius and capital F abbreviation for Fahrenheit.
- 27°C
- 98°F
#### Times
Use numbers and am or pm with a space and without periods.
- 7:00 am
- 7:30 pm
Use a hyphen between times to indicate a time period in am or pm. Use to if the time period spans am and pm.
- 7:00-9:00 am and 7:00 am to 10:30 pm
Specify a time zone when writing about an event with potential attendees worldwide. Automattic uses Coordinated Universal Time (UTC).
Abbreviate U.S. time zones:
- Eastern time: EDT or EST
- Central time: CDT or CST
- Mountain time: MDT or MST
- Pacific time: PDT or PST
#### Years
Abbreviate decades
- 80s and 90s
- 1900s and 1890s
### Punctuation
#### Ampersands
Ampersands need only be used when part of an official company/brand name. Should not be substituted for and.
- Ben & Jerrys
- Andre, Timo, and Donny went to a football game at Camp Nou.
#### Apostrophes
An apostrophe makes a word possessive. If a word already ends in s and is singular, add an s. If a word ends in s and is plural, add an apostrophe.
- A teammate borrowed Sams bike.
- A teammate borrowed Chriss bike.
- Employees hid the office managers pens.
These are possessives: FAQs questions, HEs weekly rotation. These are plural: FAQs and HEs.
#### Colons
Use a colon to create a list.
- Aaron ordered three kinds of donuts: glazed, chocolate, and pumpkin.
#### Commas
Use a serial comma, also known as an Oxford comma, when compiling a list.
- Jinny likes sunflowers, daisies, and peonies.
Use common sense for other cases. Read the sentence out loud, and use a comma where clarity or pause may be needed.
#### Dashes and hyphens
Use a hyphen without spaces on either side to link words, or indicate a span or range.
- first-time user
- Monday-Friday
Use an em dash — without spaces on either side to indicate an aside.
Use a true em dash, not hyphens or .
- Multivariate testing—just one of our new Pro features—can help you grow your business.
- Austin thought Brad was the donut thief, but he was wrong—it was Lain.
#### Ellipses
Ellipses … can be used to indicate an indefinite ending to a sentence or to show words are omitted when used in brackets […] Use rarely.
#### Exclamation points
Use an exclamation point rarely and use only one.
Exclamation points follow the same placement convention explained in Periods.
#### Periods
Periods should be:
- Inside quotation marks
- Outside parentheses when the portion in parentheses is part of a larger sentence
- Inside parentheses when the part in parentheses can stand on its own
Examples
- Jake said, “I had the best day ever.”
- She went to the supermarket (and to the nail salon).
- My mom loves pizza and beer. (Beer needs to be cold and dark.)
#### Question marks
Question marks follow the same placement convention explained in Periods.
#### Quotation marks
Periods and commas go within quotation marks. Question marks within quotes follow logic—if the question mark is part of the quotation, it goes within. If youre asking a question that ends with a quote, it goes outside the quote.
Use single quotation marks for quotes within quotes.
- Who sings, “All These Things That Ive Done”?
- Brandon Flowers of The Killers said, “I was inspired and on a roll when I wrote, I got soul, but Im not a soldier.’”
#### Semicolons
Semicolons can be used to join two related phrases.
- Their debut solo album hit the Top 10 in 20 countries; it was #1 in the UK.
### People, places, and things
#### Company names and products
Use brand identity names and products as written on official websites.
- Nestlé
- Pull&Bear
- UE Boom
Refer to a company or product as it (not they).
- WooCommerce is, and not WooCommerce are.
#### File extensions
A file extension type should be all uppercase without periods. Add a lowercase s to make plural.
- HTML
- JPEG
- PDF
A specific file should have a lowercase extension type:
- dancingcat.gif
- SalesReport2016.pdf
- firethatcannon.mp3
#### Names and titles
First mention of a person should include their first and last name. Second and consecutive mentions can use first name only.
Capitalize job titles, the names of teams, and departments.
- Happiness Engineers or HEs
- Team Apollo
- Legal
#### Pronouns
Use he/him/his and she/her/her as appropriate. Dont use “one” as a pronoun. Use they/them/their if gender is unknown or when referring to a group.
#### Quotations
Use present tense when quoting someone.
- “I love that WooCommerce is free and flexible,” says Brent Jamison.
#### Schools
The first time you mention a school, college, or university in a piece of writing, refer to it by its full official name. On all other mentions, use its more common abbreviation.
- Georgia Institute of Technology, Georgia Tech
- Georgia State University, GSU
#### States, cities, and countries
Spell out all city and state names. Dont abbreviate city names.
On first mention, write out United States. For further mentions, use U.S. The same applies to other countries or federations with a common abbreviation, such as European Union (EU) and United Kingdom (UK).
#### URLs and websites
Capitalize the names of websites and web publications. Dont italicize.
Avoid writing out URLs; omit `http://www` when its necessary.
### Slang and jargon
Write in plain English. Text should be universally understood, with potential for translation. Briefly define technical terms when needed.
### Text formatting
Use italics to indicate the title of a book, movie, or album.
- The Oren Klaff book Pitch Anything is on sale for USD $5.99.
Avoid:
- Underline formatting
- A mix of italic, bold, caps, and underline
Left-align text, never center or right-aligned.
Leave one space between sentences, never two.

View File

@ -0,0 +1,89 @@
# Performance optimization for WooCommerce stores
## Introduction
This guide covers best practices and techniques for optimizing the performance of WooCommerce stores, including caching, image optimization, database maintenance, code minification, and the use of Content Delivery Networks (CDNs). By following these recommendations, developers can build high-performing WooCommerce stores that provide a better user experience and contribute to higher conversion rates.
## Audience
This guide is intended for developers who are familiar with WordPress and WooCommerce and want to improve the performance of their online stores.
## Prerequisites
To follow this guide, you should have:
1. A basic understanding of WordPress and WooCommerce.
2. Access to a WordPress website with WooCommerce installed and activated.
## Step 1 — Implement caching
Caching plays a crucial role in speeding up your WooCommerce store by serving static versions of your pages to visitors, reducing the load on your server. There are several ways to implement caching for your WooCommerce store:
### Server-Side caching
Enable server-side caching through your hosting provider or by using server-level caching solutions like Varnish, NGINX FastCGI Cache, or Redis.
### WordPress caching plugins
Install and configure a WordPress caching plugin, such as WP Rocket, W3 Total Cache, or WP Super Cache. These plugins can help you set up page caching, browser caching, and object caching for your WooCommerce store.
### WooCommerce-Specific caching
Ensure that your caching solution is configured correctly for WooCommerce, allowing dynamic content such as cart and checkout pages to remain uncached. Some caching plugins, like WP Rocket, include built-in support for WooCommerce caching.
## Step 2 — Optimize images
Optimizing images can significantly improve your store's performance by reducing the size of image files without compromising quality. To optimize images for your WooCommerce store:
1. Use the right image format: Choose an appropriate format for your images, such as JPEG for photographs and PNG for graphics with transparency.
2. Compress images: Use an image compression tool like TinyPNG or ShortPixel to reduce file sizes before uploading them to your store.
3. Enable lazy loading: Lazy loading delays the loading of images until they're needed, improving initial page load times. Many caching plugins and performance optimization plugins offer built-in lazy loading options.
4. Use responsive images: Ensure that your theme and plugins serve appropriately sized images for different devices and screen resolutions.
## Step 3 — Minify and optimize code
Minifying and optimizing your store's HTML, CSS, and JavaScript files can help reduce file sizes and improve page load times. To minify and optimize code for your WooCommerce store:
1. Use a plugin: Install a performance optimization plugin like Autoptimize, WP Rocket, or W3 Total Cache to minify and optimize your store's HTML, CSS, and JavaScript files.
2. Combine and inline critical CSS: Where possible, combine and inline critical CSS to reduce the number of requests and improve page load times.
3. Defer non-critical JavaScript: Defer loading of non-critical JavaScript files to improve perceived page load times.
## Step 4 — Use a content delivery network (CDN)
A Content Delivery Network (CDN) can help speed up your WooCommerce store by serving static assets like images, CSS, and JavaScript files from a network of servers distributed across the globe. To use a CDN for your WooCommerce store:
1. Choose a CDN provider: Select a CDN provider like Cloudflare, Fastly, or Amazon CloudFront that fits your needs and budget.
2. Set up your CDN: Follow your chosen CDN provider's instructions to set up and configure the CDN for your WooCommerce store.
## Step 5 — Optimize database
Regularly optimizing your WordPress database can help improve your WooCommerce store's performance by removing unnecessary data and optimizing database tables. To optimize your database:
1. Use a plugin: Install a database optimization plugin like WP-Optimize, WP-Sweep, or Advanced Database Cleaner to clean up and optimize your WordPress database.
2. Remove unnecessary data: Regularly delete spam comments, post revisions, and expired transients to reduce database clutter.
3. Optimize database tables: Use the database optimization plugin to optimize your database tables, improving their efficiency and reducing query times.
## Step 6 — Choose a high-performance theme and plugins
The theme and plugins you choose for your WooCommerce store can have a significant impact on performance. To ensure your store runs efficiently:
1. Select a lightweight, performance-optimized theme: Choose a theme specifically designed for WooCommerce that prioritizes performance and follows best coding practices.
2. Evaluate plugin performance: Use tools like Query Monitor or WP Hive to analyze the performance impact of the plugins you install, and remove or replace those that negatively affect your store's performance.
## Step 7 — Enable GZIP compression
GZIP compression can help reduce the size of your store's HTML, CSS, and JavaScript files, leading to faster page load times. To enable GZIP compression:
1. Use a plugin: Install a performance optimization plugin like WP Rocket, W3 Total Cache, or WP Super Cache that includes GZIP compression options.
2. Configure your server: Alternatively, enable GZIP compression directly on your server by modifying your .htaccess file (for Apache servers) or nginx.conf file (for NGINX servers).
## Step 8 — Monitor and analyze performance
Continuously monitor and analyze your WooCommerce store's performance to identify potential bottlenecks and areas for improvement. To monitor and analyze performance:
1. Use performance testing tools: Regularly test your store's performance using tools like Google PageSpeed Insights, GTmetrix, or WebPageTest.
2. Implement performance monitoring: Install a performance monitoring plugin like New Relic or use a monitoring service like Uptime Robot to keep track of your store's performance over time.
## Conclusion
By following these best practices and techniques for performance optimization, you can build a high-performing WooCommerce store that offers a better user experience and contributes to higher conversion rates. Continuously monitor and analyze your store's performance to ensure it remains optimized as your store grows and evolves.

View File

@ -0,0 +1,5 @@
# Quality and Best Practices
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
Ensuring the quality of your WooCommerce projects is essential. This section will delve into quality exoectations, best practices, coding standards, and other methodologies to ensure your projects stand out in terms of reliability, efficiency, user experience, and more.

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 MiB

View File

@ -0,0 +1,33 @@
# Authenticating
A vendor admin user is required to be able to view and execute tests using QIT.
## Dashboard
For the QIT dashboard:
- Log in to WooCommerce.com with your vendor account.
- Click on `Vendor Dashboard` button to be taken to your vendor dashboard, which can be found on the My Account page once you've logged in:
![go-to-dashboard](qit-dashboard/_media/go-to-dashboard.png)
- Don't see this button? You may not be the vendor admin on the account. Reach out to someone else in the organization (usually the person that handles uploading the extension for publishing) to see if they have access.
> Even if you don't have access in the UI, you'll still be able to leverage the CLI. Please see the section below for a guide on how to do this.
## CLI
In order to be able to use the CLI tool, you'll need to be a vendor admin that can create a [WordPress application password](https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/) in order to authenticate. Follow the steps below to authenticate with the QIT CLI:
- [Download](https://github.com/woocommerce/qit-cli/releases/latest/) the latest version of QIT CLI and [Install it](qit-cli/getting-started#installing-qit)
- Depending on how you've installed the QIT CLI, run `./vendor/bin/qit partner:add`
- Follow the steps to generate an application password
- Enter the application password and username in the CLI
## Giving access to other developers to use the QIT
Sometimes you want to give access to other developers in your organization to run tests using the QIT, but you might not want to give them access to the WooCommerce.com account that can manage the extension in the marketplace, as it gives developers access they don't need, such as managing your extensions in the marketplace, etc.
Luckily, you can share with them the QIT Application Password, as these application passwords are restricted to only run and view test runs. They are special application passwords with limited access that can only run and view tests using QIT.
> Our roadmap includes plans to add the ability to create and revoke QIT-specific access tokens to make this particular workflow and use-case more manageable.

View File

@ -0,0 +1,11 @@
# Contact Us
We're here to help! If you have any questions, comments, or concerns, please don't hesitate to reach out to us. You can contact us by sending an email to [qit@woocommerce.com](mailto:qit@woocommerce.com).
## Report Issues
If you encounter any issues with our QIT CLI tool, please let us know by opening an issue on our GitHub repository. You can access the repository here: [https://github.com/woocommerce/qit-cli/issues](https://github.com/woocommerce/qit-cli/issues)
## Provide Feedback
We value your feedback and suggestions. Please take a moment to let us know how we're doing. Your input will help us continue to improve.

View File

@ -0,0 +1,98 @@
# GitHub Workflows Example
The QIT GitHub Workflows are examples of integrating the Quality Insights Toolkit into GitHub. You can delegate tests to the QIT and integrate it as part of your PR approval process, when a release is created, and more.
For more information on how [GitHub Actions](https://docs.github.com/en/actions) work, please see the official GitHub documentation.
The examples below can be tweaked based on your needs, and use a fictional `woocommerce-product-feeds` extension to run the tests against. There's a few [GitHub Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) that need to be configured for this flow (feel free to rename these to whatever makes the most sense for you and your team):
- `PARTNER_USER`: Your WooCommerce.com username.
- `PARTNER_SECRET`: Your [WordPress Application Password](https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/).
## Activation test example
```yaml
name: QIT Activation Test
on:
workflow_dispatch:
pull_request:
permissions:
pull-requests: write
jobs:
qit_activation:
name: QIT Activation
runs-on: ubuntu-20.04
env:
NO_COLOR: 1
QIT_DISABLE_ONBOARDING: yes
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build your plugin zip (Example)
run: zip -r my-extension.zip my-extension
- name: Install QIT via composer
run: composer require woocommerce/qit-cli
- name: Add Partner
run: ./vendor/bin/qit partner:add --user='${{ secrets.PARTNER_USER }}' --application_password='${{ secrets.PARTNER_SECRET }}'
- name: Run Activation Test
id: run-activation-test
run: ./vendor/bin/qit run:activation my-extension --zip=my-extension.zip --wait > result.txt
- uses: marocchino/sticky-pull-request-comment@v2
if: failure()
with:
header: QIT Activation Result
recreate: true
path: result.txt
```
## Security test example
```yaml
name: QIT Security Test
on:
workflow_dispatch:
pull_request:
permissions:
pull-requests: write
jobs:
qit_security:
name: QIT Security Test
runs-on: ubuntu-20.04
env:
NO_COLOR: 1
QIT_DISABLE_ONBOARDING: yes
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build your plugin zip (Example)
run: zip -r my-extension.zip my-extension
- name: Install QIT via composer
run: composer require woocommerce/qit-cli
- name: Add Partner
run: ./vendor/bin/qit partner:add --user='${{ secrets.PARTNER_USER }}' --application_password='${{ secrets.PARTNER_SECRET }}'
- name: Run Activation Test
id: run-activation-test
run: ./vendor/bin/qit run:security my-extension --zip=my-extension.zip --wait > result.txt
- uses: marocchino/sticky-pull-request-comment@v2
if: failure()
with:
header: QIT Security Result
recreate: true
path: result.txt
```
## Notes
### Required permissions
Depending on how your repository is set up, you may need to adjust the permissions step to the following:
```yaml
permissions:
contents: read
pull-requests: write
```
### Verify the zip is built correctly
If you see any failures in the pipeline, such as an activation test that fails without a result, it could be due to the way that the GitHub action is building the zip file. Double check that the zip file created by the workflow doesn't add in an extra folder to the file structure. To verify that the zip is valid to be used by QIT, you can test uploading it in the WordPress admin screen under `Plugins > Add new` and test uploading and activating the zip file. If it works, then it will work with QIT.

View File

@ -0,0 +1,50 @@
# Introduction
The Quality Insights Toolkit (QIT) is an initiative by WooCommerce designed to provide extension developers in the [Woo Marketplace](https://woocommerce.com/products/) with managed automated tests.
To ensure that all extensions in the Woo Marketplace meet our quality standards, we run a series of automated tests. As part of our commitment to supporting developers, we also provide ways for developers to easily integrate these tests into their development workflows.
## Quick Start Guide
1. `composer install woocommerce/qit-cli`
2. `./vendor/bin/qit` to authenticate with your WooCommerce.com developer account.
## Benefits for You as a Developer
- You can enjoy out-of-the-box tests for all the extensions you sell on the Marketplace
- Your extensions will undergo continuous testing, including against new releases of PHP, WooCommerce, and WordPress
- You can have increased peace of mind knowing that you'll be alerted if the tests catch anything with a future release or an edge case
- You can take advantage of integration with GitHub Workflows
- You can easily integrate the testing tool with your development workflow using the terminal tool
- You can run some tests with other extensions active at the same time, including those that may be known to cause issues when activated alongside yours.
## Benefits for Users of the WooCommerce Ecosystem
- Users can enjoy increased reliability when updating WooCommerce extensions on the Marketplace
- Users can have confidence to update PHP, WordPress, or WooCommerce versions without fear of breaking their extensions
- There will be less potential security issues for users of the WooCommerce Ecosystem
- Users can have more assurance that all extensions will continue to work as expected when activated alongside each other, ensuring a seamless experience.
## Who is this toolkit for?
This toolkit is for extension developers who are selling their extensions on the WooCommerce Marketplace.
## What types of tests are available?
- End-to-end
- API
- Activation
- Security
- PHPStan
## How can I use the toolkit?
Tests are executed automatically by us whenever you publish a new version of your extension on the WooCommerce Marketplace. You can also run tests manually using the following tools:
- [Dashboard](qit-dashboard/getting-started.md): A UI-based test runner and test results viewer, available in your WooCommerce dashboard.
- [CLI](qit-cli/getting-started.md): A CLI tool that allows you to run and view tests, including against development builds.
- [GitHub Workflows](github-workflows.md): GitHub workflow files that allow running tests regularly with QIT as part of a GitHub development workflow.
## Why does this toolkit exist?
The primary goal of these tools is to assist extension developers to easily integrate a variety of tests into their development workflows, and promote and encourage quality around WooCommerce extensions available in the marketplace.

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 KiB

View File

@ -0,0 +1,52 @@
# Getting started
The QIT CLI is a command line interface tool that allows you to run automated tests in the cloud against extensions available in the WooCommerce Marketplace, powered by the Quality Insights Toolkit test runner.
![run-e2e](_media/run-e2e.png)
## Requirements
- PHP 7.2.5 or higher
- Unix environment (Linux, macOS, Windows WSL)
- Composer
## Installing QIT
You can install QIT in three different ways:
### Per Project
1. Run `composer require woocommerce/qit-cli --dev`
2. Execute `./vendor/bin/qit` to authenticate with your WooCommerce.com Partner Developer account.
### Globally Using Composer
1. Run `composer global require woocommerce/qit-cli`
2. Execute `qit` to authenticate with your WooCommerce.com Partner Developer account. Ensure that the Composer bin folder is in your PATH. [Example](https://stackoverflow.com/a/64545124).
### Globally Using `wget`
(Pro Tip: Opting for the Composer installation method simplifies the process of updating QIT in the future 😉)
1. Run `wget https://github.com/woocommerce/qit-cli/raw/trunk/qit`
2. Execute `chmod +x qit`
3. Move the file to a directory in your PATH, such as `sudo mv qit /usr/local/bin/qit`
4. Run `qit` to authenticate with your WooCommerce.com Partner Developer account.
## Updating QIT
Updating QIT will depend on how you installed it.
### If you installed it per-project
1. Run `composer update woocommerce/qit-cli`
### If you installed it globally using Composer
1. Go to your global composer directory `cd $(composer global config bin-dir --absolute)`
2. Run `composer update woocommerce/qit-cli`
#### If you installed it with `wget`
1. Delete the old binary `which qit` then `rm` it.
2. Repeat the installation steps.

View File

@ -0,0 +1,78 @@
# Running tests
The QIT CLI allows running tests against both extensions that are published and available for sale in the WooCommerce Extension Store as well as against development builds of an extension.
## Choosing the type of test to run
The commands to run tests are formatted as `run:<test-type>`. The CLI supports all of the current [test types](test-types.md) using the following commands:
- End-to-end
- API
- Activation
- Security
- PHPStan
For example, to run end-to-end tests, you'd run the following command: `./vendor/bin/qit run:e2e my-plugin-slug`.
## Testing a published extension
For running any kind of tests, you'll need the slug for the given extension you want to run the tests against. For example, to run end-to-end tests against an extension with the slug `my-extension`, you'd run the following command:
```shell
qit run:e2e my-extension
```
This will run the [WooCommerce Core E2E Test Suite](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e-pw) against the WooCommerce extension with slug `my-extension` using the latest stable versions of WordPress and WooCommerce.
Since the tests are executed in the cloud, you can even close the terminal if you wish. You can see the result of this test after a while running `qit list-tests`, or `qit get 123`, where `123` is the test run ID. When the test finishes, the status will be updated to `Success`, `Warning`, or `Failed`. For more details on these commands, please see [Useful Commands](cli/useful-commands.md).
## Testing development builds
The QIT CLI supports testing development builds of extensions, so you can run any of the [test types](../test-types.md) against an unpublished version of your extension in the same QIT environment before publishing it to the WooCommerce Store.
!> Make sure the zipped version is a valid plugin. As this is installed on a test WordPress site, an invalid plugin will fail to install and cause the tests to fail.
Once you have a zipped up version of your extension you'd like to test with, use the `--zip` argument to pass in a path to the zip file containing your extension.
For example, to run end-to-end tests against your local build, you'd run the following command:
```shell
qit run:e2e my-extension --zip=my-extension.zip
```
## Seeing test runs and their results
Since the tests are executed in the cloud, you can even close the terminal. You can see the result of this test after a while by running one of the two commands below:
- Run `qit list-tests` to see a list of test runs.
- Run `qit get 123` to get more details about a specific test run, where `123` is the test run ID.
- Run `qit open 123` to open the report for test run `123` in the browser.
When the test finishes, the status will be updated to `Success`, `Warning`, or `Failed`. For more details on what these commands show, please see [Useful Commands](useful-commands.md).
## Specifying WooCommerce and WordPress versions
The QIT CLI supports testing against different versions of WooCommerce and WordPress. There are two arguments available to use, depending on your needs:
- `--woocommerce_version`
- `--wordpress_version`
For example, to run activation tests against the RC 2 version of WooCommerce 7.0.0 and WordPress 6.0.1, you can run the following command:
`qit run:activation my-extension --woocommerce_version=7.0.0-rc.2 --wordpress_version=6.0.1`
?> If either these arguments are not supplied, then the tests will just run against the current versions of WooCommerce and WordPress.
For example, if you wanted to run against the latest WordPress but use a different version of WooCommerce, you can do so:
`qit run:e2e my-extension --woocommerce_version=6.0.0`
## Using optional features
You can also enable option features in your test environment by using the `--optional_features` flag. For example, to run an activation test with the High Performance Order Storage feature enabled, you can run the following command:
`qit run:activation my-extension --optional_features=hpos`
Currently, QIT supports enabling the following optional features:
- `hpos`: [High Performance Order Storage (HPOS)](https://developer.woocommerce.com/roadmap/high-performance-order-storage/)

View File

@ -0,0 +1,127 @@
# Scripting
QIT CLI allows you to create robust scripts that can optimize your development workflow. Here is an example of a bash script used for authentication and running tests against a development build.
## Directory Structure
For this example, we will assume the following directory structure. This can be in the same folder where you develop your plugin or in its own directory:
- .env
- bin/qit.sh
- vendor/bin/qit
- build/extension.zip _(Assuming this is created by `npm run build`)_
## Environment Variables (.env)
Create a `.env` file in the root directory of your project and add your QIT user and application password:
```bash
QIT_USER=foo
QIT_APP_PASS=bar
```
## Bash Script (bin/qit.sh)
This script authenticates the QIT_USER and then runs security tests against the extension build. If the 'partner:remove' command is not available, it adds a partner using `QIT_USER` and `QIT_APP_PASSWORD`. For more information on how authentication works with QIT, see our [documentation around authentication](https://woocommerce.github.io/qit-documentation/#/authenticating).
```bash
#!/bin/bash
set -x # Verbose mode.
# Check if QIT_USER and QIT_APP_PASSWORD are set and not empty
if [[ -z "${QIT_USER}" ]] || [[ -z "${QIT_APP_PASSWORD}" ]]; then
echo "QIT_USER or QIT_APP_PASSWORD environment variables are not set or empty. Please set them before running the script."
exit 1
fi
# When QIT is run for the first time, it will prompt for onboarding. This will disable that prompt.
export QIT_DISABLE_ONBOARDING=yes
# If QIT_BINARY is not set, default to ./vendor/bin/qit
QIT_BINARY=${QIT_BINARY:-./vendor/bin/qit}
# Check if 'partner:remove' command is in the list of available commands
if ! $QIT_BINARY list | grep -q 'partner:remove'; then
echo "Adding partner with QIT_USER and QIT_APP_PASSWORD..."
$QIT_BINARY partner:add --user="${QIT_USER}" --application_password="${QIT_APP_PASSWORD}"
if [ $? -ne 0 ]; then
echo "Failed to add partner. Exiting with status 1."
exit 1
fi
fi
# Run the security command
echo "Running security command..."
$QIT_BINARY run:security my-extension --zip=./../build/extension.zip --wait
if [ $? -ne 0 ]; then
echo "Failed to run security command. Exiting with status 1."
exit 1
fi
```
## Script Runner (Choose between NPM, Composer, Make)
Script runners can be used to execute our bash script `qit.sh`. You can choose the script runner that best suits your needs. Below you can find some examples we've put together for NPM, Composer, and Make.
The **build** command in this script is just an example, and should be modified to fit your actual build process that generates the plugin zip that can be installed in a WordPress site.
### NPM
Usage: `npm run qit-security`
<details>
<summary>package.json</summary>
```json
{
"name": "Project",
"version": "1.0.0",
"scripts": {
"qit-security": "npm run build && dotenv -e .env -- bash ./bin/qit.sh",
"build": "zip -r build/extension.zip my-extension"
},
"devDependencies": {
"dotenv-cli": "^7.2.1"
}
}
```
</details>
### Composer
Usage: `composer run qit-security`
<details>
<summary>composer.json</summary>
```json
{
"scripts": {
"build": "zip -r build/extension.zip my-extension",
"qit-security": "export $(cat .env | xargs) && composer run-script build && ./bin/qit.sh"
}
}
```
</details>
### Makefile
Usage: `make qit-security`
<details>
<summary>Makefile</summary>
```shell
include ./.env
export
build:
zip -r build/extension.zip my-extension
qit-security: build
bash ./bin/qit.sh
```
</details>

View File

@ -0,0 +1,52 @@
# Useful commands
To see the commands that the QIT CLI provides, you can simply run `./qit` to see the full list.
Some helpful commands to get started include:
- `extensions` - Lists the WooExtensions you have access to test. The list includes the ID of the extension and the slug:
```shell
+----------------+-------------------------------------------------------------------------------------+
| ID | Slug |
+----------------+-------------------------------------------------------------------------------------+
| 123 | my-extension |
+----------------+-------------------------------------------------------------------------------------+
```
- `list-tests` - Lists the test runs, including details around the results, the versions tested and the test type:
?> `Zip` for the version denotes that the test was ran against a [development version](running-tests.md#testing-development-builds) of the plugin.
```shell
+--------+------------+-------+------------+---------+-----------+-------------------------------+
| Run Id | Test | WP | WC | Status | Report | Name/Version |
+--------+------------+-------+------------+---------+-----------+-------------------------------+
| 344745 | security | 6.1.1 | 7.2.2 | warning | | My Extension (Zip) |
| 344759 | e2e | 6.1.1 | 7.2.0-rc.2 | failed | Available | My Extension (1.0.0) |
+--------+------------+-------+------------+---------+-----------+-------------------------------+
```
- `get <run ID>` - Get a single test run using the run ID from the `list tests` command:
```bash
Run Id 344745
Test Type security
Wordpress Version 6.1.1
Woocommerce Version 7.2.2
Status warning
Is Development Yes
Woo Extension My Extension
```
?> If a report is available, you can go into the [QIT Dashboard to view the report](../qit-dashboard/viewing-test-results.md#viewing-test-logs) or view the link by running `get` and the test run ID:
```shell
Run Id 361745
Test Type e2e
Wordpress Version 6.1.1
Woocommerce Version 7.2.2
Status failed
Result Url https://testreport.url
Woo Extension My Extension
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,43 @@
# Getting started
The QIT Dashboard is a tool available to extension developers in the WooCommerce administrative interface. This tool allows developers to run a variety of tests with their extension installed in a test environment, configured with the latest version of WordPress and either the release candidate or latest version of WooCommerce. If you have multiple extensions, you can select the extension youd like to run the tests against.
To get started, you'll need to log in to your account on WooCommerce.com. Once you log in to your account, click on "Vendor Dashboard" to go to your dashboard:
![go-to-dashboard](_media/go-to-dashboard.png)
In the menu on the left-hand side, you'll see a new `Quality Insights` menu item:
![qi-menu-option](_media/qi-menu-option.png)
Hovering over the menu will give you the three sections that make up the QIT Dashboard:
- All Tests
- Create a Test
- Notification Settings
More details on each of these options is provided below.
## All tests
![all-tests-menu](_media/all-tests-menu.png)
The All Test page gives you insight into the extension the tests were ran against, the version of the extension, and what test type was ran. In addition, you can see what the results of the test runs were (such as failed, success, or pending if theyre currently running) and, in the case of end-to-end tests, view the Allure test report if the tests fail.
For more insight into the test results, please see [Viewing test results](viewing-test-results.md).
## Run a test
![run-a-test-menu](_media/run-a-test-menu.png)
On this page, you can select [the type of test](../test-types) you'd like to run, which extension to test, and choose the versions of WooCommerce and WordPress to run the tests against.
For more details around creating a test, please see [Run a test](run-a-test.md).
## Notification settings
![notification-settings-menu](_media/notification-settings-menu.png)
If any of the tests result in a failed test result, we will send out an email that contains details on the test type that failed and the versions of the extension, WooCommerce, and WordPress that the test failed for. Email notifications can be enabled or disabled for each test type. By default, emails will be sent to your account email address.
For more information around configuring notifications, see [Configure notifications](notifications.md).

View File

@ -0,0 +1,27 @@
# Configure notifications
To update the way notifications are sent for failed tests, navigate to the `Notification Settings` page under the `Quality Insights` menu:
![notification-settings-menu](_media/notification-settings-menu.png)
After making changes, click the `Update Settings` button at the bottom of the page:
![update-settings-button](_media/update-settings-button.png)
## Notifications by product
Notifications can be enabled and disabled both on a per-product basis as well as for all products that you sell in the store. To update these settings, select the specific product or select `All Products` to update notification settings for all of your products at once:
![notification-product-updates](_media/notification-product-updates.png)
## Notifications by test type
You can enable and disable notifications for each [test type](../test-types.md) that is available by clicking on the toggle:
![test-notification-settings](_media/test-notification-settings.png)
## Customize email recipients
By default we'll send test result emails to your account email address. If you'd like to override and send these emails to other recipients, please add an optional comma-separated list of email addresses to send the tests results to.
![custom-email-list](_media/custom-email-list.png)

View File

@ -0,0 +1,52 @@
# Run a test
To start a new test, navigate to the `Run a Test` page under the `Quality Insights` menu:
![run-a-test-menu](_media/run-a-test-menu.png ":size=40%")
On this page, you can configure the type of test to run, the product to run the tests against, and which release version:
![run-a-test-page](_media/run-a-test-page.png)
Once you've selected the type of test you'd like to run, the product to run it against, and the release version, click the `Confirm and run test` button at the bottom to queue up the test to be ran:
![run-a-test-start](_media/run-a-test-start.png)
Once the test has been queued up, you'll be redirected to the All Tests page and will see a success notification that the test has been created:
![test-created-notification](_media/test-created-notification.png)
!> Note that it may take a moment before the test shows in the table. You can refresh the page or wait for the table to automatically refresh.
The test will then be displayed in the table, showing the version of the extension, the selected test type, the selected WooCommerce Release version with a `Pending` status:
![pending-test-run](_media/pending-test-run.png)
Once the test has been picked up and the tests are running, the status will change to `Running`:
![running-test-run](_media/running-test-run.png)
---
More details on each the options available on the `Create a Test` page can be found below:
## Test type
Select the [type of test](test-types.md) you'd like to run. The current options are available:
- End-to-end
- API
- Activation
- Security
- PHPStan
## Product
Select the product you'd like to run the tests against. All products that you have submitted and are available on the WooCommerce Store will be listed in the dropdown.
## Release
Select the release versions of WooCommerce and WordPress you'd like to execute the tests against. Currently there are two options available:
- The most recent releases of WordPress and WooCommerce.
- The most recent release of WordPress and the latest release candidate version of WooCommerce.

View File

@ -0,0 +1,65 @@
# Viewing test results
To view the tests that were created and their results, navigate to the `All Tests` page under the `Quality Insights` menu:
![all-tests-menu](_media/all-tests-menu.png ":size=40%")
In the table on this page, all of the tests that you created will be shown in the list, starting with the most recent:
![all-tests-list](_media/all-tests-list.png)
## Filtering results
You can filter the test results shown in the table by selecting one of the three available filters at the top of the page:
![view-test-filters](_media/view-test-filters.png)
- Product: Filter by the product the tests were ran against.
- WooCommerce Release: Filter by the WooCommerce release version the tests were ran against.
- Test Types: Filter by the test type that was ran, such as e2e or activation.
You can also search the tests by providing keywords such as the product, the version, the test type, status or release:
![search-tests](_media/search-tests.png)
## Viewing test logs
After a test run completes, you'll be able to view a variety of reports depending on the test type, and you can also share the link to the test results:
> ![view-icon](_media/view-icon.png) Click this icon to view the test results report.
> ![share-icon](_media/share-icon.png) Click this icon to copy a link to the test results to your clipboard to share with others.
### End-to-end tests
#### Successful runs
When an end-to-end test passes, you'll be able to view the report and see the tests that were ran by clicking on the view icon:
![e2e-success-log](_media/e2e-success-log.png)
This will open a modal that you can scroll through and see the results of each test that was ran:
![e2e-results-modal](_media/e2e-results-modal.png)
#### Failed test runs
If an end-to-end test run fails, an Allure test report will be generated. Click on the view icon to see the full details of the Allure test report:
![failed-e2e-test](_media/failed-e2e.png)
### Security, Activation, and PHPStan tests
To view the test logs for these test types, click on view icon in the table for the extension test results you'd like to view:
![non-e2e-report-link](_media/non-e2e-report-link.png)
This will open a modal where you can view the test results. For example, a failed Security test would show the following in the modal:
![security-test-result](_media/security-test-result.png)
You'll also be able to view a log and share the result for successful tests as well:
![success-phpstan](_media/success-phpshan.png)
![success-phpstan-modal](_media/success-phpshan-modal.png)

View File

@ -0,0 +1,5 @@
# Quality Insights Toolkit
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
The Quality Insights Toolkit (QIT) is an initiative by WooCommerce designed to provide current and prospective extension developers in the Woo Marketplace with managed automated tests.

View File

@ -0,0 +1,30 @@
# Test Options
The table below shows what options are available for each test type. For example, for Activation tests you can supply a WordPress version but for the security tests it isn't supported.
| | Activation | E2E | API | Security | PHPStan |
| ---------------------------- | ---------- | --- | --- | -------- | ------- |
| WordPress Versions | ✅ | ✅ | ✅ | ❌ | ❌ |
| WooCommerce Versions | ✅ | ✅ | ✅ | ❌ | ❌ |
| WooCommerce Features | ✅ | ✅ | ✅ | ❌ | ❌ |
| PHP Version | ✅ | ✅ | ✅ | ❌ | ❌ |
| Additional Extensions | ✅ | ✅ | ✅ | ❌ | ❌ |
| Additional WordPress Plugins | ✅ | ✅ | ✅ | ❌ | ❌ |
## WordPress and WooCommerce versions
You can specify the last 5 stable releases along with the most recent beta/release candidate to be used in the test environment.
?> Please note that for API and end-to-end tests, the WooCommerce version is currently restricted to specific versions as we work to make the tests backwards and forwards compatible. For the most up to date versions that we currently support, you can select the test type in the Viewer under `Run a Test` or, using the QIT CLI, check the help for each test type: `./qit run:api --help` and `./qit run:e2e --help`.
## WooCommerce features
QIT currently supports the following option WooCommerce features:
- [High Performance Order Storage (HPOS)](https://developer.woocommerce.com/roadmap/high-performance-order-storage/)
For more information on using optional features in your tests, check out [Testing WooCommerce Optional Features](cli/running-tests?id=using-optional-features).
## PHP versions
You can specify a PHP version from 7.4 to 8.2 to be used in the test environment.

View File

@ -0,0 +1,243 @@
# Test Types
QIT supports the following test types:
- [End-to-end](#end-to-end-tests)
- [API](#api-tests)
- [Activation](#activation-tests)
- [Security](#security-tests-beta)
- [PHPStan](#phpstan-tests)
## End-to-End Tests
The end-to-end (e2e) test creates a temporary WordPress installation with WooCommerce and the extension under test installed, and uses a browser that is scripted to perform certain automated tasks, such as completing the WooCommerce onboarding wizard, creating a product, making a purchase as a customer, verifying the order details as an admin, tweaking tax settings, etc.
Then, it runs the [WooCommerce Core end-to-end tests](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e-pw) against a store with your extension activated. These tests cover the [WooCommerce Core Critical Flows](https://github.com/woocommerce/woocommerce/wiki/Critical-Flows) to verify that a given extension does not break the default WooCommerce behaviors. Once the tests complete, the dashboard will show a Success or Failure test result. In the case of a failed test, a link to an Allure test report will be provided that allows you to dig into the details and see what failed and why.
> Currently, QIT can only run the WooCommerce Core E2E test suite. Future support for running your own E2E tests is planned.
### Example
This GIF is an example of the end-to-end test running. It performs a series of automated actions in a browser, such as creating a product, making a purchase, and verifying the order details as an admin, as fast as possible. The test is run against a store with the extension under test activated.
<details>
<summary>Click to view GIF</summary>
<img src="_media/e2e.gif"/>
</details>
### What to do if it fails
If your end-to-end test is failing, please take the following steps:
- Check the Allure test report to see what failed and why. If you're unable to reproduce the issue manually, try re-running the test to see if it passes.
- If the test continues to fail, it can be either because of a bug that should be fixed, or because your extension modifies the default WooCommerce behavior in a way that is unexpected by the automated tests.
- We expect a certain amount of extensions to fail the end-to-end tests because they modify WooCommerce behaviors in ways that the tests are not designed to account for, such as modifying HTML selectors, etc. If you believe that is the case with your extension, please email us at qit@woocommerce.com and we can help you determine the best way to proceed, by either adapting the tests, suggesting some tweaks to your plugin, or by ignoring some tests specifically for your plugin.
### Understanding Allure Reports
For end-to-end test failures, an Allure test report will be generated and is available on the [All Test page](../dashboard/viewing-test-results.md). Allure reports provide a lot of great information to help troubleshoot and diagnose any test failures. For failures, screenshots and a stacktrace is provided. This section provides an overview of a report and where to go to view results. For a more detailed overview, see the official Allure documentation under [Report Structure](https://docs.qameta.io/allure-report/#_report_structure).
### Viewing a report
An Allure report is generated for end-to-end test failures and can be viewed by clicking the `View Report` button on the `Quality Insights > All Tests` page in the QIT Dashboard:
Following this link will open the Allure test results in a modal:
![allure-report-home](qit-_media/allure-report-home.png)
The `Suites` section shows what browser the tests were ran on, and the results of the tests (currently the tests are only ran in Chrome):
![allure-suites](_media/allure-suites.png)
This page will provide a quick view into what percentage of tests passed, failed, or were skipped. Any failures will be reported in the `Categories` section under `Product defects`:
![allure-categories](_media/allure-categories.png)
### Digging into the details
#### Successful results
For successful tests, you can view the details by going into the `Suites` section, either from the `Overview` page or by clicking the `Suites` menu option on the left-hand side. There, you can click into individual tests that passed and view the steps that were taken, the HTML selectors that were used, and what assertions were made:
![allure-success-results](_media/allure-success-results.png)
#### Failed cases
When tests fail, Allure will provide the stack trace, the error that it encountered, and a screenshot of where it failed:
![allure-failure-results](_media/allure-failure-results.png)
This allows you to dig through the steps that were taken by the test, download the stack trace, and see if it's possible to replicate the issue for any potential bugs that may need to be addressed.
!> We've done our best to stamp out as much flakiness as possible in our end-to-end tests, but it can still occur. If you're unable to reproduce the issue manually, try re-running the test to see if it passes.
## API Tests
API Testing is a crucial part of ensuring the smooth functioning of an application. With API testing, we execute a set of operations using the [WooCommerce REST API](https://woocommerce.github.io/woocommerce-rest-api-docs/) and verify that the API responds in an expected, consistent, way. These operations include creating products, customers, and orders through the REST API and then validating the data that we have created.
The test suite that we use for this process is the [WooCommerce Core API tests](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/api-core-tests). These tests are ran against a store where your extension has been installed and activated. Upon completion of the test, you can check the results either in the Dashboard, or retrieving the test using the QIT CLI, to see if the test has passed or failed. If it fails, you can access an Allure test report that will provide you with a detailed analysis of the reasons for the failure.
### What to do if it fails
In the event of a failed API test, you must take the following steps:
- Review the test report.
- Analyze the causes of the failure and attempt to recreate the issue on your local setup.
- Resolve the issue and run the test again.
- If you believe that the result is incorrect, please do not hesitate to contact us at qit@woocommerce.com.
## Activation tests
The Activation test type activates your extension against a freshly created shop and captures any PHP errors or warnings that may occur on activation. This test sets up a WooCommerce store using the provided WordPress and WooCommerce versions. The following statuses will be returned from this test:
- Success: No PHP notices, warnings, or errors were triggered.
- Warning: A non-fatal PHP error was triggered.
- Failure: A fatal PHP error was triggered.
### What to do if it fails
If your activation test is failing, please take the following steps:
- Open the test report
- Identify the causes of failure. The test will log PHP notices, warnings, and errors that happens when activating your plugin
- Try to reproduce it locally and fix the issue
- If you think the result is incorrect, please email us at qit@woocommerce.com
## Security Tests (Beta)
This test runs an experimental security scanner against a given extension.
- Success: No security issues errors or warnings.
- Warning: Only security issues warnings.
- Failure: One or more security issues errors.
### What Tools Are Used?
The tools used in the Security Scanner are, currently, [PHPCS](https://github.com/squizlabs/PHP_CodeSniffer) and [SemGrep](https://semgrep.dev/).
### Can I run it Locally?
Ideally, you should delegate all the testing execution to QIT. We don't support running the tests outside of QIT, but you can mimick at least the PHPCS rules. The SemGrep rules are not available to be run locally.
### Which PHPCS Rules Are Enabled?
Currently, the only rules enabled in the Security Scanner is `WordPress.Security.EscapeOutput`, and `WordPress.Security.ValidatedSanitizedInput`, with some custom sanitizing and escaping functions whitelisted.
These two rules were chosen as a basic level of security to enforce on all extensions, as they are very accurate and will hardly flag false positives. In the near future, we plan to allow the developer to opt-in to stricter levels of security scans, to show off the good work they do, such as nonce checks, or other security programs, such as generational AI-based scanners that can understand flow of logic, or other third party software other than PHPCS and SemGrep. If you'd like to be a part of the process to define the rules ran against your extensions, feel free to [contact us](https://woocommerce.github.io/qit-documentation/#/contact-us) with your suggestions.
For a more detailed look on our PHPCS rulesets, please see the sample below.
```xml
<?xml version="1.0"?>
<ruleset name="Woo Marketplace PHPCS Security Checks">
<description>Woo Marketplace PHPCS Security Checks.</description>
<arg value="sp"/>
<arg name="colors"/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="8"/>
<exclude-pattern>tests/*</exclude-pattern>
<exclude-pattern>vendor/*</exclude-pattern>
<exclude-pattern>vendor-prefixed/*</exclude-pattern>
<rule ref="WordPress.Security.EscapeOutput">
<properties>
<property name="customEscapingFunctions" type="array" value="WC_Payments_Utils,esc_interpolated_html,wc_help_tip,wc_sanitize_tooltip,wc_selected,wc_kses_notice,wc_esc_json,wc_query_string_form_fields,wc_make_phone_clickable" />
</properties>
</rule>
<!-- Lack of nonces will be added at a later point to minimize noise. -->
<rule ref="WordPress.Security.NonceVerification">
<severity>0</severity>
</rule>
<!-- Do not flag missing "wp_unslash()" calls to globals such as $_POST, and $_GET, etc. -->
<rule ref="WordPress.Security.ValidatedSanitizedInput.MissingUnslash">
<severity>0</severity>
</rule>
<!-- Do not flag missing checks of "isset" on $_POST, $_GET, etc. -->
<rule ref="WordPress.Security.ValidatedSanitizedInput.InputNotValidated">
<severity>0</severity>
</rule>
<!-- Do not flag usage of deprecated "// WPCS: XSS ok." -->
<rule ref="WordPress.Security.EscapeOutput.DeprecatedWhitelistCommentFound">
<severity>0</severity>
</rule>
<!-- Warn about usage of potentially dangerous functions. -->
<rule ref="Generic.PHP.ForbiddenFunctions">
<properties>
<property name="error" value="false" />
<property name="forbiddenFunctions" type="array" value="wp_set_auth_cookie=>null,wp_set_current_user=>null"/>
</properties>
</rule>
<rule ref="WordPress.Security.PluginMenuSlug"/>
<!-- When we disable "InputNotValidated", "InputNotSanitized" also gets disabled, and this is not what we want. -->
<rule ref="WordPress.Security.ValidatedSanitizedInput.InputNotSanitized">
<severity>5</severity>
</rule>
<rule ref="WordPress.Security.ValidatedSanitizedInput">
<properties>
<property name="customSanitizingFunctions" type="array" value="wc_booking_sanitize_time,wc_clean,wc_sanitize_tooltip,wc_format_decimal,wc_stock_amount,wc_sanitize_permalink,wc_sanitize_textarea" />
<property name="customUnslashingSanitizingFunctions" type="array" value="stripslashes"/>
</properties>
</rule>
</ruleset>
```
### What to do When Encountering a Discouraged Function?
We identify functions that may lead to potential security vulnerabilities and mark them with a Warning using the `Generic.PHP.ForbiddenFunctions.Discouraged` rule.
While these functions are not inherently unsafe, they frequently contribute to critical vulnerabilities. We flag them to encourage you to review the code for security. If you've confirmed that the code is secure, you can suppress the warning by adding the following comment on the same line as the function: `// phpcs:ignore Generic.PHP.ForbiddenFunctions.Discouraged`
### What to do if it Fails
If your security test is failing, please take the following steps:
- Open the test report
- Identify the causes of failure. The test will log any security issues that our scanner identifies
- Fix the issue and re-run the test
### Handling False Positives
False positives, or alerts for security issues that do not exist in actuality, may occasionally arise during security testing. Though we've chosen PHPCS and SemGrep rules to minimize such occurrences, it's important to address these false positives in a systematic way.
- **Verification:** The first step is to understand and confirm if it's indeed a false positive. Review the flagged code section and the warning or error raised by the tool. It's always good to revisit the code and the associated rule to understand the potential security implications, if any.
- **Report:** If after careful review, the flag still appears to be a false positive, report it to us. Send an email to qit@woocommerce.com explaining the situation, with the specific test result and the corresponding part of your code. Please make sure to include any additional information that can help us understand why you believe it's a false positive.
- **Suppression (temporarily):** In the meantime, while we investigate the issue, you might want to suppress the false positive to continue your work without disruption. To do so, add a comment line right before the flagged line in your code.
- For PHPCS errors, add `// phpcs:ignore Rule.Name` on the line where the error is reported. Replace `Rule.Name` with the rule that has caused the false positive, eg: `// phpcs:ignore WordPress.Security.ValidatedSanitizedInput`
- For SemGrep errors, add `// nosemgrep: rule-id` in a similar manner, replacing rule-id with the SemGrep rule identifier, eg: `// nosemgrep: audit.php.wp.security.xss.query-arg`
Only suppress the error if you are certain that it is a false positive.
- **Resolution:** We'll review your report and communicate our findings. If we confirm it's a false positive, we will work towards fine-tuning our rules to prevent such instances in the future. Your cooperation in reporting these instances is invaluable to improve the quality and accuracy of our security testing.
Please note, suppressing warnings or errors should be done judiciously and is only recommended as a temporary solution. We strongly advise against using it as a permanent solution to avoid security tests. Our goal is to ensure that your extensions are as secure as possible, and ignoring genuine warnings or errors can lead to security vulnerabilities.
## PHPStan tests
The PHPStan test type runs level 0 PHPStan checks against your extension. More details on what the rule levels cover can be found in the official PHPStan documentation: [Rule Levels](https://phpstan.org/user-guide/rule-levels).
### What to do if it fails
Due to the very nature of WordPress and WooCommerce of not being typed codebases, static code analysis such as PHPStan have a high failure rate when testing WordPress plugins in general.
This doesn't mean that there are issues with the quality of the code, it's only that the code is not friendly to static code analysis, such as code with extensive usage of getters and setters, which is very common when integrating with WooCommerce Core.
The PHPStan tests still provide a lot of value for the developers that want to pursue the highest levels of quality. By default, we run PHPStan tests with level 0.
If your PHPStan test is failing, please take the following steps:
- You can ignore this test, as we don't use it internally to measure an extensions quality
- But if you wish to address the feedback that the static code analsysis provide, open the test report
- Identify the causes of failure
- Fix the issue and re-run the test
- If you think the result is incorrect, please email us at qit@woocommerce.com

View File

@ -0,0 +1,5 @@
# Reference Code
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
Dive deep into code snippets, examples, and templates tailored for WooCommerce. This section will serve as a valuable resource for developers, providing reusable pieces of code that can be integrated into various WooCommerce projects.

View File

@ -0,0 +1,86 @@
# Adding columns to analytics reports and CSV downloads
Adding columns to analytics reports are a really interesting way to add functionality to WooCommerce. New data can be consumed in the table view of the user interface and in your user's favourite spreadsheet or third party application by generating a CSV.
These instructions assume that you have a test plugin for WooCommerce installed and activated. You can follow the ["Getting started" instructions](extending-woocommerce-admin-reports.md) to get a test plugin set up. That post also includes instructions to further modify the query that is executed to get the data in an advanced fashion - it isn't required to just add a simple column.
In WooCommerce, analytics CSVs are generated in two different ways: in the web browser using data already downloaded, or on the server using a new query. It uses the size of the data set to determine the method - if there is more than one page worth of results it generates the data on the server and emails a link to the user, but if the results fit on one page the data is generated and downloaded straight away in the browser.
We'll look at the on-server method for adding a column first, because this is also where the data sent to the browser is generated.
This example extends the Downloads analytics report. To get some data in your system for this report, create a downloadable product with a download expiry value, create an order purchasing the product, then download the product several times. In testing I created 26 downloads, which is enough that the report is spread over two pages when showing 25 items per page, and on a single page when showing 50 items per page. This let me test CSVs generated both on the server and in browser.
In the PHP for your plugin, add three filter handlers:
```php
// This adds the SELECT fragment to the report SQL
function add_access_expires_select( $report_columns, $context, $table_name ) {
if ( $context !== 'downloads' ) {
return $report_columns;
}
$report_columns['access_expires'] =
'product_permissions.access_expires AS access_expires';
return $report_columns;
}
add_filter( 'woocommerce_admin_report_columns', 'add_access_expires_select', 10, 3 );
// This adds the column header to the CSV
function add_column_header( $export_columns ) {
$export_columns['access_expires'] = 'Access expires';
return $export_columns;
}
add_filter( 'woocommerce_filter_downloads_export_columns', 'add_column_header' );
// This maps the queried item to the export item
function map_access_expires( $export_item, $item ) {
$export_item['access_expires'] = $item['access_expires'];
return $export_item;
}
add_filter( 'woocommerce_report_downloads_prepare_export_item', 'map_access_expires', 10, 2 );
```
This adds the access expiry timestamp to the Downloads table/CSV (when the CSV is generated on the server).
These three filters together add the new column to the database query, adds the new header to the CSV, and maps the data returned from the database to the CSV. The first filter `woocommerce_admin_report_columns` adds a SQL fragment to the `SELECT` statement generated for the data query. The second filter `woocommerce_filter_downloads_export_columns` adds the column header to the CSV generated on the server. The third filter `woocommerce_report_downloads_prepare_export_item` maps the value in the data returned from the database query `$item` to the export item for the CSV.
To finish this off by adding support for columns generated in browser, another filter needs to be added to your plugin's JavaScript:
```js
import { addFilter } from "@wordpress/hooks";
function addAccessExpiresToDownloadsReport(reportTableData) {
const { endpoint, items } = reportTableData;
if ("downloads" !== endpoint) {
return reportTableData;
}
reportTableData.headers = [
...reportTableData.headers,
{
label: "Access expires",
key: "access_expires",
},
];
reportTableData.rows = reportTableData.rows.map((row, index) => {
const item = items.data[index];
const newRow = [
...row,
{
display: item.access_expires,
value: item.access_expires,
},
];
return newRow;
});
return reportTableData;
}
addFilter(
"woocommerce_admin_report_table",
"dev-blog-example",
addAccessExpiresToDownloadsReport
);
```
This filter first adds the header to the CSV, then maps the data.
With the plugin you've created, you should now be able to add data to the analytics table, the CSV generated on the server, and the CSV generated on the browser.

View File

@ -0,0 +1,302 @@
# Extending WC-Admin reports
## Introduction
This document serves as a guide to extending WC-Admin Reports with a basic UI dropdown, added query parameters, and modification of SQL queries and resulting report data. This example will create a currency selector for viewing the Orders Report based on a specific currency.
Code from this guide can be viewed in the [wc-admin code repository](https://github.com/woocommerce/woocommerce-admin/tree/main/docs/examples/extensions/sql-modification).
## Getting started
We'll be using a local installation of WordPress with WooCommerce and the development version of WC-Admin to take advantage of `create-wc-extension` as a way to easily scaffold a modern WordPress JavaScript environment for plugins.
In your local install, clone and start WC-Admin if you haven't already.
```sh
cd wp-content/plugins
git clone git@github.com:woocommerce/woocommerce-admin.git
cd woocommerce-admin
npm run build
```
Once thats working, we can setup the extension folder ready for JavaScript development.
```sh
npm run create-wc-extension
```
After choosing a name, move into that folder and start webpack to watch and build files.
```sh
cd ../<my-plugin-name>
npm install
npm start
```
Don't forget to head over to `/wp-admin/plugins.php` and activate your plugin.
## Populating test data
Next, set up some orders to have sample data. Using WooCommerce > Settings > Currency, I added three test orders in Mexican Peso, US Dollar, and New Zealand Dollar.
After doing so, check out WC-Admin to make sure the orders are showing up by going to `/wp-admin/admin.php?page=wc-admin&period=today&path=%2Fanalytics%2Forders&compare=previous_year`. Note that without any modification currency figures show according to what I have currently in WooCommerce settings, which is New Zealand Dollar in this case.
![screenshot of wp-admin showing processing orders](https://woocommerce.files.wordpress.com/2020/02/screen-shot-2020-02-19-at-12.11.34-pm.png?w=851)
We can confirm each order's currency by running the following query on the `wp_posts` table and joining `wp_postmeta` to gather currency meta values. Results show an order in NZD, USD, and MXN. This query is similar to the one we'll implement later in the guide to gather and display currency values.
```sql
SELECT
ID,
post_name,
post_type,
currency_postmeta.meta_value AS currency
FROM `wp_posts`
JOIN wp_postmeta currency_postmeta ON wp_posts.ID = currency_postmeta.post_id
WHERE currency_postmeta.meta_key = '_order_currency'
ORDER BY wp_posts.post_date DESC
LIMIT 3
```
![screenshot of resulting query](https://woocommerce.files.wordpress.com/2020/02/screen-shot-2020-02-19-at-12.33.45-pm.png?w=756)
## Add a UI dropdown
In order to view reports in differing currencies, a filter or dropdown will be needed. We can add a basic filter to reports by adding a configuration object similar to [this one from the Orders Report](https://github.com/woocommerce/woocommerce-admin/blob/main/client/analytics/report/orders/config.js#L50-L62).
First, we need to populate the client with data to render the dropdown. The best way to do this is to add data to the `wcSettings` global. This global can be useful for transferring static configuration data from PHP to the client. In the main PHP file, add currency settings to the Data Registry to populate `window.wcSettings.multiCurrency`.
```php
function add_currency_settings() {
$currencies = array(
array(
'label' => __( 'United States Dollar', 'dev-blog-example' ),
'value' => 'USD',
),
array(
'label' => __( 'New Zealand Dollar', 'dev-blog-example' ),
'value' => 'NZD',
),
array(
'label' => __( 'Mexican Peso', 'dev-blog-example' ),
'value' => 'MXN',
),
);
$data_registry = Automattic\WooCommerce\Blocks\Package::container()->get(
Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry::class
);
$data_registry->add( 'multiCurrency', $currencies );
}
add_action( 'init', 'add_currency_settings' );
```
In the console, you can confirm the data has safely made its way to the client.
![screnshot of console](https://woocommerce.files.wordpress.com/2020/02/screen-shot-2020-02-19-at-1.11.50-pm.png?w=476)
In `index.js` create the custom currency filter and add it the Orders Report.
```js
import { addFilter } from "@wordpress/hooks";
import { __ } from "@wordpress/i18n";
const addCurrencyFilters = (filters) => {
return [
{
label: __("Currency", "dev-blog-example"),
staticParams: [],
param: "currency",
showFilters: () => true,
defaultValue: "USD",
filters: [...(wcSettings.multiCurrency || [])],
},
...filters,
];
};
addFilter(
"woocommerce_admin_orders_report_filters",
"dev-blog-example",
addCurrencyFilters
);
```
If we check out the Orders Report, we can see our new dropdown. Play around with it and you'll notice the currency query parameter gets added to the url. If you check out the Network tab, you'll also see this value included in requests for data used to populate the report. For example, see the requests to orders stats endpoint, `/wp-json/wc-analytics/reports/orders/stats`. Next we'll use that query parameter to adjust report results.
![screenshot showing UI dropdown in wp-admin](https://woocommerce.files.wordpress.com/2020/02/screen-shot-2020-02-19-at-1.16.44-pm.png?w=512)
## Handle currency parameters on the server
Now that our dropdown adds a `currency` query parameter to requests for data, the first thing we'll need to do is add the parameter as a query argument to the Orders Data Store and Orders Stats Data Store. Those data stores use query arguments for caching purposes, so by adding our parameter we can be sure a new database query will be performed when the parameter changes. Add the query argument in your main PHP file.
```php
function apply_currency_arg( $args ) {
$currency = 'USD';
if ( isset( $_GET['currency'] ) ) {
$currency = sanitize_text_field( wp_unslash( $_GET['currency'] ) );
}
$args['currency'] = $currency;
return $args;
}
add_filter( 'woocommerce_analytics_orders_query_args', 'apply_currency_arg' );
add_filter( 'woocommerce_analytics_orders_stats_query_args', 'apply_currency_arg' );
```
Now that we're sure a new database query is performed on mutations of the `currency` query parameter, we can start adding SQL statements to the queries that gather data.
Lets start by adding a JOIN for the orders table, orders stats, and orders chart.
```php
function add_join_subquery( $clauses ) {
global $wpdb;
$clauses[] = "JOIN {$wpdb->postmeta} currency_postmeta ON {$wpdb->prefix}wc_order_stats.order_id = currency_postmeta.post_id";
return $clauses;
}
add_filter( 'woocommerce_analytics_clauses_join_orders_subquery', 'add_join_subquery' );
add_filter( 'woocommerce_analytics_clauses_join_orders_stats_total', 'add_join_subquery' );
add_filter( 'woocommerce_analytics_clauses_join_orders_stats_interval', 'add_join_subquery' );
```
Next, add a WHERE clause
```php
function add_where_subquery( $clauses ) {
$currency = 'USD';
if ( isset( $_GET['currency'] ) ) {
$currency = sanitize_text_field( wp_unslash( $_GET['currency'] ) );
}
$clauses[] = "AND currency_postmeta.meta_key = '_order_currency' AND currency_postmeta.meta_value = '{$currency}'";
return $clauses;
}
add_filter( 'woocommerce_analytics_clauses_where_orders_subquery', 'add_where_subquery' );
add_filter( 'woocommerce_analytics_clauses_where_orders_stats_total', 'add_where_subquery' );
add_filter( 'woocommerce_analytics_clauses_where_orders_stats_interval', 'add_where_subquery' );
```
And finally, a SELECT clause.
```php
function add_select_subquery( $clauses ) {
$clauses[] = ', currency_postmeta.meta_value AS currency';
return $clauses;
}
add_filter( 'woocommerce_analytics_clauses_select_orders_subquery', 'add_select_subquery' );
add_filter( 'woocommerce_analytics_clauses_select_orders_stats_total', 'add_select_subquery' );
add_filter( 'woocommerce_analytics_clauses_select_orders_stats_interval', 'add_select_subquery' );
```
Lets head back to the Orders Report and see if it works. You can manipulate the dropdown and see the relevant order reflected in the table.
![screenshot of WooCommerce Orders tab in wp-admin showing the relevant order reflected in the table.](https://woocommerce.files.wordpress.com/2020/02/screen-shot-2020-02-19-at-1.38.54-pm.png?w=585)
## Finishing touches
The orders table could use some customisation to reflect the selected currency. We can add a column to display the currency in `index.js`. The `reportTableData` argument is an object of headers, rows, and items, which are arrays of data. We'll need to add a new header and append the currency to each row's data array.
```js
const addTableColumn = (reportTableData) => {
if ("orders" !== reportTableData.endpoint) {
return reportTableData;
}
const newHeaders = [
{
label: "Currency",
key: "currency",
},
...reportTableData.headers,
];
const newRows = reportTableData.rows.map((row, index) => {
const item = reportTableData.items.data[index];
const newRow = [
{
display: item.currency,
value: item.currency,
},
...row,
];
return newRow;
});
reportTableData.headers = newHeaders;
reportTableData.rows = newRows;
return reportTableData;
};
addFilter("woocommerce_admin_report_table", "dev-blog-example", addTableColumn);
```
![screenshot of customized table](https://woocommerce.files.wordpress.com/2020/02/screen-shot-2020-02-19-at-4.02.15-pm.png?w=861)
While adding a column is certainly helpful, currency figures in the table and chart only reflect the store currency.
![screenshot of report](https://woocommerce.files.wordpress.com/2020/02/screen-shot-2020-02-19-at-4.03.42-pm.png?w=865)
In order to change a Report's currency and number formatting, we can make use of the `woocommerce_admin_report_currency` JS hook. You can see the store's default sent to the client in `wcSettings.currency`, but we'll need to change these depending on the currency being viewed and designated by the query parameter `?currency=NZD`.
![screenshot of currency settings](https://woocommerce.files.wordpress.com/2020/04/screen-shot-2020-04-03-at-11.18.42-am.png?w=238)
First, lets create some configs in index.js.
```js
const currencies = {
MXN: {
code: "MXN",
symbol: "$MXN", // For the sake of the example.
symbolPosition: "left",
thousandSeparator: ",",
decimalSeparator: ".",
precision: 2,
},
NZD: {
code: "NZD",
symbol: "$NZ",
symbolPosition: "left",
thousandSeparator: ",",
decimalSeparator: ".",
precision: 2,
},
};
```
Finally, add our function to the hook which applies a config based on the currency query parameter.
```js
const updateReportCurrencies = (config, { currency }) => {
if (currency && currencies[currency]) {
return currencies[currency];
}
return config;
};
addFilter(
"woocommerce_admin_report_currency",
"dev-blog-example",
updateReportCurrencies
);
```
🎉 We can now view our Orders Report and see the currency reflected in monetary values throughout the report.
![Screenshot of customized order report](https://woocommerce.files.wordpress.com/2020/04/screen-shot-2020-04-03-at-11.29.05-am.png?w=912)
## Conclusion
In this guide, we added a UI element to manipulate query parameters sent to the server and used those values to modify SQL statements which gather report data. In doing so, we established a way to highly customise WC-Admin reports. Hopefully this example illustrates how the platform can be tailored by extensions to bring a powerful experience to users.

5
docs/reporting/readme.md Normal file
View File

@ -0,0 +1,5 @@
# Reporting
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
Understanding your WooCommerce store's performance is crucial. This section will provide insights into generating, understanding, and optimizing reports to make informed decisions about WooCommerce projects.

5
docs/rest-api/readme.md Normal file
View File

@ -0,0 +1,5 @@
# REST API
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
Harness the power of WooCommerce's REST API. This section will help you discover comprehensive documentation on endpoints, authentication, and best practices, aiding developers in integrating and manipulating WooCommerce functionalities programmatically.

5
docs/security/readme.md Normal file
View File

@ -0,0 +1,5 @@
# Security
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
Security is paramount. This section will dive into best practices, guidelines, and insights to ensure your WooCommerce projects remain secure from threats.

View File

@ -0,0 +1,10 @@
# Reporting security issues
WooCommerce cares deeply about security and works hard to keep our merchants and their customers safe.
You can find our security policy [over here](https://github.com/woocommerce/woocommerce/security/policy) and, if you believe you have discovered a vulnerability, we encourage you to follow it and submit your findings via [HackerOne](https://hackerone.com/automattic?type=team)—a trusted third party service that facilitates reporting of security issues. Please refer to the policy for more details, however some key points are as follows:
- We operate a [bug bounty program](https://hackerone.com/automattic?type=team), so you can be rewarded for valid reports, but not everything is in scope. Please check the guidance before posting.
- We strongly encourage [responsible disclosure](https://www.hackerone.com/disclosure-guidelines). To better protect everyone, please use HackerOne and **do not** post your findings in a public forum.
Thank you for being a responsible reporter!

View File

@ -0,0 +1,85 @@
# WooCommerce security best practices
## Introduction
This guide covers the best practices for securing WooCommerce stores, including hardening WordPress, keeping plugins and themes up to date, implementing secure coding practices, and protecting user data. By following these recommendations, developers can build secure and resilient WooCommerce stores that protect both their business and their customers.
## Audience
This guide is intended for developers who are familiar with WordPress and WooCommerce and want to improve the security of their online stores.
## Prerequisites
To follow this guide, you should have:
1. A basic understanding of WordPress and WooCommerce.
2. Access to a WordPress website with WooCommerce installed and activated.
## Step 1 — Keep WordPress, WooCommerce, and plugins up to date
Regularly updating WordPress, WooCommerce, and all installed plugins is crucial to maintaining a secure online store. Updates often include security patches that address vulnerabilities and help protect your store from attacks. To keep your WordPress and WooCommerce installations up to date:
1. Enable automatic updates for WordPress core.
2. Regularly check for and install updates for WooCommerce and all plugins.
## Step 2 — Choose secure plugins and themes
The plugins and themes you use can have a significant impact on the security of your WooCommerce store. To ensure your store is secure:
1. Install plugins and themes from reputable sources, such as the WordPress Plugin Directory and Theme Directory.
2. Regularly review and update the plugins and themes you use, removing any that are no longer maintained or have known security vulnerabilities.
3. Avoid using nulled or pirated plugins and themes, which may contain malicious code.
## Step 3 — Implement secure coding practices
Secure coding practices are essential for building a secure WooCommerce store. To implement secure coding practices:
1. Follow the WordPress Coding Standards when developing custom themes or plugins.
2. Use prepared statements and parameterized queries to protect against SQL injection attacks.
3. Validate and sanitize user input to prevent cross-site scripting (XSS) attacks and other vulnerabilities.
4. Regularly review and update your custom code to address potential security vulnerabilities.
## Step 4 — Harden WordPress security
Hardening your WordPress installation can help protect your WooCommerce store from attacks. To harden your WordPress security:
1. Use strong, unique passwords for all user accounts.
2. Limit login attempts and enable two-factor authentication (2FA) to protect against brute-force attacks.
3. Change the default "wp\_" table prefix in your WordPress database.
4. Disable XML-RPC and REST API access when not needed.
5. Keep file permissions secure and restrict access to sensitive files and directories.
## Step 5 — Secure user data
Protecting your customers' data is a critical aspect of securing your WooCommerce store. To secure user data:
1. Use SSL certificates to encrypt data transmitted between your store and your customers.
2. Store customer data securely and limit access to sensitive information.
3. Comply with data protection regulations, such as the GDPR, to ensure you handle customer data responsibly.
## Step 6 — Implement a security plugin
Using a security plugin can help you monitor and protect your WooCommerce store from potential threats. To implement a security plugin:
1. Choose a reputable security plugin, such as Wordfence, Sucuri, or iThemes Security.
2. Configure the plugin's settings to enable features like malware scanning, firewall protection, and login security.
## Step 7 — Regularly monitor and audit your store's security
Continuously monitor and audit your WooCommerce store's security to identify potential vulnerabilities and address them before they can be exploited. To monitor and audit your store's security:
1. Use a security plugin to perform regular scans for malware and other security threats.
2. Monitor your site's activity logs to identify suspicious activity and potential security issues.
3. Perform regular security audits to evaluate your store's overall security and identify areas for improvement.
## Step 8 — Create regular backups
Backing up your WooCommerce store is essential for quickly recovering from security incidents, such as data loss or site compromise. To create regular backups:
1. Choose a reliable backup plugin, such as UpdraftPlus, BackupBuddy, or Duplicator.
2. Configure the plugin to automatically create regular backups of your entire site, including the database, files, and media.
3. Store your backups securely off-site to ensure they are accessible in case of an emergency.
## Conclusion
By following these security best practices, you can build a secure and resilient WooCommerce store that protects both your business and your customers. Regularly monitoring, auditing, and updating your store's security measures will help ensure it remains protected as new threats and vulnerabilities emerge.

118
docs/style-guide.md Normal file
View File

@ -0,0 +1,118 @@
# Technical documentation style guide
This style guide is intended to provide guidelines for creating effective and user-friendly tutorials and how-to guides for WooCommerce technical documentation that will live in repo and be editable and iterative by open source contributors and WooCommerce teams.
## Writing style
### Language style
- Its important to use clear and concise language that is easy to understand. Use active voice and avoid using jargon or technical terms that may be unfamiliar to the user. The tone should be friendly and approachable, and should encourage the user to take action.
- Articles are written in the 3rd-person voice.
Example: “Add an embed block to your page.”
- Use American English for spelling and punctuation styles, or consider using a different word that doesnt have a different spelling in other English variants.
- Use sentence case (not title case) for docs titles and subheadings.
Example: “Introduction to the launch experience” rather than “Introduction to the Launch Experience.”
- When referring to files or directories, the text formatting eliminates the need to include articles such as “the” and clarifying nouns such as “file” or “directory”.
Example: “files stored in ~~the~~ `/wp-content/uploads/` ~~directory~~” or “edit ~~the~~ `/config/config.yml` ~~file~~ with”
### Writing tips
- Our target audience has a range of roles and abilities. When creating a tutorial or how-to guide, its important to consider the intended audience. Are they beginners or advanced users? What is their technical background? Understanding the audience can help guide the level of detail and the choice of language used in the guide.
- Use language understable even by readers with little technical knowledge and readers whose first language might not be English.
- Consider that this might be the first WooCommerce documentation page the reader has seen. They may have arrived here via a Google search or another website. Give the reader enough context about the topic and link words and phrases to other relevant Docs articles as often as possible.
- Consider notes and sections that provide insights, tips, or cautionary information to expand on topics with context that would be relevant to the reader.
- When providing specific direction, best practices, or requirements, we recommend including a description of the potential consequences or impacts of not following the provided guidance. This can help seed additional search keywords into the document and provide better context when support links to the documentation.
- Always write a conceptual, high-level introduction to the topic first, above any H2 subheading.
### Tutorials
Tutorials are comprehensive and designed to teach a new skill or concept.
> You are the teacher, and you are responsible for what the student will do. Under your instruction, the student will execute a series of actions to achieve some end.
>
> [Divio Framework on Tutorial Writing](https://documentation.divio.com/tutorials/)
### How-to guides
How-to guides are focused and specific, providing instructions on how to accomplish a particular task or solve a particular problem.
> How-to guides are wholly distinct from tutorials and must not be confused with them:
>
> - A tutorial is what you decide a beginner needs to know.
> - A how-to guide is an answer to a question that only a user with some experience could even formulate.
>
> [Divio Framework on How-to-Guide Writing](https://documentation.divio.com/how-to-guides/)
## Formatting
### Visual style
- Use the H2 style for main headings to be programmatically listed in the articles table of contents.
- File names and directory paths should be stylized as code per the [HTML spec](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-code-element).
Example: `/wp-content/uploads/`
- References to a single directory should have a trailing slash (eg. “/” appended) to the name.
Example: “uploads/“
- References to repositories should appear without forward slashes and not be formatted in any way. The first appearance of a repository in article content should link to the URL of the repository source whenever possible.
Example: “[woocommerce-blocks](https://github.com/woocommerce/woocommerce-blocks)” followed by “woocommerce-blocks”
- Inline references to functions and command line operations should be formatted as inline code.
Example: “Use `dig` to retrieve DNS information.”
- Functions should be styled with “Inline code” formatting and retain upper and lower case formatting as established from their source.
Example: `WP_Query` (not WP_query)
### Visual aids
Visual aids such as screenshots, diagrams, code snippets and videos can be very helpful in a how-to guide. They provide a visual reference that can help the user understand the instructions more easily. When including visual aids, be sure to label them clearly and provide a caption or description that explains what is being shown.
### Acronyms
Phrases that are more familiarly known in their acronym form can be used. The first time an acronym appears on any page, the full phrase must be included, followed by its acronym in parentheticals.
Example: Weve enhanced the querying functionality in WooCommerce with the introduction of High Performance Order Storage (HPOS).
After that, the acronym can be used for the remainder of the page.
When deciding if a term is common, consider the impact on translation and future internationalization (i18n) efforts.
## Patterning
### Article content
When creating a how-to guide, its important to use a consistent and easy-to-follow format. Here is a suggested template for a software how-to guide:
**Introduction**: Provide an overview of the task or feature that the guide covers.
**Prerequisites**: List any prerequisites that are required to complete the task or use the feature.
**Step-by-step instructions**: Provide detailed, step-by-step instructions for completing the task or using the feature. Use numbered steps and include screenshots or other visual aids where appropriate.
**Troubleshooting**: Include a troubleshooting section that addresses common issues or errors that users may encounter.
**Conclusion**: Summarize the key points covered in the guide and provide any additional resources or references that may be helpful.
## Terminology
### Reference to components and features
- “**WordPress Admin dashboard**” should be presented in its complete form the first time it appears in an article, followed by its abbreviated form in parentheses (“WP Admin”). Thereafter the abbreviated form can be used for any reference to the WordPress Admin dashboard within the same article.
- When referring to the URL of the WordPress Admin dashboard, the shortened form `wp-admin` can be used.
## Testing
Before publishing a tutorial or guide, its important to test it thoroughly to ensure that the instructions are accurate and easy to follow.
## Structure
### Atomizing the docs
Articles that cover too many topics in one place can make it difficult for users to find the information they are looking for. “Atomizing” the Docs refers to breaking down extensive articles into a group of smaller related articles. This group of articles often has a main “landing page” with a high-level overview of the group of articles, and the descriptive text provides links to the related articles that a user will find relevant. These groups of articles can be considered an information “molecule” formed by the smaller, atomized articles.
Breaking out smaller chunks of content into their own articles makes it easier to link to specific topics rather than relying on links to more extensive articles with anchor tags. This more specific linking approach is helpful to our Support team but is also useful for cross-linking articles throughout the Docs site.

View File

@ -0,0 +1,85 @@
# Theme Design and User Experience Guidelines
This guide covers general guidelines and best practices to follow in order to ensure your theme experience aligns with ecommerce industry standards and WooCommerce for providing a great online shopping experience, maximizing sales, ensuring ease of use, seamless integration, and strong UX adoption.
We recommend you review the [UI best practices for WordPress](https://developer.wordpress.org/themes/advanced-topics/ui-best-practices/) to ensure your theme is aligned with the WordPress theme requirements.
Make sure your theme fits one or more industries currently available in the [WooCommerce themes store](https://woocommerce.com/product-category/themes). Its important that the theme offers enough originality and distinctiveness in its design, while keeping it familiar, in order to be distinguished from other themes on the WooCommerce theme store. Your theme should avoid copying existing themes on the WooCommerce theme store or other WordPress theme marketplaces.
## Design
High-quality design is an important aspect of an online store, and that is driven by the theme design and content. The design of the theme should be simple, consistent, uncluttered, memorable, intuitive, efficient, and functional. When designing a new theme for WooCommerce special attention should be given to:
### Layout
The theme should be up to industry standards in terms of hierarchy, flow, content balance, and white space.
Theme authors must ensure that store pages (shop, product page, categories, cart, checkout, profile page, etc) fit seamlessly with the theme since they are the central point of a WooCommerce theme.
The Theme is expected to be fully functional and optimized to be accessed on common device types such as laptops, tablets, and smartphones.
### Typography
The theme should provide elegant and legible font pairings that promote a comfortable reading experience.
Consistent and harmonious font sizes, line widths and spacing must be employed across all pages and device types.
The theme typography must consist of a small number of typefaces that complement each other, generally no more than two.
Proper capitalization is used, avoiding all caps (with the exception of some UI elements such as buttons, tabs, etc).
### Iconography
Icons used in the theme portray a direct meaning of the actions/situations they are representing and are used consistently regarding sizing positioning and color.
### Color
The theme must follow a harmonious and consistent color scheme across UI elements and all pages. The color scheme should consist of small number of colors that contain:
- A primary/accent dominant color
- One or two secondary colors that complement the primary
- Neutral colors (white, black, gray)
The color palette used in text and graphical UI components must be compliant with the [WCAG AA conformance level](https://www.w3.org/TR/WCAG20/#conformance) or above.
### Patterns
The theme must employ a consistent set of patterns that are used across pages, such as:
- Navigation, sidebars, footer
- Content blocks (titles, paragraphs, lists, product details, reviews, image showcases, etc)
- Forms structure and elements (fields, drop-downs, buttons, etc)
- Tables
- Lists
- Notices
## Accessibility
The theme must meet the [Web Content Accessibility Guidelines](https://www.w3.org/TR/WCAG20/) (WCAG). Meeting 100% conformance with WCAG 2.0 is hard work; meet the AA level of conformance at a minimum.
For more information on accessibility, check out the [WordPress accessibility quick start guide](https://make.wordpress.org/accessibility/handbook/best-practices/quick-start-guide/).
## Customization
Themes have to rely on the customizer for any type of initial set up. Specific onboarding flows are not permitted.
Any customization supported by the theme, such as layout options, additional features, block options, etc, should be delivered in the customizer or on block settings for blocks that are included in the theme.
Themes should not bundle or require the installation of additional plugins/extensions (or frameworks) that provide additional options or functionality. For more information on customisation, check out the [WordPress theme customization API](https://codex.wordpress.org/Theme_Customization_API)**.**
On activation, themes shouldnt override the WordPress theme activation flow by taking the user into other pages.
## Branding
The theme must not contain any branding or references to theme authors in locations that interfere with the normal operation of an online store. Theme authors can include links to their websites on the theme footer. Affiliate linking is not permitted.
The interface should solely focus on the experience, the usage of notices, banners, large logos, or any promotional materials is not allowed in the admin interface.
## Demos and sample content
Upon submission theme authors must provide a way for the theme to be showcased and tested. The sample content/demo should refrain from using custom graphics/assets that will not be present in the deliverables to avoid merchant confusion and broken expectations (examples: using logos, illustrations). When creating a theme for a specific vertical theme authors should consider using sample content that aligns with the vertical.
All imagery and text should be appropriate for all ages/family-friendly. The theme author should consider using imagery that is inclusive of ages, nationalities, etc. The theme should refrain from using imagery that looks like stock photography.
The theme must be distributed and cleared of all the necessary licenses for assets such as images, fonts, icons, etc.

View File

@ -0,0 +1,253 @@
# Adding a custom field to simple and variable products
In this tutorial you will learn how to create a custom field for a product and show it in your store. Together we will set up the skeleton plugin, and learn about WP naming conventions and WooCommerce hooks. In the end, you will have a functioning plugin for adding a custom field.
The [full plugin code](https://github.com/EdithAllison/woo-product-custom-fields) was written based on WordPress 6.2 and WooCommerce 7.6.0
## Prerequisites
To do this tutorial you will need to have a WordPress install with the WooCommerce plugin activated, and you will need at least one [simple product set up](https://woocommerce.com/document/managing-products/), or you can [import the WooCommerce sample product range](https://woocommerce.com/document/importing-woocommerce-sample-data/).
## Setting up the plugin
To get started, lets do the steps to [create a skeleton plugin](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/create-woo-extension).
First, navigate to your wp-content/plugins folder, then run:
```sh
npx @wordpress/create-block -t @woocommerce/create-woo-extension woo-product-fields
```
Then we navigate to our new folder and run the install and build:
```sh
cd woo-product-fields
npm install # Install dependencies
npm run build # Build the javascript
```
WordPress has its own class file naming convention which doesnt work with PSR-4 out of the box. To learn more about Naming Conventions see the [WP Handbook](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#naming-conventions). We will use the standard format of “class-my-classname.php” format, so lets go to the composer.json file and change the autoload to:
```json
"autoload": {
"classmap": ["includes/", "includes/admin/"]
},
```
After saving run dump-autoload to generate the class map by running in the Terminal:
```sh
composer dump-autoload -o
```
This generates a new vendor/composer/autoload_classmap.php file containing a list of all our classes in the /includes/ and /includes/admin/ folder. We will need to repeat this command when we add, delete or move class files.
## WooCommerce Hooks
Our aim is to create a new custom text field for WooCommerce products to save new stock information for display in the store. To do this, we need to modify the section of the Woo data in the admin area which holds the stock info.
WooCommerce allows us to add our code to these sections through [hooks](https://developer.wordpress.org/plugins/hooks/), which are a standard WordPress method to extend code. In the “Inventory” section we have the following action hooks available to us:
For our Woo extension, well be appending our field right at the end with `woocommerce_product_options_inventory_product_data`.
## Creating our class
Lets get started with creating a new class which will hold the code for the field. Add a new file with the name `class-product-fields.php` to the `/includes/admin/` folder. Within the class, we add our namespace, an abort if anyone tries to call the file directly and a \_\_construct method which calls the `hooks()` method:
```php
<?php
namespace WooProductField\Admin;
defined( 'ABSPATH' ) || exit;
class ProductFields {
public function __construct() {
$this->hooks();
}
private function hooks() {}
}
```
Then in Terminal we run `composer dump-autoload -o` to regenerate the class map. Once thats done, we add the class to our `setup.php` \_\_construct() function like so:
```php
class Setup {
public function __construct() {
add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
new ProductFields();
}
```
## Adding the custom field
With the class set up and being called, we can create a function to add the custom field. WooCommerce has its own `woocommerce_wp_text_input( $args )` function which we can use here. `$args` is an array which allows us to set the text input data, and we will be using the global $product_object to access stored metadata.
```php
public function add_field() {
global $product_object;
?>
<div class="inventory_new_stock_information options_group show_if_simple show_if_variable">
<?php woocommerce_wp_text_input(
array(
'id' => '_new_stock_information',
'label' => __( 'New Stock', 'woo_product_field' ),
'description' => __( 'Information shown in store', 'woo_product_field' ),
'desc_tip' => true,
'value' => $product_object->get_meta( '_new_stock_information' )
)
); ?>
</div>
<?php
}
```
Lets take a look at the arguments in the array. The ID will be used as meta_key in the database. The Label and Description are shown in the data section, and by setting desc_tip to true, it will be shown as a hover over the info icon. The last argument value ensures that if a value is already stored, then it will be shown.
For the div class, the class names `show_if_simple` and `show_if_variable` will control when our section is shown. This is linked to JS code which dynamically hides/reveals sections. If for example, we wanted to hide the section from variable products, then we can simply delete `show_if_variable`.
Now that we have our field, we need to save it. For this, we can hook into woocommerce_process_product_meta which takes two arguments, `$post_id` and `$post`:
```php
public function save_field( $post_id, $post ) {
if ( isset( $_POST['_new_stock_information'] ) ) {
$product = wc_get_product( intval( $post_id ) );
$product->update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'] ) );
$product->save_meta_data();
}
}
```
This function checks if our new field is in the POST array. If yes, we create the product object, update our metadata and save the metadata. The `update_meta_data` function will either update an existing meta field or add a new one. And as were inserting into the database, we must [sanitize our field value](https://developer.wordpress.org/apis/security/sanitizing/).
And to make it all work, we add the hooks:
```php
private function hooks() {
add_action( 'woocommerce_product_options_inventory_product_data', array( $this, 'add_field' ) );
add_action( 'woocommerce_process_product_meta', array( $this, 'save_field' ), 10, 2 );
}
```
Now if we refresh our product screen, we can see our new field.
If we add data and save the product, then the new meta data is inserted into the database.
At this point you have a working extension that saves a custom field for a product as product meta.
Showing the field in the store
If we want to display the new field in our store, then we can do this with the `get_meta()` method of the Woo product class: `$product->get_meta( '\_new_stock_information' )`
Lets get started by creating a new file /includes/class-product.php. You may have noticed that this is outside the `/admin/` folder as this code will run in the front. So when we set up the class, we also adjust the namespace accordingly:
```php
<?php
namespace WooProductField;
defined( 'ABSPATH' ) || exit;
class Product {
public function __construct() {
$this->hooks();
}
private function hooks() { }
}
```
Again we run `composer dump-autoload -o` to update our class map.
If you took a look at the extension setup you may have noticed that `/admin/setup.php` is only called if were within WP Admin. So to call our new class well add it directly in `/woo-product-field.php`:
```php
public function __construct() {
if ( is_admin() ) {
new Setup();
}
new WooProductField\Product();
}
```
For adding the field to the front we have several options. We could create a theme template, but if we are working with a WooCommerce-compatible theme and dont need to make any other changes then a quick way is to use hooks. If we look into `/woocommerce/includes/wc-template-hooks.php` we can see all the existing actions for `woocommerce_single_product_summary` which controls the section at the top of the product page:
For our extension, let's add the new stock information after the excerpt by using 21 as the priority:
```php
private function hooks() {
add_action( 'woocommerce_single_product_summary', array( $this, 'add_stock_info' ), 21 );
}
```
In our function we output the stock information with the [appropriate escape function](https://developer.wordpress.org/apis/security/escaping/), in this case, Im suggesting to use `esc_html()` to force plain text.
```php
public function add_stock_info() {
global $product;
?>
<p><?php echo esc_html( $product->get_meta( '_new_stock_information' ) ); ?> </p>
<?php
}
```
Now if we refresh the product page our stock information will be shown just below the excerpt:
Fantastic! You have completed this tutorial and have a working WooCommerce extension that adds a new custom field and shows it in the store! 🎉I hope its shown you how easily you can extend WooCommerce through hooks and tailor it to your or your clients shop requirements!
Below is a bonus task if you are interested in variable products. Feel free to come back to this later.
## How to handle variable products?
The above example was done with a simple product. But what if we have variations, for example, a T-Shirt in multiple sizes and we wanted to store different stock information for each variant? WooCommerce lets us do that with the [variable product type](https://woocommerce.com/document/variable-product/).
A variable product type has variations as its children. To add a custom field to a variation, we can use the `woocommerce_variation_options_inventory` hook, and to save `woocommerce_save_product_variation` so lets update our `hooks()` method with the new action hooks like so:
```php
private function hooks() {
add_action( 'woocommerce_product_options_inventory_product_data', array( $this, 'add_field' ) );
add_action( 'woocommerce_process_product_meta', array( $this, 'save_field' ), 10, 2 );
add_action( 'woocommerce_variation_options_inventory', array( $this, 'add_variation_field' ), 10, 3 );
add_action( 'woocommerce_save_product_variation', array( $this, 'save_variation_field' ), 10, 2 );
}
```
The setup is very similar to simple products, the main difference is that we need to use the $loop id which distinguishes between the variations, and we will be using the `wrapper_class` to show it as a full width text input:
```php
public function add_variation_field( $loop, $variation_data, $variation ) {
$variation_product = wc_get_product( $variation->ID );
woocommerce_wp_text_input(
array(
'id' => '\_new_stock_information' . '[' . $loop . ']',
'label' => \_\_( 'New Stock Information', 'woo_product_field' ),
'wrapper_class' => 'form-row form-row-full',
'value' => $variation_product->get_meta( '\_new_stock_information' )
)
);
}
```
For saving we use:
```php
public function save_variation_field( $variation_id, $i ) {
if ( isset( $_POST['_new_stock_information'][$i] ) ) {
$variation_product = wc_get_product( $variation_id );
$variation_product->update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'][$i] ) );
$variation_product->save_meta_data();
}
}
```
And we now have a new variation field that stores our new stock information. If you cannot see the new field, please make sure to enable “Manage Stock” for the variation by ticking the checkbox in the variation details.
Displaying the variation in the front store works a bit differently for variable products as only some content on the page is updated when the customer makes a selection. This exceeds the scope of this tutorial, but if you are interested have a look at `/woocommerce/assets/js/frontend/add-to-cart-variation.js` to see how WooCommerce does it.
## How to find hooks?
Everyone will have their own preferred way, but for me, the quickest way is to look in the WooCommere plugin code. The code for each data section can be found in `/woocommerce/includes/admin/meta-boxes/views`. To view how the inventory section is handled check the `html-product-data-inventory.php` file, and for variations take a look at `html-variation-admin.php`.

5
docs/tutorials/readme.md Normal file
View File

@ -0,0 +1,5 @@
# Tutorials
> ⚠️ **Notice:** This documentation is currently a **work in progress**. While it's open to the public for transparency and collaboration, please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
This section will contain step-by-step guides and walkthroughs tailored for both novice and seasoned WooCommerce enthusiasts. Whether it's setting up a new feature or diving into complex customizations, our tutorials will cover a wide range of topics to help you achieve your goals.