diff --git a/.codeclimate.yml b/.codeclimate.yml
index a11de13a5c8..9a63874430e 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -15,23 +15,23 @@ engines:
- javascript
ratings:
paths:
- - "includes/*"
+ - "includes/*"
exclude_paths:
- - tests/*
- - apigen/*
- - dummy-data/*
- - i18n/*
- - includes/api/legacy/*
- - includes/libraries/*
- - includes/updates/*
- - includes/gateways/simplify-commerce/*
- - includes/shipping/legacy-*
- - includes/wc-deprecated-functions.php
- - includes/class-wc-legacy-api.php
- - assets/js/accounting/**
- - assets/js/jquery-*
- - assets/js/prettyPhoto/*
- - assets/js/round/*
- - assets/js/select2/*
- - assets/js/stupidtable/*
- - assets/js/zeroclipboard/*
+- "tests/"
+- "apigen/"
+- "sample-data/"
+- "i18n/"
+- "includes/api/legacy/"
+- "includes/libraries/"
+- "includes/updates/"
+- "includes/gateways/simplify-commerce/"
+- "includes/shipping/legacy-*"
+- "includes/wc-deprecated-functions.php"
+- "assets/js/accounting/"
+- "assets/js/jquery-*"
+- "assets/js/prettyPhoto/"
+- "assets/js/round/"
+- "assets/js/select2/"
+- "assets/js/selectWoo/"
+- "assets/js/stupidtable/"
+- "assets/js/zeroclipboard/"
diff --git a/.codecov.yml b/.codecov.yml
new file mode 100644
index 00000000000..115ca2cc537
--- /dev/null
+++ b/.codecov.yml
@@ -0,0 +1,26 @@
+codecov:
+ notify:
+ require_ci_to_pass: yes
+
+coverage:
+ precision: 2
+ round: nearest
+ range: "50...100"
+
+ status:
+ project: yes
+ patch: off
+ changes: off
+
+parsers:
+ gcov:
+ branch_detection:
+ conditional: yes
+ loop: yes
+ method: no
+ macro: no
+
+comment:
+ layout: "files"
+ behavior: default
+ require_changes: yes
diff --git a/.coveralls.yml b/.coveralls.yml
deleted file mode 100644
index c00a1ca9322..00000000000
--- a/.coveralls.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-src_dir: .
-coverage_clover: ./tmp/clover.xml
-json_path: ./tmp/coveralls-upload.json
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 00000000000..f44a9c08503
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,21 @@
+*.min.js
+
+/assets/js/accounting/**
+/assets/js/flexslider/**
+/assets/js/jquery-blockui/**
+/assets/js/jquery-cookie/**
+/assets/js/jquery-flot/**
+/assets/js/jquery-payment/**
+/assets/js/jquery-qrcode/**
+/assets/js/jquery-serializejson/**
+/assets/js/jquery-tiptip/**
+/assets/js/jquery-ui-touch-punch/**
+/assets/js/js-cookie/**
+/assets/js/photoswipe/**
+/assets/js/prettyPhoto/**
+/assets/js/round/**
+/assets/js/select2/**
+/assets/js/selectWoo/**
+/assets/js/stupidtable/**
+/assets/js/zeroclipboard/**
+/assets/js/zoom/**
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 00000000000..fa832ed3d28
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,18 @@
+{
+ "root": true,
+ "env": {
+ "browser": true,
+ "node": true
+ },
+ "globals": {
+ "wp": true,
+ "wpApiSettings": true,
+ "wcSettings": true
+ },
+ "rules": {
+ "camelcase": 0,
+ "indent": 0,
+ "max-len": [ 2, { "code": 140 } ],
+ "no-console": 1
+ }
+}
diff --git a/.gitattributes b/.gitattributes
index 5e8686b5f3a..d728da00bed 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,10 +1,12 @@
/.* export-ignore
apigen* export-ignore
+CODE_OF_CONDUCT.md export-ignore
CHANGELOG.txt export-ignore
composer.* export-ignore
Gruntfile.js export-ignore
package.json export-ignore
-phpcs.ruleset.xml export-ignore
+package-lock.json export-ignore
+phpcs.xml export-ignore
phpunit.* export-ignore
README.md export-ignore
tests export-ignore
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 97fcc742bbd..4491e491985 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,54 +1,63 @@
-# How To Contribute
+# Contributing to WooCommerce ✨
-Community made patches, localizations, bug reports and contributions are always welcome and crucial to ensure WooCommerce remains the leading eCommerce platform for WordPress. WooCommerce currently powers 30% of all online stores across the internet, and your help making it even more awesome will be greatly appreciated :)
+There are many ways to contribute to the WooCommerce project!
-When contributing please ensure you follow the guidelines below to help us keep on top of things.
+- Translating strings into your language.
+- Answering questions on GitHub and within the various WooCommerce communities.
+- Submitting fixes, improvements, and enhancements.
-__Please Note:__
+WooCommerce currently powers 30% of all online stores across the internet, and your help making it even more awesome will be greatly appreciated :)
-GitHub is for _bug reports and contributions only_ - if you have a support question or a request for a customization this is not the right place to post it. Use [WooCommerce Support](https://support.woocommerce.com) for customer support, [WordPress.org](https://wordpress.org/support/plugin/woocommerce) for community support, and for customizations we recommend one of the following services:
+If you think something can be improved and you wish to contribute code,
+[fork](https://help.github.com/articles/fork-a-repo/) WooCommerce, commit your changes,
+and [send a pull request](https://help.github.com/articles/using-pull-requests/). We'll be happy to review your changes!
+## Feature Requests
+
+Feature requests can be [submitted to our issue tracker](https://github.com/woocommerce/woocommerce/issues/new?template=Feature_request.md). Be sure to include a description of the expected behavior and use case, and before submitting a request, please search for similar ones in the closed issues.
+
+Feature request issues will remain closed until we see sufficient interest via comments and [👍 reactions](https://help.github.com/articles/about-discussions-in-issues-and-pull-requests/) from the community.
+
+You can see a [list of current feature requests which require votes here](https://github.com/woocommerce/woocommerce/issues?q=label%3A%22votes+needed%22+label%3Aenhancement+sort%3Areactions-%2B1-desc+is%3Aclosed).
+
+## Technical Support / Questions
+
+We don't offer technical support on GitHub so we recommend using the following:
+
+**Reading our documentation**
+Usage docs can be found here: https://docs.woocommerce.com/
+
+If you have a problem, you may want to start with the self help guide here: https://docs.woocommerce.com/document/woocommerce-self-service-guide/
+
+**Technical support for premium extensions or if you're a WooCommerce.com customer**
+ from a human being - submit a ticket via the helpdesk
+https://woocommerce.com/contact-us/
+
+**General usage and development questions**
+- WooCommerce Slack Community: https://woocommerce.com/community-slack/
+- WordPress.org Forums: https://wordpress.org/support/plugin/woocommerce
+- The WooCommerce Help and Share Facebook group
+
+**Customizations**
- [WooExperts](https://woocommerce.com/experts/)
- [Codeable](https://codeable.io/)
-## Contributing To The Core
+## Coding Guidelines
-### Reporting Issues
+- **Ensure you stick to the [WordPress Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/)**
+- Install our pre-commit hook using composer. It'll help with the Coding Standards. To install run `composer install` from the command line within the woocommerce plugin directory.
+- Ensure you use LF line endings in your code editor. Use [EditorConfig](http://editorconfig.org/) if your editor supports it so that indentation, line endings and other settings are auto configured.
+- When committing, reference your issue number (#1234) and include a note about the fix.
+- Ensure that your code is compatible with PHP 5.2+.
+- Push the changes to your fork and submit a pull request on the master branch of the WooCommerce repository. Existing maintenance branches will be maintained by WooCommerce developers.
-Reporting issues is a great way to became a contributor as it doesn't require technical skills. In fact you don't even need to know a programming language or to be able to check the code itself, you just need to make sure that everything works as expected and [submit an issue report](https://github.com/woocommerce/woocommerce/issues/new) if you spot a bug. Sound like something you're up for? Go for it!
+Please **don't** modify the changelog or update the .pot files. These will be maintained by the WooCommerce team.
-#### How To Submit An Issue Report
+## Translating WooCommerce
-If something isn't working, congratulations you've found a bug! Help us fix it by submitting an issue report:
+We have a [project on translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/woocommerce). You can join the localization team of your language and help by translating WooCommerce. [Find more about using joining a language team and using GlotPress](https://make.wordpress.org/polyglots/handbook/tools/glotpress-translate-wordpress-org/).
-* Make sure you have a [GitHub account](https://github.com/signup/free)
-* Search the [Existing Issues](https://github.com/woocommerce/woocommerce/issues) to be sure that the one you've noticed isn't already there
-* Submit a report for your issue
- * Clearly describe the issue (including steps to reproduce it if it's a bug)
- * Make sure you fill in the earliest version that you know has the issue.
-
-### Making Changes
-
-Making changes to the core is a key way to help us improve WooCommerce. You will need some technical skills to make a change, like knowing a bit of PHP, CSS, SASS or JavaScript.
-
-If you think something could be improved and you're able to do so, make your changes and submit a Pull Request. We'll be pleased to get it :)
-
-#### How To Submit A PR
-
-* Fork the repository on GitHub
-* Make the changes to your forked repository
- * **Ensure you stick to the [WordPress Coding Standards](https://make.wordpress.org/core/handbook/coding-standards/php/).**
- * Ensure you use LF line endings - no crazy Windows line endings please :)
-* When committing, reference your issue number (#1234) and include a note about the fix
-* Push the changes to your fork and submit a pull request on the master branch of the WooCommerce repository. Existing maintenance branches will be maintained by WooCommerce developers
-* Please **don't** modify the changelog - this will be maintained by the WooCommerce developers.
-* Please **don't** add your localizations or update the .pot files - these will also be maintained by the WooCommerce developers. To contribute to the localization of WooCommerce, please join the [translate.wordpress.org project](https://translate.wordpress.org/projects/wp-plugins/woocommerce). This is much needed, if you speak a language that needs translating consider yourself officially invited to the party.
-
-After you follow the step above, the next stage will be waiting on us to merge your Pull Request. We review them all, and make suggestions and changes as and if necessary.
-
-## Contribute To Localizing WooCommerce
-
-Localization is a very important part of WooCommerce. We believe in net neutrality and want our platform to be available to everyone, everywhere with equal ease. When you localize WooCommerce, you are helping hundreds of people in the world, and all the people who speak your language. That's pretty neat.
+If WooCommerce is already 100% translated for your language, join the team anyway! We regularly update our language files and there will definitely be need of your help soon.
### Glossary & Style Guide
@@ -78,22 +87,8 @@ We don’t have a Style Guide template available, so feel free to create your ow
If you created a style guide for your language, please let us know so we can add it in the list above. You can also add it by yourself by submitting a PR for this file.
-### Translating The Core
-
-We have a [project on translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/woocommerce). You can join the localization team of your language and help by translating WooCommerce. [Find more about using joining a language team and using GlotPress](https://make.wordpress.org/polyglots/handbook/tools/glotpress-translate-wordpress-org/).
-
-If WooCommerce is already 100% translated for your language, join the team anyway! We regularly update our language files and there will definitely be need of your help soon.
-
### Translating Video Tutorials
Another valuable way to help is by translating our growing library of WooCommerce video tutorials. Check out the [Translating Our Videos](https://docs.woocommerce.com/document/translating-our-videos/) doc and join in!
By translating video tutorials you'll be helping non-English speaking users and people affected by disabilities to get to grips with using WooCommerce for the first time, and to go on and create their businesses and make a living! That's something to be proud of and if you choose to dive into this area, we salute you.
-
-# Additional Resources
-
-* [General GitHub documentation](https://help.github.com/)
-* [GitHub pull request documentation](https://help.github.com/articles/about-pull-requests/)
-* [Translator Handbook](https://make.wordpress.org/polyglots/handbook/)
-* [WooCommerce Docs](https://docs.woocommerce.com/)
-* [WooCommerce Support](https://support.woocommerce.com)
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 0d1135a372b..3019353697d 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,31 +1,48 @@
-### EXPLANATION OF THE ISSUE
+
-
+
-### STEPS TO REPRODUCE THE ISSUE
+
-
+
-### SYSTEM STATUS
+
+
+## Prerequisites
+
+
+
+- [ ] I have searched for similar issues in both open and closed tickets and cannot find a duplicate
+- [ ] The issue still exists against the latest `master` branch of WooCommerce on Github (this is **not** the same version as on WordPress.org!)
+- [ ] I have attempted to find the simplest possible steps to reproduce the issue
+- [ ] I have included a failing test as a pull request (Optional)
+
+## Steps to reproduce the issue
+
+
+
+1.
+2.
+3.
+
+## Expected/actual behavior
+
+When I follow those steps, I see...
+
+I was expecting to see...
+
+## Isolating the problem
+
+
+
+- [ ] This bug happens with only WooCommerce plugin active
+- [ ] This bug happens with a default WordPress theme active, or [Storefront](https://woocommerce.com/storefront/)
+- [ ] I can reproduce this bug consistently using the steps above
+
+## WordPress Environment
```
-Grab the system status report from WooCommerce > System Status and paste it here between the `details` tags.
+Copy and paste the system status report from **WooCommerce > System Status** in WordPress admin here.
```
-
-
diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
new file mode 100644
index 00000000000..1caed3aa63c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Bug_report.md
@@ -0,0 +1,34 @@
+---
+name: "\U0001F41E Bug report"
+about: Report a bug if something isn't working as expected in the core WooCommerce
+ plugin.
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is. Please be as descriptive as possible; issues lacking detail, or for any other reason than to report a bug, may be closed without action.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Isolating the problem (mark completed items with an [x]):**
+- [ ] I have deactivated other plugins and confirmed this bug occurs when only WooCommerce plugin is active.
+- [ ] This bug happens with a default WordPress theme active, or [Storefront](https://woocommerce.com/storefront/).
+- [ ] I can reproduce this bug consistently using the steps above.
+
+**WordPress Environment**
+
+```
+Copy and paste the system status report from **WooCommerce > System Status** in WordPress admin.
+```
+
diff --git a/.github/ISSUE_TEMPLATE/Enhancement.md b/.github/ISSUE_TEMPLATE/Enhancement.md
new file mode 100644
index 00000000000..cb690414090
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Enhancement.md
@@ -0,0 +1,17 @@
+---
+name: "✨ New Enhancement"
+about: "If you have an idea to improve an existing feature in core or need something for development (such as a new hook) please let us know or submit a Pull Request!"
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md
new file mode 100644
index 00000000000..e7e5ee9021b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Feature_request.md
@@ -0,0 +1,17 @@
+---
+name: "\U0001F680 Feature request"
+about: "Suggest a new feature \U0001F389 We'll consider building it if it receives sufficient interest! \U0001F44D"
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/Support.md b/.github/ISSUE_TEMPLATE/Support.md
new file mode 100644
index 00000000000..33beabefdbe
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Support.md
@@ -0,0 +1,22 @@
+---
+name: "❓ Support Question"
+about: "If you have a question \U0001F4AC please see our docs or use our forums, helpdesk,
+ or Slack Community!"
+
+---
+
+We don't offer technical support on GitHub so we recommend using the following:
+
+**Reading our documentation**
+Usage docs can be found here: https://docs.woocommerce.com/
+
+If you have a problem, you may want to start with the self help guide here: https://docs.woocommerce.com/document/woocommerce-self-service-guide/
+
+**Technical support for premium extensions or if you're a WooCommerce.com customer**
+ from a human being - submit a ticket via the helpdesk
+https://woocommerce.com/contact-us/
+
+**General usage and development questions**
+- WooCommerce Slack Community: https://woocommerce.com/community-slack/
+- WordPress.org Forums: https://wordpress.org/support/plugin/woocommerce
+- The WooCommerce Help and Share Facebook group
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000000..0435d0f3331
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,33 @@
+### All Submissions:
+
+* [ ] Have you followed the [WooCommerce Contributing guideline](https://github.com/woocommerce/woocommerce/blob/master/.github/CONTRIBUTING.md)?
+* [ ] Does your code follow the [WordPress' coding standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/)?
+* [ ] Have you checked to ensure there aren't other open [Pull Requests](../../pulls) for the same update/change?
+
+
+
+
+
+### Changes proposed in this Pull Request:
+
+
+
+Closes # .
+
+### How to test the changes in this Pull Request:
+
+1.
+2.
+3.
+
+### Other information:
+
+* [ ] Have you added an explanation of what your changes do and why you'd like us to include them?
+* [ ] Have you written new tests for your changes, as applicable?
+* [ ] Have you successfully ran tests with your changes locally?
+
+
+
+### Changelog entry
+
+> Enter a short summary of all changes on this Pull Request. This will appear in the changelog if accepted.
diff --git a/.gitignore b/.gitignore
index 0612a52c0cf..6d673efc6ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,9 +6,14 @@ project.properties
.project
.settings*
.idea
+.vscode
+*.sublime-project
+*.sublime-workspace
+.sublimelinterrc
# Grunt
/node_modules/
+none
# Sass
.sass-cache/
@@ -33,9 +38,14 @@ tests/cli/vendor
/tmp
/tests/bin/tmp
/tests/e2e-tests/config/local-*.json
+/tests/e2e-tests/config/local.json
# Logs
/logs
# Composer
/vendor/
+contributors.md
+
+# Screenshots for e2e tests failures
+/screenshots/
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
index 07af2c45c90..ddbd18e1f4d 100644
--- a/.scrutinizer.yml
+++ b/.scrutinizer.yml
@@ -1,32 +1,37 @@
-filter:
- excluded_paths:
- - tests/*
- - apigen/*
- - dummy-data/*
- - i18n/*
- - includes/api/legacy/*
- - includes/legacy/*
- - includes/libraries/*
- - includes/updates/*
- - includes/gateways/simplify-commerce/*
- - includes/shipping/legacy-*
- - includes/wc-deprecated-functions.php
- - includes/class-wc-legacy-api.php
-
+tools:
+ php_code_sniffer:
+ config:
+ standard: WordPress
+ sensiolabs_security_checker: true
+ external_code_coverage:
+ timeout: 2500
checks:
php:
+ avoid_closing_tag: false
+ avoid_superglobals: false
+ coding_standard:
+ name: WordPress
+ no_exit: false
+ no_global_keyword: false
+ one_class_per_file: false
+ psr2_class_declaration: false
+ psr2_control_structure_declaration: false
+ psr2_switch_declaration: false
variable_existence: false
verify_access_scope_valid: false
verify_argument_usable_as_reference: false
verify_property_names: false
- no_global_keyword: false
- psr2_switch_declaration: false
- psr2_control_structure_declaration: false
- psr2_class_declaration: false
- one_class_per_file: false
- no_exit: false
- avoid_superglobals: false
- avoid_closing_tag: false
-
-tools:
- sensiolabs_security_checker: true
+filter:
+ excluded_paths:
+ - apigen/
+ - sample-data/
+ - i18n/
+ - includes/api/legacy/
+ - includes/gateways/simplify-commerce/includes/
+ - includes/legacy/
+ - includes/libraries/
+ - includes/shipping/legacy-*
+ - includes/updates/
+ - includes/vendor/
+ - includes/wc-deprecated-functions.php
+ - tests/
diff --git a/.stylelintrc b/.stylelintrc
index 4c93dd4476d..8bde8cb5c24 100644
--- a/.stylelintrc
+++ b/.stylelintrc
@@ -55,6 +55,6 @@
"selector-pseudo-element-colon-notation": "double",
"selector-pseudo-element-no-unknown": true,
"selector-type-case": "lower",
- "selector-no-id": [true, { "severity": "warning" } ],
+ "selector-no-id": [true, { "severity": "warning" } ]
}
}
diff --git a/.travis.yml b/.travis.yml
index b6cd8bce848..be05d8d4b13 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,33 +1,64 @@
language: php
+addons:
+ chrome: stable
+ apt:
+ packages:
+ - nginx
+
sudo: false
-# Test main supported versions of PHP and HHVM against latest WP. 5.2 is min supported version.
+# Test main supported versions of PHP against latest WP.
php:
- - 5.2
- - 5.3
- 5.6
- 7.0
- 7.1
- - hhvm
env:
- - WP_VERSION=latest WP_MULTISITE=0 PHP_LATEST_STABLE=7.1
+ - WP_VERSION=latest WP_MULTISITE=0
-# Additonal tests against stable PHP (min recommended version is 5.6) and past supported versions of WP.
+# Additional tests against stable PHP (min recommended version is 5.6) and past supported versions of WP
+# and code coverage report.
matrix:
+ fast_finish: true
include:
- - php: 5.6
- env: WP_VERSION=latest WP_MULTISITE=1 PHP_LATEST_STABLE=7.1
+ - php: 5.3
+ dist: precise
+ - php: 5.2
+ dist: precise
+ - php: 7.2
+ env: WP_VERSION=latest WP_MULTISITE=0 RUN_PHPCS=1 RUN_E2E=1
+ - php: 7.1
+ env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
+ - php: 7.3
+ env: WP_VERSION=5.0-beta5 WP_MULTISITE=0
+ allow_failures:
+ - php: 7.1
+ env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
before_script:
- - export PATH="$HOME/.composer/vendor/bin:$PATH"
+ - |
+ # Remove Xdebug for a huge performance increase:
+ if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then
+ phpenv config-rm xdebug.ini
+ else
+ echo "xdebug.ini does not exist"
+ fi
+ - export PATH="$HOME/.config/composer/vendor/bin:$PATH"
- bash tests/bin/install.sh woocommerce_test root '' localhost $WP_VERSION
- bash tests/bin/travis.sh before
script:
- bash tests/bin/phpunit.sh
- - bash tests/bin/travis.sh during
+ - bash tests/bin/phpcs.sh
+ - travis_retry bash tests/bin/run-e2e-CI.sh
after_script:
- bash tests/bin/travis.sh after
+
+# Specifies that Travis should create builds for master and release branches and also tags.
+branches:
+ only:
+ - master
+ - /^\d+\.\d+(\.\d+)?(-\S*)?$/
+ - /^release\//
diff --git a/.wordpress-org/screenshot-1.png b/.wordpress-org/screenshot-1.png
index 9b90d4fd05d..25dd507e20d 100644
Binary files a/.wordpress-org/screenshot-1.png and b/.wordpress-org/screenshot-1.png differ
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index c7aa5904ee1..32b1aff4ac3 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,5 +1,1012 @@
== Changelog ==
+= 3.5.0 - 2018-10-17 =
+* Feature - REST API v3. #20111
+* Feature - Option has been added on the inventory tab of the edit product page to set a low stock threshold for individual products. #20260
+* Feature - Add ability to export products by category to the CSV exporter. #20870
+* Feature - Ability to define custom product placeholder images that will resize to correct store aspect ratio. #20644
+* Enhancement - Excluded children categories from WP_Query in product shortcode if cat_operator=AND. #20207
+* Enhancement - Add anchor tag example to email template preview. #20246
+* Enhancement - Introduce is_paypal_supported_currency check in setup wizard. #20244
+* Enhancement - Payment method table reordering accessibility. #19844
+* Enhancement - Log errors from transaction emails with logger. #20203
+* Enhancement - Improved shipping calculator experience. Shows destination country and added context to calculate shipping link. #20345
+* Enhancement - On the fly image generation for frontend, if image sizes are missing. #20011
+* Enhancement - SelectWoo enabled product categories dropdown widget. #20617
+* Enhancement - Make it easier to read and act upon the outdated template notice. #20732
+* Enhancement - Styled date, time, etc. inputs in admin to match styling of other inputs. #21013
+* Enhancement - Show update notices on the System Status page for WordPress.org hosted Official WooCommerce extensions. #21073
+* Enhancement - Better wording for transactional emails. #21288
+* Fix - Check billing email is posted before using in WC_Cart::check_customer_coupons. #20180
+* Fix - Shipping postcode formatting when only posting a billing address. #20330
+* Fix - Correctly show/hide save card checkbox on tokenization form. #20506
+* Fix - orderby and order parameters in WC_Customer_Download_Log_Data_Store::get_download_logs() were ignored. #20931
+* Fix - Unslash city name to prevent double escape in tax settings. #21205
+* Fix - Updated phone validation logic. #21188
+* Fix - Fix weight and dimensions cache of variable products if childs doesn't have any of those params. #21244
+* Fix - Correctly replace images in the woocommerce_uploads folder with the placeholder image. #20848
+* Fix - Show parent variable product in shipping class admin screen when variation has shipping class. #21278
+* Fix - Correctly excluded administrators from "Customer list" report. #21304
+* Fix - Update quick edit logic to show/hide Stock qty and Backorders fields. #21301
+* Fix - Fix Layered Nav Widget where special HTML entities did not display correctly in the "Any %s" string. #21312
+* Fix - Set the is_checkout javascript parameter on any page that uses the checkout filter or shortcode. #21328
+* Fix - Fix cron_interval property support in WP_Background_Process. #21353
+* Fix - CSS Changes to make text fields line up on the shipping settings page. #21247
+* Fix - Add extra null check to fix an issue with select payment fields using disabed select as placeholders. #21391
+* Fix - Don't modify attributes orderby when sorting by name. #21408
+* Fix - Allow saving a stock quantity of 0 using quick edit. #21447
+* Fix - Change the query used to save session data to the database to protect against deadlocks. #21455
+* Fix - Make sure default category tooltip is rendered when the image column is deactivated. #21410
+* Fix - Fix warning when using logger instance in woocommerce_logging_class filter. #21448
+* Fix - Use uppercase "ID" when sorting product queries by ID. #21461
+* Fix - Consistently escape the gateway ID in the checkout payment method template. #21439
+* Fix - Avoid treating HTTP 301 and 302 codes as failures for webhooks. #21491
+* Fix - Add address_1 to shipping packages info in WC_Cart:: get_shipping_packages to make it work correctly in address formatting functions. #21493
+* Fix - Don't fire two of the same action when saving shipping settings. #21494
+* Fix - Remove double condition for address line 2 in `WC_Countries::get_default_address_fields`. #20629
+* Fix - Correctly handle shorthand values for memory_limit in php.ini. #21557
+* Fix - Product shortcode numeric term slug matching. #21560
+* Fix - Remove the erasure tools links from the descriptions of the erasure settings for users without the manage_privacy_options capability. #21565
+* Fix - Don't double urldecode posted variation attributes. #21570
+* Fix - Don't double-sanitize cart images. #21574
+* Fix - Check if ID exists and is not empty before set Product's download ID in API. #21588
+* Fix - Ensure wp_list_pluck() gets a array and not possibly null in WC_Product_Data_Store_CPT::update_attributes. #21591
+* Fix - Trim CSV header rows to prevent leading/trailing whitespace issues. #21614
+* Fix - Show draft products in previews on unsupported themes. #21619
+* Fix/Tweak - Fire `woocommerce_grant_product_download_access` hook after the download has its ID set. #20905
+* Fix/Tweak/Performance - Change wp_woocommerce_sessions primary key to session_id. #21245
+* Tweak - Show empty terms in admin product category filter dropdown. #20324
+* Tweak - Don't force default token gateway active by default. #20125
+* Tweak - Move notice output to hooked in functions. #19794
+* Tweak - Apply order bulk actions in chronological order. #20338
+* Tweak - Updated Emogrifier to 2.0. #20547
+* Tweak - Avoid using wp.template (eval) in add-to-cart-variation.js. #19496
+* Tweak - Hide Preview button when creating new products, as most fields aren't set up for it. #20650
+* Tweak - For guests, store all address fields to the session whilst placing an order. #20665
+* Tweak - Removed 'ajax_add_to_cart' class from 'Read more' button. #20690
+* Tweak - Removed unnecessary checkout form change trigger on load of the checkout page. #20655
+* Tweak - Add image size filters to wc_get_product_attachment_props(). #20722
+* Tweak - Only display the current site's tables for a multisite install when viewing the system status. #20731
+* Tweak - include the file path and line number where a fatal error occurred in the fatal errors log. #20787
+* Tweak - Cast tax rate to float so that it can be treated as number further on in the code. #20910
+* Tweak - Send webhooks using Action Scheduler. #20030
+* Tweak - Update customer's ip address on successful payment. #21038
+* Tweak - Changed wc_clean to checking for valid utf8 for line items and password. #20993
+* Tweak - Add to cart notice actions (View cart/Continue shopping) now have tabindex 1 for improved accessibility. #21108
+* Tweak - Remove icanhazip from geolocation services. #21198
+* Tweak - Remove unnecessary aria-required attributes from product reviews template. #21211
+* Tweak - Added hidden label for screen readers on checkout address line 2 input. #21193
+* Tweak - Remove empty space in mini-cart template. #21261
+* Tweak - Tax display in cart now depends on whether customer is tax exempt. #21292
+* Tweak - Change sort dropdown option "Sort by newness" to "Sort by latest". #21311
+* Tweak - Sanitize endpoint slugs upon saving. #21355
+* Tweak - Ignore converting float meta value for registered post meta. #21333
+* Tweak - Remove 'order_again' query string to avoid multiple re-orders. #21444
+* Tweak - Remove Netherlands Antilles from the North America continent definitions. #21449
+* Tweak - Display label and meta on the same line in order emails to match frontend Order Details styling. #21456
+* Tweak - Use wp_get_upload_dir for geolite DB path. #21550
+* Performance/Tweak - Use post_author for the order customer instead of '_customer_user' meta data. #17895
+* Performance - Exclude frontend include from REST API calls. #20000
+* Performance - Improve performance of the query to delete version transients by removing unneeded "ORDER BY". #21274
+* Dev - REST API - Allows oAuth1.0a authentication under SSL.
+* Dev - REST API - Fix position param for images. #20497
+* Dev - REST API - Handle children products deletion regardless of type. #20670
+* Dev - Added woocommerce_increase_coupon_usage_count and woocommerce_decrease_coupon_usage_count action hooks to increase extensibility of Coupons. #19981
+* Dev - Add endpoints to account menu items filter. #19980
+* Dev - Added qty param to `wc_add_to_cart_message` filter. #19817
+* Dev - Added `woocommerce_search_products_ids` filter. #20160
+* Dev - Introduced `woocommerce_cart_calculate_shipping_address` field to allow manipulation of cart shipping calculator data. #20046
+* Dev - Introduced `woocommerce_shipping_calculator_enable_country` filter. #20046
+* Dev - Pass product id to backorder notification. #20416
+* Dev - Added woocommerce_cart_shipping_total filter to control shipping display. #20591
+* Dev - Refactor "Order again" handling to separate logic better. #20606
+* Dev - Added 'woocommerce_products_admin_list_table_filters' filter to make it easier to customize the products list table filters. #20634
+* Dev - Added `woocommerce_shipping_method_add_rate_args` and `woocommerce_shipping_method_add_rate` filters. #20633
+* Dev - Added `woocommerce_coupon_validate_user_usage_limit` filter. #20630
+* Dev - Add hooks needed for product custom tables feature plugin. #20520
+* Dev - Added new filter to 'Item in quotes' translation for messages. #20714
+* Dev - Add 'woocommerce_shutdown_error' hook triggered on request termination with an error. #20787
+* Dev - New filter 'woocommerce_admin_meta_boxes_variations_count' to customize the shown count of variations. #21067
+* Dev - Added ability to query products that have a field set in wc_get_products/WC_Product_Query using the wildcard symbol '*'. #21162
+* Dev - Added a JavaScript events before and after the order total recalculation on the Edit Order page. #21181
+* Dev - Check for `needs_payment` instead of `has_status( 'pending' )` in PayPal PDT handler for custom order status support. #21200
+* Dev - Added form action hooks for edit account and login templates. #21248
+* Dev - Add action for when system tools are run. #21270
+* Dev - Add - woocommerce_restock_refunded_items filter to control default state of the restock option when refunding items on an order. #21314
+* Dev - Add an extensible/swappable job queue via WC_Action_Queue and WC_Queue_Interface. #20030
+* Dev - Use WC_Action_Queue for schedule and delivery of webhooks. #20030
+* Dev - Include Action Scheduler v2.1.0 and use it for the default job queue. #21424 / #20030
+* Dev - Save reviews under the 'review' comment type. #21305
+* Localization - Updated IT provinces. #20286
+* Localization - Eircode validation. #20330
+* Localization - Disable postcode requirement for Bahrain. #21103
+* Localization - Make postcode field optional and hidden for Nigeria and label State. #21056
+* Localization - Make Romania state selection mandatory. #21180
+* Localization - Make city field optional and hidden for Singapore addresses. #21016
+
+= 3.4.6 - 2018-10-11 =
+* Fix - Security issues
+* Fix - Allow percent coupons with sale restrictions to apply to carts with sale items in them. #21241
+* Fix - Prevent multiple slashing of variation's SKU. #21019
+
+= 3.4.5 - 2018-08-29 =
+* Fix - Tweak sanitization when resetting password cookie. #20901
+* Fix - Use `+` instead of `array_merge` when appending parent to tax class to fix issues with numeric tax class names. #20916
+* Fix - Correct translation for North Khorasan. #20972
+* Fix - Unify scroll-to notices for all browsers. #20992
+* Fix - Prevent multiple slashing of variation's SKU. #21019
+* Fix - Variation image in fullscreen now shows correct caption for the respective image. #21022
+* Fix - Vertically center admin order action buttons. #21053
+* Fix - Correct context for shipping packages translation. #21065
+* Fix - Add permission checks for installing Jetpack on the setup wizard. #21072
+* Fix - Use refund currency instead of store default currency when displaying refund amount in the edit order screen. #21106
+* Fix - Fix a typo in REST API customer schema. #21171
+* Fix - Use entire sentence for checkout address_2 placeholder string. #21186
+* Fix - Only suppress comments number on unsupported theme shop page. #21191
+* Fix - Don't allow users without manage_product_terms permissions to create categories using the product importer. #21192
+* Fix - Correct sale coupon restriction logic. #21219
+
+= 3.4.4 - 2018-07-25 =
+* Fix - Only wordwrap plain email content. #20723
+* Fix - Better escaping on product quick edit. #20740
+* Fix - Log file deletion. #20730
+* Fix - Search feature in Webhooks and REST API keys settings. #20706
+* Fix - Notices in REST API keys settings screen. #20706
+* Fix - add a check to prevent WC_Geolite_Integration::get_country_iso() from generating a PHP undefined index notice when unable to determine the country code for a given IP address. #20608
+* Fix - Variable product stock display if parent is stock managed and not the variation. #20661
+* Fix - Correctly hide cost for zero cost shipping methods after placing orders. #20663
+* Fix - Disabled autocomplete to prevent datepicker overlapping. #20687
+* Fix - Prevent a PHP notice in the setup wizard when store state is not selectable. #20695
+* Fix - Fix logic error in WC_Product_CSV_Exporter::get_column_value_stock. #20753
+* Fix - Fixed missing notice about no product variation matching. #20762
+* Fix - Correct PHPDocs in exporter class. #20861
+* Fix - Prevent Mailchimp redirection during the Setup Wizard. #20879
+* Fix - Don't hide coupon form after coupon has been applied. #20889
+* Tweak - Remove (optional) text from Address line 2 field. #20622 #20639
+* Tweak - Removed 100% width for images on single product page using 2017 theme. #20818
+* Tweak - Add margin to best selling product title in the dashboard widget to avoid overlapping the sparkline. #20849
+* Tweak - Re-add woocommerce_order_details_after_customer_details_filter removed during WC 3.2. #20886
+* Dev - Added woocommerce_calculate_item_totals_taxes filter. #20586
+* Dev - Links to next and previous page sent out in HTTP header via REST API fixed for some endpoints. #20686
+* Dev - Better wc_format_phone_number cleaning. #20637
+
+= 3.4.3 - 2018-06-20 =
+* Fix - Fix label for the price filter widget on RTL sites. #20417
+* Fix - Checkout: stopPropagation when payment method selected so description tips show on radio buttons. #20432
+* Fix - Shipping zone settings: fixed title for shipping methods without settings. #20441
+* Fix - Ensure custom Webhook topic selections are correctly saved in admin. #20406
+* Fix - Webhook bottom bulk actions. #20445
+* Fix - Fixes multisite orders dashboard widget to use order number rather than ID. #20457
+* Fix - Add check to ensure download log FK does not exist before adding it. Update routine will cleanup any duplicates. #20478
+* Fix - IPv6 support with HTTP_X_FORWARDED_FOR header. #20479
+* Fix - Avoid setting wrong prices when syncing grouped products with children. #20482
+* Fix - Separation of explode and end functions in two lines. End function should get a reference as parameter. #20500
+* Fix - Initialize payment gateways before running bulk actions so gateways can listen for events. #20502
+* Fix - Cast shipping total to a float so incl. tax shows only when needed. #20531
+* Fix - Fix automatic stock status updates based on stock level. #20573
+* Fix - Improved sanitize_special_column_name_regex trim to fix column matching when importing CSVs. #20486
+* Fix - Force importer log table to wrap long columns. #20534
+* Fix - Rest API: Prevent errors if variation parent is invalid and cannot be read. #20572
+* Fix - Rest API: Remove legacy API enabled check from auth endpoint. #20499
+* Fix - Display products on sub-subcategories when sorting parent category by price. #20579
+* Fix - Set order status to refunded when a PayPal transaction is refunded. #20574
+* Fix - fix undefined index in abstract-wc-widget. #20544
+* Fix - Round items for order total when recalculating order values to match cart. #20533
+* Fix - Removed mysql transactions when updating order status, tweaked caching, and improved version transient cleanup to prevent possible deadlocks on checkout. #20537
+* Tweak - Added a message to promote Wootenberg when running Gutenberg feature plugin. #20524
+* Tweak - Added a warning notice before removing personal data from orders in bulk. #20481
+* Dev - generate_select_html and generate_multiselect_html functions again support the usage of integer-keyed arrays as available values. #20569
+* Dev - Allow order billing fields to use a provided 'value'. #20424
+
+= 3.4.2 - 2018-06-05 =
+* Fix - Flexslider gallery fixes for RTL sites, and for variation image switching. #20328 #20321
+* Fix - Allow forms to be submitted when the password strength library fails to load. #20362
+* Fix - Personal data exporter: Do not export a customer data group containing no data. #20347
+* Fix - Fix navigation notification in settings when clicking save. #20335
+* Fix - Show discount amount for free shipping coupons. #20334
+* Fix - Fixed cache clearing for category children for sites running object caching. #20308
+* Fix - Use correct escaping on select2 placeholders. #20364
+* Fix - Order by price clauses when searching within terms. #20391
+* Fix - Clear needs_processing transient when adding a product to an order. #20390
+* Enhancement - Permission_id constraint checks on install. #20366
+* Dev - Added order to "woocommerce_order_is_vat_exempt" filter arguments. #20365
+* Localization - Disable states for Bahrain. #20363
+* Localization - Disable states for Luxemberg. #20389
+
+= 3.4.1 - 2018-05-29 =
+* Fix - Fix webhook admin filtering URLs. #20236
+* Fix - Add missing wp_unslash calls to product data meta box to prevent quote characters being escaped on save. #20235
+* Fix - Display price filter widget in LTR mode on RTL sites. #20221
+* Fix - Refactor WC_Coupon constructor to allow for passing in coupon objects. #20193
+* Fix - Path field in advanced CSV importer was broken due to an esc_url call. #20191
+* Fix - Prevent shipping method instances trying to save settings on non-instance screens. #20217
+* Fix - Wrapper function to get full mysql version string with mariadb handling. #20231
+* Fix - woocommerce_pagination had some extra white space. #20214
+* Fix - If a file size cannot be read, ignore range headers to prevent offsite downloads being 0kb. #20205
+* Fix - Allow HTML when using `wc_attribute_label()`. #20202
+* Fix - Update address-i18n.js to prevent appending multiple "(optional)" labels. #20195
+* Fix - Check plugin properties exist when listening to auto_update_plugin hook. #20234
+* Fix - Add extra checks in `get_canonical_package_rate_ids` to prevent notices. #20237
+* Fix - Fix infinite loop with importing tax rates. #20253
+* Fix - Echo attribute label for "empty" default option. #20256
+* Fix - Fix download sample tax rates URL format. #20272
+* Fix - Product properties should not be accessed directly PHP notice when calling `wc_get_product_attachment_props`. #20282
+* Fix - If flexslider is disabled, gallery images also need to trigger photoswipe on click. #20290
+* Fix - Product import file uploads on windows servers. #20273
+* Fix - Fix variation attribute selection via the cart page/query string. #20293
+* Fix - Add greater specificity to required styling in 2017 theme. #20296
+* Enhancement - Export legacy paypal meta data in personal data exporter. #20200
+* Enhancement - Improve performance of `wc_update_340_states` update routine to help prevent timeouts. #20241
+* Dev - Remove red styling for PHP notice if using > 5.6. #20294
+* Dev - Add an action hook after printing the cart item name. #20190
+* Localization - Use "payment tokens" terminology in exports. #20197
+
+= 3.4.0 - 2018-05-23 =
+* Feature - GDPR: Tools to export WooCommerce data using the new export functionality in WordPress 4.9.6. #19330
+* Feature - GDPR: Tools to bulk anonymize order data in admin. #19330
+* Feature - GDPR: Tools to turn off company/address-2/phone checkout fields to avoid unnecessary data collection, and a toggle to choose how required fields are presented. This is available via the Customizer. #19637
+* Feature - GDPR: Tools in the Customizer to change the terms and conditions checkbox label on the checkout. #19637
+* Feature - GDPR: Tools to define a privacy policy for the account page and checkout page in "account privacy" settings and within the Customizer. #19747
+* Feature - GDPR: Tools to automatically clean up and remove order personal data after a set time period. #19743
+* Feature - GDPR: Added privacy snippet which works with the new privacy page functionality in WordPress 4.9.6. #19749
+* Feature - Added a new order widget to the dashboard (on multisite) so you can see your orders across multiple stores on the same WordPress network. #17598
+* Feature - Added "display name" input on the My Account page. #19078
+* Feature - Product search improvements including stopword support and support for searching for multiple products at the same time. #19096
+* Feature - Cash on Delivery gateway can be enabled/disabled for specific shipping methods instead of only method types. #19221
+* Feature - Add wildcard email support for coupons. #19331
+* Feature - Added support for the GeoLite2 library as a replacement for the deprecated MaxMind GeoIP library. #19419
+* Feature - Added tool for cleaning up download permissions table. #19922
+* Tweak - GDPR: Improved appearance of checkout field 'descriptions' (if used) to make them more useful for privacy notices. #19637
+* Tweak - GDPR: Improved related data cleanup when deleting users/orders. #19330
+* Tweak - GDPR: Notice about HTTPS as a requirement in admin if missing. #19756
+* Tweak - GDPR: Improved the checkout (payments) settings screen, moved page options to a new "advanced" section, and made an "Accounts and Privacy" section. #19703
+* Tweak - GDPR: Hash customer email address in download URLs to protect privacy. #18957
+* Tweak - GDPR: Add highlight to T&C checkbox if not checked to show it needs to be checked. #19177
+* Tweak - GDPR: Automatically purge old logs after 30 days. #19920
+* Tweak - GDPR: Only log Webhook body if WP_DEBUG is enabled. #19914
+* Tweak - GDPR: Store less PII in PayPal standard. #19914
+* Tweak - Only show admin notices on WooCommerce screens/plugins/dashboard. #19772
+* Tweak - Standardize stock update messages in admin and correctly log who performed the action. When an order note is added after modifying stock manually, update order notes display via AJAX. #18080
+* Tweak - Rollback if payment complete or update status fails to prevent partial order updates on failure. #18175
+* Tweak - Made the system status tool which purges user carts also purge persistent carts. #18492
+* Tweak - Display whether or not external object cache is enabled in system status report. #18595
+* Tweak - Display zero value when using shipping classes. #18624
+* Tweak - Fixed settings table styling on mobile. #18655
+* Tweak - Updated Flexslider to version 2.7.0. #18779
+* Tweak - Enable screen options for list screens. #18817
+* Tweak - Don't call WC_Install::install() on downgrades. #18818
+* Tweak - Remove user login from reset password link to protect personally identifying info. #18820
+* Tweak - Added a function to return a list of custom tables to aid with cleanup. #18831
+* Tweak - Enable going backwards in the setup wizard. #18921
+* Tweak - Make sure terms page exists and isn’t trashed before using it. #18993
+* Tweak - Toggle when clicking anywhere in toggle row during setup wizard. #19035
+* Tweak - Use `read_product` permissions instead of `edit_product` for ajax product search. #19087
+* Tweak - Add `priceSpecification` property with `valueAddedTaxIncluded` to product structured data. #19091
+* Tweak - Importer remembers mappings across imports. #19110
+* Tweak - Made coupon total displayed in cart more consistent. #19166
+* Tweak - Remove forced CSS line-heights to improve text input displays across different browsers. #19174
+* Tweak - When loading default attributes/variation, if there is no longer a match, reset the form and hide the notice #19190
+* Tweak - Removed admin product type column from core and made it into a free feature plugin. #19192
+* Tweak - Use `woocommerce-no-js` class to hide JavaScript-only forms and content. #19199
+* Tweak - Activate plugins during installation process even if directory doesn't match slug. #19200
+* Tweak - Allow category and attribute ids in the `products` shortcode instead of only slugs. #19204
+* Tweak - Invalidate cart items when important props like product type are updated. #19255
+* Tweak - Don't use mysql functions directly on system status page to prevent errors if they are disabled. #19281
+* Tweak - Replaces `have_posts` with `woocommerce_product_loop` which looks to see if there are products, or if the loop is going to be showing something else. #19288
+* Tweak - Delete widget options and order notes on uninstall. #19371
+* Tweak - Add unique names to all nonces in template fields and forms. #19387
+* Tweak - Enable using the tab key to select elements in selectWoo dropdowns. #19416
+* Tweak - Added autocomplete attributes to form elements for better autocomplete support. #19426
+* Tweak - Removed PayPal line item limit and ensured URLs are shorter than maximum length. #19493
+* Tweak - Disable Gutenberg editor on products posts. #19543
+* Tweak - Improvements around UI and wording of store setup step in setup wizard, a revamped extras step, and other improvements.
+* Tweak - Only push images to lightbox if an image is found. #19568
+* Tweak - Added and improved notices around old PHP versions and disabled geolocation on PHP 5.4 or lower. #19573
+* Tweak - The `manage_stock` field in the product API can return a `mixed` type instead of `boolean` for variations. #19598
+* Tweak - Link product import/export to WordPress import/export capabilities. #19602
+* Tweak - Use ` ` to separate asterisks in required fields to prevent awkward line breaks. #19610
+* Tweak - Load meta box input values using CRUD and edit context. #19670
+* Tweak - Scroll to notices on cart/checkout for better mobile visibility. #19699
+* Tweak - Add filter to coupon URL on "Edit order" screen. #19777
+* Tweak - Throw error if order can't be loaded on checkout. #19802
+* Tweak - Remove deprecated freegeoip service from geolocation. #19841
+* Tweak - Allow arrays of query vars in wc_get_orders and wc_get_products. #19848
+* Tweak - Invalidate fragment cache on theme switch.
+* Tweak - Include select tags when saving payment details temporarily in checkout.js. #19854
+* Tweak - Update - Include pending products in export. #19928
+* Tweak - Deprecate woocommerce_ajax_added_order_items action in favor of more useful action. #19933
+* Tweak - Enable touch-to-zoom on touch devices to make photoswipe more easily accessible. #20002
+* Tweak - Wizard: List out all plugins to be installed upon proceeding to the next step, with a highlight on hover indicating relevant settings. #19952
+* Tweak - Hide/show password strength meter instead of removing/inserting password strength meter. #20006
+* Tweak - Added support for HTTP_RANGE requests (used by iOS devices) to Force download method. #19984
+* Tweak - Replaced protocol-relative URLs for thumbnails in the cart and mini-cart with protocol-specific URLs to prevent problems with URLs that include port section. #19934
+* Tweak - In CSV exports, wrap cell in ' rather than just prepending to escape values. #20041
+* Tweak - Add JS listeners for reloading/reinitializing order items in edit-order page. #20082
+* Fix - Properly set orderby and order when calling WC_Customer_Download_Data_Store::get_downloads(). #1862
+* Fix - Set maxlength for order item meta key to avoid values disappearing if too long. #18918
+* Fix - Remove hardcoded /wp-content check for downloads. #18961
+* Fix - Made get_on_sale_products respect the setting to hide outofstock products. #18984
+* Fix - Prevent shortcode [product_page] redirecting to the actual product's page after add to cart. #19043
+* Fix - Make the "main term" logic match for both the breadcrumb and product categories widget. #19044
+* Fix - Check parent status too when seeing if variation is purchasable. #19045
+* Fix - Fix uppercasing of accented characters. #19086
+* Fix - Do not allow updating parent ID from variations after created. #19097
+* Fix - Ensure coupon amount is not empty to prevent non-numeric value errors. #19098
+* Fix - Ensure shop archive works correctly when `paged=1` is in the URL. #19104
+* Fix - Ensure orders created with `woocommerce_adjust_non_base_location_prices` filter active have the same cost on frontend and admin. #19109
+* Fix - Handling in the CLI to prevent `Resource does not exist` errors when using commands of a certain format. #19123
+* Fix - Use subtotal when calculating discounts in admin/orders to ensure prices are the same as on the frontend. #19159
+* Fix - Use `kses` to process download names to prevent escaped HTML displaying in emails.
+* Fix - Remove translation from Thailand state file to prevent PayPal errors around unsupported characters. #19219
+* Fix - Fix auto-select variation URLs with special characters in them. #19283
+* Fix - Introduced `wc_round_discount` and improved consistency of discount rounding. #19291
+* Fix - Only add schema for ratings to structured data when ratings are enabled. #19310
+* Fix - Prevent default state applying unless the country was also unset in JS state/country inputs. #19338
+* Fix - Escape quantity labels correctly to prevent broken html. #19375
+* Fix - Delete orphaned variations after product import. #19378
+* Fix - Ensure API credentials exist before defining PayPal refund support. #19380
+* Fix - Force word-wrapping in the log viewer to prevent layout-breaking long lines. #19503
+* Fix - Removes permission checks that were preventing webhooks from displaying properly when no post object existed. #19508
+* Fix - Empty cart after completing PayPal payment. #19509
+* Fix - Strip tags on aria-labels in Add to Cart template to prevent broken HTML. #19522
+* Fix - Update post_modified date when saving products and variations but no other product data. #19595
+* Fix - Clear comment count transient when cleaning product transients to prevent incorrect comment count displays. #19664
+* Fix - Load gateways before order is saved/email is triggered to ensure all information gets sent/processed. #19667
+* Fix - Clear shipping transient when saving shipping method on zones screen. #19668
+* Fix - Handle escape characters for fputcsv to work around PHP standards issues. #19678
+* Fix - Cast post IDs to integers in admin meta boxes. #19710
+* Fix - Fix CSV unescaping of negative numbers in download expiry/limit columns. #19732
+* Fix - Don't load unsupported theme functionality if shop page ID is -1. #19822
+* Fix - Select and display "Downloadable" option in product admin filter when selected. #19876
+* Fix - Add sort handle column when adding new tags. #19875
+* Fix - More thorough CSV importer cleanup. #19877
+* Fix - Fix gallery switching when image is the same #19878
+* Fix - Ensure coupon amount is always returns as a float value #19889
+* Fix - No update available message after activating subscription that has a valid update. #19831
+* Fix - Include scheduled products in CSV export. #19907
+* Fix - Generator tag actions should be filters. #19946
+* Fix - WC API should not try to create a product image when creating a product variation if an empty image is passed. #19971
+* Fix - Force settings API settings to autoload by default. #19998
+* Fix - Cart html5 validation events when using keyboard. #20001
+* Fix - Don't show stock status fields in external product quick-edit. #20005
+* Fix - Prevent an infinite loop if 2 grouped products are linked. #20020
+* Fix - Switch stock_status when manage stock gets changed to prevent being out of stock if stock quantity is > 0. #20021
+* Fix - When duplicating variation, set the date to null. #20083
+* Fix - Fix rounding of line items for orders to match cart. #20086
+* Fix - Remove hardcoded border in email template. #20090
+* Fix - Prevent autofocus on checkout. #20123
+* Fix - Recalc taxes if address changes in API. #20137
+* Dev - Made wc_query_string_form_fields handle strings. #20162
+* Dev - Added refunded_payment prop to orders for determining if payment was refunded via API. #18196
+* Dev - Added extra params to `woocommerce_order_get_downloadable_items`. #18408
+* Dev - Store shipping method ID and instance ID in separate fields instead of both in one serialized field. #18483
+* Dev - Add `woocommerce_rest_insert_system_status_tool` hook that fires after executing a REST system status tool. #18505
+* Dev - Gallery meta box is now powered by CRUD. #18511
+* Dev - Refactor woocommerce_wp_select so it could be used for a multiselect. #18536
+* Dev - Added ability to declare sanitize_callback in settings API. #18554
+* Dev - Added support for additional HTML5 input types for settings/checkout forms. #18594
+* Dev - Made 'woocommerce_email_downloads_column_' hook format aware. #18600
+* Dev - Add missing `woocommerce_update_options__` actions for settings pages that override save method. #18609
+* Dev - Allow default value for single_select_country and multi_select_countries. #18754 #18756
+* Dev - Added `grouped_form` class to grouped product `form` element. #18786
+* Dev - Mini cart item link now respects value of $product_permalink. #18979
+* Dev - Added `woocommerce_coupon_get_items_to_validate` filter to enable excluding products from coupon validation. #19002
+* Dev - Added `woocommerce_persistent_cart_enabled` filter. #19027
+* Dev - Added `woocommerce_admin_order_item_coupon_url` filter. #19777
+* Dev - Replaced calls to `exit` with `wp_die` in the ajax methods to enable unit testing of those methods.
+* Dev - Introduce `woocommerce_coupon_custom_discounts_array` filter to allow post processing on custom coupons. #19148
+* Dev - Move jQuery UI styles into WooCommerce assets folder and load them from there. #19173
+* Dev - Added `woocommerce_coupon_validate_expiry_date` filter to enable modifying the coupon expiry date check. #19228
+* Dev - Added `woocommerce_shipping_calculator_enable_state` filter to enable disabling state section in shipping calculator. #19241
+* Dev - Added `woocommerce_bacs_process_payment_order_status` filter allowing plugins to change the order status to the BACS gateway. #19311
+* Dev - Added `woocommerce_coupon_sort` filter to allow plugins to override the default coupon apply order. #19339
+* Dev - Added `woocommerce_before_output_product_categories` and `woocommerce_after_output_product_categories` filters. #19363
+* Dev - Added general `woocommerce_form_field` filter to make it easier to filter all of the form fields. #19388
+* Dev - Added `woocommerce_install_get_tables` filter to enable plugins to register new, WooCommerce-specific tables. $19436
+* Dev - Use `get_variation_price` method in structured data to grab min/max so filters are ran. #19527
+* Dev - Added `woocommerce_helper_suppress_connect_notice` filter to enable suppressing the admin WordPress.com connection message. #19599
+* Dev - Moved all photoswipe styles to `photoswipe.css` to make it easy to dequeue all the photoswipe styles. #19673
+* Dev - Slash meta values before updating values in the data stores. #19675
+* Dev - New wc_selected method to handle array key conversion to int. #19705
+* Performance - Optimized saving of orders. Adds a transient for needs_processing, and only saves changes when saving order items. #18538
+* Performance - Refactored the SQL query for `WC_Customer_Download_Data_Store::get_downloads()` to fetch available downloads faster. #18559
+* Performance - Split the layered nav counts into multiple transient records by taxonomy and added a filter to allow bypassing caching. #19225
+* Performance - Removed duplicate `SET SESSION SQL_BIG_SELECTS=1` queries. #19502
+* Performance - Avoid storing coupon `_used_by` data to prevent database bloat. #19669
+* Performance - Introduced new wc_get_product_class() and wc_product_class() functions. #19639
+* Performance - Series of tweaks aimed at reducing the number of queries performed #19918
+* Template - Update cart coupon button from input to button type. #19059
+* Template - Added `woocommerce-form-register` class to registration form. #19486
+* Template - Added escaping to publish date. #19530
+* Template - Added a template file for recent product reviews. #19711
+* Template - Made add to cart templates more consistent between product types. #19666
+* Localization - Switched Georgian Lari symbol to new UTF symbol. #19603
+* Localization - Use ISO county codes for Irish states. #19658
+* Localization - Use ISO county codes for BD states. #19744
+* Localization - LR-Liberia states. #19709
+* Localization - Update ZA tax rate. #19909
+* Localization - Various spelling, grammar fixes, and phrasing improvements.
+* Localization - Fix missing Bahrain country code. #20061
+
+= 3.3.5 - 2018-04-10 =
+* Fix - Shop page notice should not appear when editing the "Hello World!" page.
+* Fix - Inconsistent order item refund sign.
+* Fix - Change `wc_get_price_excluding_tax` to not round the return value so calculations in admin are not pre-rounded.
+* Fix - Use minimum price instead of maximum price when ordering variable products from low to high on term archives.
+* Fix - `order` and `orderby` on shop page when using rewrite rules.
+* Fix - Ajax loading spinner when using twentyseventeen theme.
+* Fix - Out of Stock products change stock to On Backorder when imported to update existing products.
+* Fix - Visibility dropdown not responding in quick edit when stock management is disabled.
+* Fix - Featured paramenter in products endpoint on REST API.
+* Fix - Linebreaks in order item meta.
+* Fix - Product rating count when updated by admin.
+* Tweak - Define array before attempting to append to it.
+* Tweak - Change WC WP-CLI commands default per_page value to 100.
+* Tweak - Ensure background process class returns `data` as an array.
+* Tweak - Increase orders table checkbox column size on small devices.
+* Tweak - Better support for infinite scroll in Jetpack.
+
+= 3.3.4 - 2018-03-20 =
+* Fix - Fixed undefined index after running setup wizard two times on fresh install.
+* Fix - wc_get_loop_class; force columns to be a minimum of 1.
+* Fix - Added loading spinner to WC panels in menu admin.
+* Fix - Use relative scheme for AJAX endpoint to avoid errors when using a mix of HTTP and HTTPS.
+* Fix - Fix SelectWoo templateSelection property.
+* Fix - Layered nav support on unsupported theme archives.
+* Fix - Prevent full refresh when editing store notice in the customizer.
+* Fix - Only append tax label in email content if taxes are enabled.
+* Fix - More reliable Jetpack detection.
+* Fix - Check if product has weight before calculate weight total in cart.
+* Fix - Correctly handle default ordering on the search page.
+* Fix - Fix default product category handling in installer.
+* Fix - Properly check slugs when updating attributes.
+* Fix - Use gallery thumbnail size for variation image switcher.
+* Fix - Clear subcategory cache when updating product categories.
+* Fix - Round fractional cents when out of base.
+* Fix - Inherit 'is variation' from existing attribute during csv import.
+* Fix - Set is_shortcode loop prop when outputting subcategories.
+* Fix - Reload gateways after updating the order.
+* Tweak - Use wc_get_default_products_per_row as the default for product shortcodes.
+* Tweak - Add post_excerpt to product search.
+* Tweak - Update the description of the user tracking notice in the onboarding wizard.
+* Tweak - Add extra data in order mobile view (status and date).
+* Tweak - Add profile link to order screen.
+
+= 3.3.3 - 2018-02-21 =
+* Fix - Fixed is_numeric check which was affecting order subtotals/totals when using comma decimal separator.
+* Fix - Add missing direct script access checks to loop templates.
+* Fix - Added wp-post-image class to main image so variation images are swapped correctly.
+* Fix - API - Adjusted schema for products shipping_class_id to integer.
+* Fix - Made init tooltips event more specific to avoid conflict with Product Invoices extension.
+
+= 3.3.2 - 2018-02-20 =
+* Fix - Fixed admin product SKU searching and searching non-published products.
+* Fix - PHP7.1 notice when image height is empty.
+* Fix - Prevent repeated update_option calls on page load due to php type juggling.
+* Fix - Only do unsupported template rendering in the loop to prevent conflicts with other shortcodes on the shop page.
+* Fix - Don't prepend regular shortcodes with categories.
+* Fix - If using get_catalog_ordering_args. remove the args when finished.
+* Fix - Remove "Type" column on attributes table by default unless custom types are defined.
+* Fix - Use verbose page rules when shop is in the URL, including shop base with category, to prevent 404s.
+* Fix - Set woocommerce_hide_invisible_variations to true so disabled variation attributes are hidden on product pages.
+* Fix - Help tip for webhook status.
+* Fix - Shipping zone documentation help link was printing wrong.
+* Fix - Stop background processing images when disabled via the filter.
+* Fix - Only search when a search term is provided. Ignore empty strings.
+* Fix - Fix check for external resources.
+* Fix - Show full date for future orders.
+* Fix - Prevent JS error is 'orders' row is disabled on order screen.
+* Fix - Fix save of tax settings when no changes have been made.
+* Fix - Add nonce to logout link on my account page so you do not need to confirm the action.
+* Fix - Fix plain text entity replacement so currency symbols are included.
+* Fix - API - Set status after order is created/updated so triggered emails are current.
+* Fix - API - Fix single webhook endpoint.
+* Tweak - Added help text for background image processing.
+* Tweak - Added notice when background image processing is running, with cancel button.
+* Tweak - Run background image processing less often by tracking changes.
+* Tweak - Added system status tool to run background image processing manually.
+* Tweak - If using Jetpack Photon, use that instead of background image processing.
+* Tweak - Gallery thumbnail image size to handle small, square cropped images.
+* Tweak - Helper function (and template version bump for image templates) to render gallery images.
+* Tweak - Add help text for the default category to explain usage.
+* Tweak - Allow changing the default product category.
+* Tweak - Tweak mobile view of order preview to improve layout in non-english.
+* Tweak - If selecting text, don't link to order on row click.
+* Localization - Remove isle of man state.
+
+= 3.3.1 - 2018-02-06 =
+* Fix - Added `woocommerce_output_product_categories` to replace `woocommerce_product_subcategories` function to prevent outdated theme template files from outputting categories on the shop and category pages in err.
+* Fix - Prevented columns from being set to anything lower than 1.
+* Fix - Added extra error checking in Webhooks API to prevent notices when deleting Webhooks.
+* Fix - Prevented list table classes being loaded multiple times. This also fixes compatibility with Smart Coupons extension.
+* Fix - Removed stray debug string from order email template and fixed some typos.
+* Fix - Set up the loop when calling wc_get_loop_prop. Fixes compatibility with some themes.
+* Fix - Remove multiple application of filter 'woocommerce_order_item_product'.
+* Fix - Protect against theme support being defined too late. Fixes some issues with custom themes defining WooCommerce support incorrectly.
+* Fix - Add fallback for themes that just get the pagination template.
+* Fix - Made the on-the-fly image regen also regenerate missing sizes.
+* Fix - Fixed missing user_id in webhook migration script.
+* Fix - Allow uncategorized category to be sorted like the others.
+* Fix - If theme support changes, we may need to flush permalinks since some are changed based on this flag.
+* Fix - Fire hooks for pagination etc only when pagination is enabled.
+* Fix - Default HTML in end wrapper template.
+* Fix - Prevent regular pagination showing on archives for unsupported themes.
+* Fix - Fix shop when shown as homepage in unsupported themes.
+* Fix - Fix SKU mapping for placeholders during CSV import.
+* Fix - Use CRUD search helper in admin products table so partial SKU search works.
+* Fix - Fix bulk sale/regular price percentage handling.
+* Fix - More specificity on smallscreen style override for columns.
+* Tweak - Add notice for moved store notice setting.
+* Tweak - Allow removing coupons on editable orders only.
+* Tweak - Extended the background processing library to avoid changing methods in the library.
+* Tweak - Do not show row settings if something is managing the number of products per page.
+* Tweak - Allow devs to add 'no-link' class to elements to prevent order view link being triggered on row click.
+* Tweak - Made woocommerce_resize_images filter more useful by calling it later.
+* Tweak - Revert default columns back to 4 so it's consistent with 3.2.
+
+= 3.3.0 - 2018-01-30 =
+* Feature - Improved default appearance in themes which do not support WooCommerce, making the shop page shortcode based.
+* Feature - Products shortcodes; improved random sorting, with some caching.
+* Feature - Products shortcodes; support for pagination.
+* Feature - Added new options to the WordPress Appearance Customizer; control the product grid (rows and columns), and image sizes.
+* Feature - Improved how image sizes are defined and calculated. Set an aspect ratio (custom, 1:1, uncropped) and image sizes will be automagically calculated based on widths.
+* Feature - Changing image sizes will trigger automatic thumbnail regeneration in the background.
+* Feature - Improved how downloads are stored within products, and added new reporting/logging features to track who downloaded what, when.
+* Feature - Improved the overall appearance of the backend orders list, and added a new 'preview' button to quickly see order details.
+* Feature - New default sample data and placeholders.
+* Feature - Added sandbox and live API details to the PayPal standard data, as well as an indication on the checkout to what mode is currently active. PayPal IPN email notifications are also now optional.
+* Feature - Introduced product category threshold filter (`woocommerce_product_category_filter_threshold`). AJAX powered select will kick in when you have over 100 categories.
+* Feature - Added `add_to_cart_description` method and aria-labels to cart buttons in the loop for accessibility.
+* Feature - Ability to search in logs when the database logger is used.
+* Performance - Adjusted how permalinks are retrieved and saved to avoid switching locales on each page load.
+* Performance - Added cache when loading product variation attributes.
+* Fix - Fix wc_notice_count logic.
+* Fix - Correct bulk edit price formatting.
+* Fix - Ajax add-to-cart button shortcode fix for variations.
+* Tweak - Update billing if account form changes.
+* Tweak - Remove videos from help sections.
+* Tweak - Preserve seconds when saving order date.
+* Tweak - Allow quantities less than 1, but not 0, in admin.
+* Tweak - Post types with no archives should not show in breadcrumb.
+* Tweak - Only load session handler class on frontend not during cron.
+* Tweak - Moved the 'Store Notice" option into the customizer.
+* Tweak - Checkout Postcode / Zip validation error message was missing Billing / Shipping Identification.
+* Tweak - Added Iris color picker validation.
+* Tweak - Use scrollIntoView on checkout.
+* Tweak - Converted input submit elements to button submit elements across the entire codebase for consistency.
+* Tweak - Added `{site_title}` replacement for email footers.
+* Tweak - Added delete product confirmation if a product has had sales.
+* Tweak - Improved when "incl. VAT" is displayed in cart totals.
+* Tweak - Use base text color for links in email templates.
+* Tweak - Show theme overrides that are done through the wc_get_template filter in the system status report.
+* Tweak - Added nofollow tags in layered nav to prevent duplicate indexed content.
+* Tweak - Hide "incl. VAT" when no rates are defined in "single total" display mode.
+* Tweak - Added replay protection for refunds.
+* Tweak - GeoDB empty file handling.
+* Tweak - Let wp_signon handle email to username conversion.
+* Tweak - Made email field wider on checkout.
+* Tweak - Post entire shipping selection when showing multiple packages.
+* Dev - REST API - Orders should be created for users who exist on the site only.
+* Dev - REST API - Fixed default value of "dp" on orders and refunds endpoints.
+* Dev - Theming - Added theme support variables to declare image sizes used for products.
+* Dev - Theming - Added support for single-product-postname.php template files.
+* Dev - Added actions before calculations order totals and taxes and is_vat_excempt support.
+* Dev - Add filter 'woocommerce_coupon_get_apply_quantity'.
+* Dev - Grouped products; added filters to allow custom columns and changes to values.
+* Dev - Allow for cloning the WC_Cart object
+* Dev - Apply filters to registration-error-email-exists error.
+* Dev - Added `woocommerce_cross_sells_order` filter.
+* Dev - Add order-details `before` hooks to complement existing hooks.
+* Dev - WC_CHUNK_SIZE constant for controlling readfile.
+* Dev - Add short circuit to customer bought product function.
+* Dev - Added a `wc_caught_exception` method to aid with logging.
+* Dev - Added Data stores and CRUD for working with Webhooks.
+* Dev - Bumped minimum WP version requirement to 4.5 and removed legacy API files.
+* Dev - New actions - `woocommerce_order_details_before_order_table_items`, `woocommerce_order_details_after_order_table_items` and `woocommerce_order_details_before_order_table`
+* Dev - Passed `widget_id` to `content-widget-product.php` so actions can be ran conditionally, and added sanitisation to `woocommerce_before_widget_product_list` and `woocommerce_after_widget_product_list`.
+* Dev - Improved the `is_internal_meta_key` checks to consider getters and setters.
+* Dev - Cleaned up the Order Customer Details template.
+* Dev - JavaScript payment_method_selected events on checkout.
+* Dev - Add new `$order->get_edit_order_url()` method.
+* Dev - Pass through options to zoom, flexslider, and photoswipe.
+* Dev - Added actions before and after scheduled sales initiation and completion.
+* Localization - Add direction character to currency output.
+* Localization - States for Tanzania and Moldova.
+
+= 3.2.6 - 2017-12-13 =
+* Fix - CSV Importer - Fix ID mapping to existing IDs.
+* Fix - CSV Importer - Unslash header fields to avoid extra slashes.
+* Fix - CSV Importer - Allow import and export of draft products.
+* Fix - CSV Importer - Get global attribute ID only when is a global attribute.
+* Fix - Remove URL fragment when appending geolocation hash.
+* Fix - Additional cart rounding fixes so rounding before subtotal works again. Added more unit tests.
+* Fix - Add BOM to exported report CSVs.
+* Fix - is_visible should ensure product is is not trashed before returning true.
+* Fix - Return packages with no rates back to the cart so the shipping calculator is displayed even when the current country is not shippable.
+* Fix - Merge session and persistent carts when both exists after login.
+* Fix - Remove "wc_error" query string after login.
+* Fix - Allow woocommerce_form_field() have 'custom_attributes' equal 0.
+* Fix - Bulk actions in status logs table.
+* Fix - Exclude add-to-cart from pagination links.
+* Fix - Updated $GLOBALS['post'] data in products shortcode to prevent theme conflicts.
+* Fix - Only remove base taxes in cart totals class if item is taxable.
+* Fix - REST API - Fixed date format in reports schema.
+* Fix - REST API - Updated product categories image schema.
+* Fix - REST API - UUse KSES for purchase_note like in admin.
+* Fix - REST API - Filter passed images before processing so they can be unset via querystring.
+* Tweak - Use protected instead of private methods to allow easy override in session handler.
+* Tweak - wc_lostpassword_url should not be used before init - added warning.
+* Localization - Update Japanese prefectures to include prefecture type.
+
+= 3.2.5 - 2017-11-22 =
+* Fix - WordPress 4.9 - REST API - Updated schema, sanitization, and validation callbacks to support correct data types.
+* Fix - WordPress 4.9 - Fix an issue saving variation attributes on new products and with attributes containing slashes.
+* Fix - Save fee tax lines to new orders on checkout.
+* Fix - Restore the post global after rendering product shortcodes.
+* Fix - Fix product filtering when searching for a string including quote characters.
+* Fix - Fix layered nav drop-downs containing unicode characters.
+* Fix - Fix an edge case rounding bug with shipping taxes, and another with non-integer quantities.
+* Fix - Set correct defaults when adding a new shipping class in admin.
+
+= 3.2.4 - 2017-11-16 =
+* Fix - Cache IDs in shortcodes rather than query objects.
+* Fix - Fix float rounding issues in cart with currencies like Bitcoin.
+* Fix - Prevent slashes appearing in shipping fields and inside meta keys when using quotes.
+* Fix - Check valid data when filtering `wp_nav_menu_objects` to prevent conflicts.
+* Fix - `get_total_ex_tax` should exclude fee taxes.
+* Fix - Fix orders count in tax reports.
+* Fix - Allow removing coupons from the cart, even if coupons are disabled.
+* Fix - Prevent calculate_totals totals running too often.
+* Fix - Set attributes during variation creation so all options are correctly displayed in cart forms.
+* Fix - Grab description directly to pass through wc_format_content to prevent double sanitization.
+* Fix - Fix db warnings when using the "Add Order Indexes" tool.
+* Fix - Remove unnecessary html formatting in variation dimensions field.
+* Fix - Fix WC_Customer_Download isset method.
+* Fix - Removed class within class in admin meta boxes HTML.
+* Fix - Fixed wrong `flex-control-nav` selector scope in `add-to-cart-variation.js`
+* Fix - Allow variations to be added to cart from query string.
+* Fix - Use `add_filter` for `comment_feed_where` hook.
+* Fix - Change nocache_headers hook firing in the cache helper.
+* Fix - Coupon min/max spend based on displayed subtotal.
+* Fix - Fix event propagation on click in setup wizard and improve validation.
+* Fix - API - Change how line items are saved in API so calculations are correct.
+* Tweak - Hide downloads from admin emails.
+* Tweak - Set placeholder for variation lxwxh field to that of the parent.
+* Tweak - Improve the Add Payment Methods display so buttons are not shown when no payment methods support the feature.
+* Localization - Update NJ tax rate.
+* Localization - Add Belarusian ruble BYN.
+
+= 3.2.3 - 2017-11-02 =
+* Fix - Fixed a conflict with some slider plugins due to sanitization of archive/term descriptions.
+* Fix - Fixed a flexslider bug when there is only 1 image on the product page (no gallery).
+* Fix - Prevent potential notices when someone extends product tabs wrongly.
+* Fix - Fixed display of shipping calculator under some conditions.
+* Fix - Fix discount calculation when customer is not within the base location and prices include tax.
+
+= 3.2.2 - 2017-10-31 =
+* Fix - Properly escape commas when exporting products to CSV.
+* Fix - Fixed email template padding in Outlook.
+* Fix - Flexslider support for RTL languages and fixes for zoom target in Chrome.
+* Fix - Correctly sync prices for grouped products.
+* Fix - Filter and remove invalid tax classes names.
+* Fix - Stop showing "major" update notification for minor or patch releases.
+* Fix - Allow scroll bar in untested plugins list on the bulk plugin updates screen.
+* Fix - Fixed meta data cloning when duplicating products.
+* Fix - Clean "Filter Products by Attribute" widget cache when updating attributes.
+* Fix - Fixed warning messages when reseting passwords with an invalid key.
+* Fix - Cart totals: Don't add shipping costs unless show_shipping is true.
+* Fix - Cart totals: Calculate shipping after discounts so discount amounts are available.
+* Fix - Cart totals: Fixed issue where VAT exempt users where still being charged VAT on the totals.
+* Fix - Cart totals: Fixed the coupons user limit and calculations.
+* Fix - Fixed "relevance" default sorting in search results.
+* Fix - Use item tax class rather than product tax class when recalculating order totals.
+* Tweak - Allow shortcodes and relative URLs for downloads in product CSV importer.
+* Tweak - Save unsaved items first while deleting order items.
+* Tweak - Only change `nocacheheaders` when on a cart/checkout page.
+* Tweak - Setup locale before generating settings placeholders in email templates.
+* Tweak - On checkout, improved the field locale logic to work without clearing default values.
+* Tweak - Change title of customer invoice email for clarity.
+* Tweak - Use custom event instead of blur to trigger validation.
+* Tweak - Various selectWoo usability improvements and better support for keyboard controls on AJAX multiselect elements.
+* Tweak - Various setup Wizard improvements.
+* Dev - Fixed orders date query when querying by meta data.
+* Dev - In the CSV exporter, added a filter to process meta values before export.
+
+= 3.2.1 - 2017-10-13 =
+* Fix - Made grouped products display in the saved order, vs the menu order.
+* Fix - Made variations with 'same as parent' tax class calculate taxes correctly.
+* Fix - Fixed tax rate reverting to 0 when the tax rate itself is not changed and the row is saved.
+* Fix - Made tax rates sort correctly when defining postcodes and cities.
+* Fix - Made guided tour help tab videos lazy-load to prevent performance issues.
+* Fix - Added SelectWoo dependency to admin meta box scripts.
+* Fix - Fixed cart subtotal 1p rounding error.
+* Fix - Fixed discount logic to also look at variation parent categories when validating coupons.
+* Fix - Product import filename based matching, and full URL based matching where the date part would still be present.
+* Fix - Fixed storage of cart discounts when prices include tax.
+* Fix - Added styling for screen-reader-text for themes which do not define it.
+* Fix - Fixed legacy cart `prices_include_tax` variable.
+* Fix - Hide cat-parent class when category will show no children due to the new depth setting.
+* Fix - Make sure image zoom is enable for calling initZoomForTarget.
+* Fix - {blogname} email placeholder.
+* Fix - API - Use edit context when updating prices.
+* Tweak - Clearly describe when a feature is powered by WooCommerce Services in the setup wizard.
+* Tweak - Restored discount total line in order screen when discounts are present.
+* Tweak - Add back option to send admin new order email, and include order number and customer email in order emails.
+* Tweak - Replace settings screenshot on wp.org listing.
+
+= 3.2.0 - 2017-10-11 =
+* Feature - Coupons can now be applied and removed in admin when editing unpaid orders.
+* Feature - Simplified the ability to resend order details to customers with a single "Resend Order Details" action.
+* Feature - Added store street address, city and postal code to settings for use by plugins.
+* Feature - Wrapping values in quotes now let's you use commas in the product CSV importer.
+* Feature - If a fatal error occurs, WooCommerce will catch and log it to be viewed in WC > Status > Logs.
+* Feature - Drag and drop sorting on the grouped product field to control display order.
+* Feature - Integrated selectWoo; more accessible Select2 (enhanced select boxes) in admin and on the front-end.
+* Feature - Enhanced select boxes in the shipping calculator.
+* Feature - Enhanced select boxes in layered nav "or" widget.
+* Feature - Ajaxified the product category filter on the products screen.
+* Feature - `[products]` shortcode can be used in place of other product shortcodes - one shortcode to rule them all.
+* Feature - Added option to control maximum depth of product category widget, and cleaned up widget naming.
+* Feature - Show sorting options when viewing search results. This defaults to sorting by relevance.
+* Feature - Support for the `WC tested up to` plugin header to show which extensions have been tested against updates.
+* Feature - Helper - Filters on the subscription management screen, update notifications, and support for shared licenses.
+* Tweak - Importer now supports menu_order property, adds filename based titles to imported images, and correctly sets post status of variations.
+* Tweak - Made the buyer phone number clickable in the in the order back-end.
+* Tweak - Clean up user is_paying_customer after deleting an order.
+* Tweak - If stock changes between page load and editing, reject stock changes to avoid incorrect stock changes.
+* Tweak - Disable search engines indexing core, dynamic, cart/checkout pages.
+* Tweak - Added shortcodes to description output in structured data, and improved variable product data.
+* Tweak - Use AJAX when restoring an item in the cart, and removing an item from the mini-cart.
+* Tweak - On-boarding: added "next" button to pointers and allowed them to be dismissed.
+* Tweak - Display post states for WC pages e.g. shop, checkout etc.
+* Tweak - Improved order tracking page display and validation.
+* Tweak - Wizard improvements, with store-owner newsletter sign-up.
+* Tweak - Improved tax calculations on negative fees by apportioning to all items.
+* Tweak - Added logic to install the plugins and themes asynchronously without using wp-cron.
+* Tweak - Modify product API returned data by context.
+* Tweak - Move js clipboards off of zeroclipboard script.
+* Tweak - Remove spam trap field from registration form.
+* Tweak - Added screen reader text to quantity input template.
+* Fix - Improved error handling in the CSV importer when invalid files are uploaded.
+* Fix - Handle full refunds in tax report by date.
+* Fix - API - Return empty result when there is no on_sale products.
+* Fix - Fixed WC_Emails::wrap_message hooks .
+* Fix - Load up gateways on ajax order status transitions so PayPal funds capture when order is completed.
+* Fix - Replace wistia videos with youtube.
+* Fix - Handle sale dates on the fly in case of missed cron schedule.
+* Fix - If sorting by date in the REST API, fallback to ID so searches are consistant.
+* Fix - Do not apply custom sorting to product feeds.
+* Fix - Make importer columns case-insensitive.
+* Dev - Make parse_date_for_wp_query public.
+* Dev - API - Creating webhooks uses the current API version rather than the latest API version.
+* Dev - Product CRUD search helpers.
+* Dev - Refactor shipping rate to include instance IDs, and pass instance IDs through filters.
+* Dev - New attribute helper functions.
+* Dev - Order note helper functions.
+* Dev - Added the "Terms and conditions" page to the api system status report.
+* Dev - Made date inputs reusable.
+* Dev - Added option for merging when using 'Order Again' via filter `woocommerce_empty_cart_when_order_again`.
+* Dev - Added system status tool for re-populating order address search indexes.
+* Dev - Added system status tool for clearing webhook logs.
+* Dev - Added woocommerce_get_asset_url filter.
+* Dev - Show notice when internal meta props are accessed directly.
+* Dev - Improve meta data updates so data is only updated when changed.
+* Dev - Improved get_filtered_term_product_counts performance.
+* Dev - Introduced wc_get_account_orders_actions function.
+* Dev - `wc_get_account_formatted_address` can get address by customer ID.
+* Dev - Added `woocommerce_get_product_id_by_sku` filter.
+* Dev - Refactored cart to use new WC_Cart_Session/WC_Cart_Totals/WC_Cart_Fees/WC_Discounts classes.
+* Dev - New `WC_Shortcode_Products` class to handle all product based shortcodes.
+* Theming - Display downloads in their own table, universally, using a new template file.
+* Theming - Streamlined email templates content: using the new downloads table, moved billing email with the billing address, order notes into the order totals table, and removed the need for 'downloadable' subjects/headings.
+* Theming - Checkout: Order pay template
+* Localization - Added cantons of Switzerland.
+* Localization - Updated XAF and XOF currency codes.
+* Localization - Added rtl support for activation.css.
+* Localization - Updated Mexican states to use correct 2 letter codes.
+* Localization - Improved many strings by excluding HTML.
+
+= 3.1.2 - 2017-08-15 =
+* Fix - Importer: Prevent multiple placeholders being created when mixing IDs and SKUs.
+* Fix - Importer: correctly set stock management props.
+* Fix - Importer: Allow "unfiltered_html" for name, description and short description fields.
+* Fix - Fix filename image handling.
+* Fix - Rest API: Allow OPTIONS requests.
+* Fix - Fixed missing reviews in product_page shortcode when querying by SKU.
+* Fix - Don't subtract negative taxes in net sales report.
+* Fix - Sort by order + zone ID as a fallback in shipping zones so the zones always match in the same order.
+* Fix - Corrected subject and heading in customer refunded email.
+* Fix - Corrected handling of custom checkbox fields in checkout get_posted_data method.
+* Fix - Fix admin help videos async property.
+* Fix - Fixed price filters by introducing precision.
+* Fix - Improved customer IP address detection.
+* Fix - Fix dark theme readability.
+* Fix - CLI tools command.
+* Fix - Adjusted shop manager role to prevent unfiltered HTML being used.
+* Fix - Various notices/warnings.
+* Dev - Correctly invalidate cache after saving order items.
+* Dev - Added `woocommerce_data_store_wp_{$this->meta_type}_read_meta` filter.
+
+= 3.1.1 - 2017-07-11 =
+* Fix - Product importer: fixed handling of non UTF8 characters in descriptions.
+* Fix - Product importer: Allow times in date fields.
+* Fix - Product exporter: fixed meta data checkbox option.
+* Fix - Helper: Styling and connect button in non-english languages.
+* Fix - Tweak terms and conditions template to check for disallowed shortcodes.
+* Fix - Fixed order helper queries when before_date and after_date args are both, corrected use of "paged", and corrected use of filters.
+* Fix - Gallery; Trigger resize after main image loads to ensure correct gallery size.
+* Fix - Prevent extra slashes being added to meta values when using the CRUD.
+* Fix - Appends "where" clauses in the comment feed to prevent a notice.
+* Fix - Fixed structured data output for variable product prices.
+* Fix - 3.x issue: Changed state validation logic to work for MX states.
+* Fix - 3.x issue: 7day reports should start from midnight, not the current time.
+* Fix - 3.x issue: Status changes made by admin should be marked as a manual in the order notes.
+* Fix - 3.x issue: Allow unsetting product shipping class in REST API.
+* Fix - 3.x issue: Corrected error handling in zones shippingMethodView.
+* Tweak - Avoid CloudFlare email obfuscation in admin.
+* Tweak - Improved detection of DOING_AUTOSAVE in admin meta box code.
+* Tweak - Improved my-account redirects and fallbacks.
+* Tweak - Add `cart_subtotal` to the shipping package so prices are recalculated when needed.
+* Dev - Add search_customers() filter in customer data store.
+* Dev - Product exporter: woocommerce_product_export_skip_meta_keys filter to control what gets exported.
+* Dev - Pass correct value to woocommerce_shipping_classes_save_class when inserting a new term
+
+= 3.1.0 - 2017-06-28 =
+* Feature - Built-in product CSV importer and exporter for products.
+* Feature - Display (toggle-able) terms inline on the checkout rather than showing a link.
+* Feature - On the "pay for order" page, if logged out show a login form rather than an error message.
+* Feature - Enabled oembed support for product short descriptions.
+* Feature - Added bulk variation update for stock status.
+* Feature - On customer profiles: added a button to copy billing address to shipping address.
+* Feature - Setup Wizard - Automatic Shipping Zone Creation In Setup Wizard for the base location.
+* Feature - Setup Wizard - Added a new optional Storefront Theme step if you're using a non-WooCommerce compatible theme.
+* Feature - Made it possible to manage extension licenses purchased from WooCommerce.com on the extensions screen.
+* Tweak - Gallery - Added a data-caption for captions to support both captions and titles for SEO.
+* Tweak - Gallery - Used smoothHeight setting to better support images of different heights.
+* Tweak - UI - Added blank states for API keys & webhooks.
+* Tweak - UI - Made Product submenu labels consistent in admin.
+* Tweak - UI - Changed street address field label and placeholder to minimize user error on checkout.
+* Tweak - UI - Added a confirmation before deleting log files.
+* Tweak - If prices are the same for all variations, use price not priceSpecification in structured data.
+* Tweak - Added variable so shipping calculator is shown on first row only when showing multiple shipping packages.
+* Tweak - Updated mini-cart HTML to use a list.
+* Tweak - Allow linking to single product additional_information tab from url hash.
+* Tweak - Re-included WooCommerce endpoints on the appearance > menus screens.
+* Tweak - Always sync incorrect titles on variation read regardless of version.
+* Tweak - Standardize rating HTML in all templates.
+* Tweak - When searching, disable WC sort order so results are sorted by relevance.
+* Tweak - Update price sorting code to use min or max for variable products depending on sorting direction.
+* Tweak - Utilize $product method to get thumbnail in loops.
+* Tweak - Check for an existing display name before updating a user on checkout. Adds display_name prop to the CRUD.
+* Tweak - Adapt variable product price used in sorting based on direction of sort.
+* Tweak - Made state validation less strict for keys.
+* Tweak - For COD orders, force payment complete status to be completed.
+* Fix - Use get_max_purchase_quantity in cart template and fix logic when stock management is off.
+* Fix - Added log_id as the secondary sorting column to log list so log entries sort correctly.
+* Fix - Fix shop page when using shop base and UTF8 shop page slug.
+* Fix - Added handles so drag and drop does not break edit on mobile when sorting categories.
+* Fix - Added ABSPATH checks to all files.
+* Fix - Fixed how to flush rewrite rules after saving the shop main page.
+* Fix - Emails sent via admin should switch to global locale.
+* Fix - Set and restore wp_query so product page functions think it's a real product page.
+* Fix - Variation default value of '0' fails to save on product.
+* Fix - Prevent locations being added to the "Rest Of The World" shipping zone via the API.
+* Dev - Allow date created to be set in wc_create_refund.
+* Dev - Introduced a [WC_Order_Query class](https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query) for finding/searching orders.
+* Dev - Added "restored" webhook.
+* Dev - Support floats for the custom attribute name sorting function.
+* Dev - Updated Emogrifier to version 1.2.
+* Dev - Sort product data tabs by priority in admin screen.
+* Dev - Added new hooks for: dashboard reviews widget, product and category sorting events, woocommerce_add_to_cart_sold_individually_found_in_cart, cart empty messages.
+* Dev - Added filters for zoom / flexslider / photoswipe enabling.
+* Dev - Added filter for cookie name.
+* Dev - Added ability to filter Photoswipe lightbox options.
+* Dev - Added new filter for product thumbnail size.
+* Dev - Added action for displaying custom data for fees in admin.
+* Dev - Changed build_payload from private to public in webhook system.
+* Dev - Added deprecated notice to WC_Order_Item_Meta (deprecated in 3.0).
+* Dev - Added namespace to jQuery events that are removed in VariationForm.
+* Dev - Made WC_Checkout::get_posted_data() public.
+* Dev - Add custom message for custom system status tools.
+* Dev - Added filters to change which order items are created and loaded to support custom item types.
+* Dev - Updated jQuery payment and serializejson libraries.
+* Localization - Added Bolivian states.
+* Localization - Use VAT for Norway instead of Tax.
+
+= 3.0.9 - 2017-06-22 =
+* Fix - Exclude sale products from category checks if coupon is not valid for sale products in coupon class.
+* Fix - Fix missing states in state field when selected country differs from checkout data. Required template modification.
+* Fix - Updated `woocommerce_email_actions` to send email when order status changes from processing to cancelled.
+* Fix - Fix undefined variables in terms and legacy order API endpoints.
+* Fix - Correctly update variation outofstock term on save.
+* Fix - Add a nonce and confirmation message for logging out via the customer my account page.
+* Fix - Allow setting grouped_products via the API.
+* Fix - Prevent edge case errors in `wc_get_product_term_ids`.
+* Fix - Remove extra escaping to fix saving of special characters in attribute terms.
+* Fix - Stricter shipping method matching in COD to prevent conflicts.
+* Fix - Recalculate totals after local pickup selection so taxes are recalculated.
+* Fix - Add missing nonce to product sales report.
+* Fix - Fix webhook save actions and ping the URL to test only once.
+* Fix - Fix issue with CLI IDs which overlap with actual data.
+* Fix - Normalise emails in coupons so lower/upper case is ignored.
+* Fix - Added background color to `x` button in product gallery edit box.
+* Dev - Renamed `woocommerce_credit_card_type_labels` filter from `wocommerce_credit_card_type_labels`.
+
+= 3.0.8 - 2017-06-06 =
+* Fix - Include multi-dimensional array support in oAuth1.0.
+* Fix - Stock/backorder notice when stock management is disabled.
+* Fix - Handle shipping item taxes if set to avoid the legacy fallback.
+* Fix - Variations should inherit purchase_note from parent.
+* Fix - Check if subtotal is blank, not empty, before setting for order items.
+* Fix - Cancelled email should be send for processing orders, not pending.
+* Fix - Missing variable in legacy API.
+* Fix - Correct price query when on a post type archive.
+* Fix - Missing $ip Variable in geolocation class.
+* Fix - A single multi-word attribute is fine for variation titles.
+* Fix - Gallery should be updated even if empty in REST API.
+* Fix - Fix saving of text attributes with special chars.
+* Fix - Undefined index warning when saving variations with stock management disabled.
+* Fix - Use meta id instead of key in WC_Order_Item::offsetGet.
+* Fix - Format parent stock qty on read.
+* Fix - Hide replies from recent reviews widgets.
+* Fix - Use formatted weight and dimensions for variations.
+* Fix - Ensure we have child before getting price to fix a notice in grouped products.
+* Fix - Fixed unicode characters when saving webhook delivery logs.
+* Fix - Avoid deprecated ID in legacy API.
+* Fix - Add correct args to woocommerce_shipping_zone_method_deleted and woocommerce_shortcode_products_query hooks.
+* Fix - Correctly append cache in product widget.
+* Fix - Add ability to invalidate cache by object ID.
+* Fix - Notice in structured data class.
+* Fix - Only delete if an object has an ID in CRUD to avoid wp_delete_post using global ID.
+* Fix - Avoid notices on checkout by ensuring all legacy data is correctly set.
+* Fix - Add failed to processing event for the processing email.
+* Fix - Store user ID and use that to determine if the session should be loaded or not. Ensures user data is correct and shipping calculator data is stored.
+
+= 3.0.7 - 2017-05-16 =
+* Fix - Display of grouped product permalinks + names.
+* Fix - Ensure `wc_get_payment_gateway_by_order` has a valid order ID to avoid errors.
+* Fix - Ensure `get_plugin_updates` exists in API.
+* Fix - Correctly set rating term after updating product visibility.
+* Fix - `is_ip_address` should be static.
+* Fix - Handle clearing for 3, 4, and 5 columns in the product gallery.
+* Fix - Some added protection against notices/errors in the assets and variation data-store files.
+* Fix - If backorders are enabled, do not make variable products out of stock.
+* Fix - Undefined function in `class-wc-embed.php`.
+* Fix - Fix 'base location' not being returned via the settings API.
+* Fix - When re-filling fields on checkout, only change the empty ones to avoid conflicts with gateway plugins and hidden fields.
+* Fix - Make calculate tax function clear taxes if taxes are disabled on recalculation.
+* Fix - Update all customer session address fields when updating via checkout.
+* Fix - Support customer searches < 3 characters long, but with result limiting.
+
+= 3.0.6 - 2017-05-09 =
+* Fix - Fixed conflict between global attributes and custom attributes with the same names.
+* Fix - Added missing "id" to API for shipping zone methods to support the CLI.
+* Fix - Incorrect use of `wc_format_price_range` in `get_price_html_from_to`.
+* Fix - Clone each meta object when cloning WC_Data object to avoid modifying original meta stdClass objects.
+* Fix - Fix non numeric warning for some order data.
+* Fix - Fixed a warning when no customer country is defined for state input.
+* Fix - Use term name when reordering so correct data is passed to the new order.
+* Fix - Formatting issues in wc_display_item_meta.
+* Fix - Check if IP address is valid in IP address detection code.
+* Fix - wc_attribute_taxonomy_id_by_name should use wc_sanitize_taxonomy_name to prevent breaking special chars.
+* Fix - Correct variable name in order structured data.
+* Fix - Prepend new item keys with `$items_key` to make them unique.
+* Fix - Hide offers from structured markup when blank.
+* Fix - Fixed "Process to checkout" button color in Twenty seventeen dark theme.
+* Fix - Only set reply-to if the email + name is set.
+* Fix - Correctly exclude terms in wc_get_related_products.
+* Fix - Reset post data prevents grouped products working in shortcodes.
+* Fix - Fix min price range comparisons.
+* Fix - Properly save order items in legacy REST API.
+* Fix - Use correct full size for variation images.
+* Fix - Add noscript style for gallery.
+* Fix - Fix/duplicate potential stock reduction with paypal.
+* Tweak - Improve _wc_term_recount performance.
+* Tweak - Improve plugin update detection in system status report to reduce timeouts.
+* Tweak - Improve "Save Order" button to reproduce WordPress post/page behavior.
+* Tweak - Added zipcode validation for France.
+* Dev - Added woocommerce_shop_order_search_results filter.
+
= 3.0.5 - 2017-04-28 =
* Fix - Tooltip display within shipping zone modals.
* Fix - Fix missing title for actions column on mobile.
@@ -1221,7 +2228,7 @@
* Fix - Use wc_get_order in simplify-commerce.
* Fix - Use 'no' instead of boolean to disable PayPal gateway.
* Fix - Do not escape redirect url in form handler - fixes malformed URLs.
-* Fix - Prevented non-existant pages from breaking cache helper.
+* Fix - Prevented non-existent pages from breaking cache helper.
* Fix - Prevent sale prices showing errors in admin wrongly.
* Fix - Prevent order statuses affecting other queries.
* Fix - Removed deprecated get_page() functions.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000000..9d5e431f0df
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at support@woocommerce.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/Gruntfile.js b/Gruntfile.js
index 3aab4d79348..df897dae4d8 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -42,8 +42,13 @@ module.exports = function( grunt ) {
// Minify .js files.
uglify: {
options: {
- // Preserve comments that start with a bang.
- preserveComments: /^!/
+ ie8: true,
+ parse: {
+ strict: false
+ },
+ output: {
+ comments : /@license|@preserve|^!/
+ }
},
admin: {
files: [{
@@ -80,7 +85,6 @@ module.exports = function( grunt ) {
'<%= dirs.js %>/photoswipe/photoswipe.min.js': ['<%= dirs.js %>/photoswipe/photoswipe.js'],
'<%= dirs.js %>/photoswipe/photoswipe-ui-default.min.js': ['<%= dirs.js %>/photoswipe/photoswipe-ui-default.js'],
'<%= dirs.js %>/round/round.min.js': ['<%= dirs.js %>/round/round.js'],
- '<%= dirs.js %>/select2/select2.min.js': ['<%= dirs.js %>/select2/select2.js'],
'<%= dirs.js %>/stupidtable/stupidtable.min.js': ['<%= dirs.js %>/stupidtable/stupidtable.js'],
'<%= dirs.js %>/zeroclipboard/jquery.zeroclipboard.min.js': ['<%= dirs.js %>/zeroclipboard/jquery.zeroclipboard.js']
}
@@ -97,16 +101,9 @@ module.exports = function( grunt ) {
ext: '.min.js'
}]
},
- simplify_commerce: {
+ flexslider: {
files: [{
- expand: true,
- cwd: 'includes/gateways/simplify-commerce/assets/js/',
- src: [
- '*.js',
- '!*.min.js'
- ],
- dest: 'includes/gateways/simplify-commerce/assets/js/',
- ext: '.min.js'
+ '<%= dirs.js %>/flexslider/jquery.flexslider.min.js': ['<%= dirs.js %>/flexslider/jquery.flexslider.js']
}]
}
},
@@ -115,8 +112,7 @@ module.exports = function( grunt ) {
sass: {
compile: {
options: {
- sourcemap: 'none',
- loadPath: require( 'node-bourbon' ).includePaths
+ sourceMap: 'none'
},
files: [{
expand: true,
@@ -128,7 +124,7 @@ module.exports = function( grunt ) {
}
},
- // Generate RTL .css files
+ // Generate RTL .css files.
rtlcss: {
woocommerce: {
expand: true,
@@ -168,7 +164,7 @@ module.exports = function( grunt ) {
watch: {
css: {
files: ['<%= dirs.css %>/*.scss'],
- tasks: ['sass', 'rtlcss', 'cssmin', 'concat']
+ tasks: ['sass', 'rtlcss', 'postcss', 'cssmin', 'concat']
},
js: {
files: [
@@ -196,6 +192,7 @@ module.exports = function( grunt ) {
potFilename: 'woocommerce.pot',
exclude: [
'apigen/.*',
+ 'vendor/.*',
'tests/.*',
'tmp/.*'
]
@@ -226,12 +223,13 @@ module.exports = function( grunt ) {
},
files: {
src: [
- '**/*.php', // Include all files
- '!apigen/**', // Exclude apigen/
- '!node_modules/**', // Exclude node_modules/
- '!tests/**', // Exclude tests/
- '!vendor/**', // Exclude vendor/
- '!tmp/**' // Exclude tmp/
+ '**/*.php', // Include all files
+ '!apigen/**', // Exclude apigen/
+ '!includes/libraries/**', // Exclude libraries/
+ '!node_modules/**', // Exclude node_modules/
+ '!tests/**', // Exclude tests/
+ '!vendor/**', // Exclude vendor/
+ '!tmp/**' // Exclude tmp/
],
expand: true
}
@@ -243,9 +241,9 @@ module.exports = function( grunt ) {
stdout: true,
stderr: true
},
- apigen: {
+ apidocs: {
command: [
- 'apigen generate -q',
+ 'vendor/bin/apigen generate -q',
'cd apigen',
'php hook-docs.php'
].join( '&&' )
@@ -255,12 +253,40 @@ module.exports = function( grunt ) {
},
e2e_tests: {
command: 'npm run --silent test'
+ },
+ e2e_tests_grep: {
+ command: 'npm run --silent test:grep "' + grunt.option( 'grep' ) + '"'
+ },
+ contributors: {
+ command: [
+ 'echo "Generating contributor list since <%= fromDate %>"',
+ './node_modules/.bin/githubcontrib --owner woocommerce --repo woocommerce --fromDate <%= fromDate %> --authToken <%= authToken %> --cols 6 --sortBy contributions --format md --sortOrder desc --showlogin true > contributors.md'
+ ].join( '&&' )
+ }
+ },
+
+ prompt: {
+ contributors: {
+ options: {
+ questions: [
+ {
+ config: 'fromDate',
+ type: 'input',
+ message: 'What date (YYYY-MM-DD) should we get contributions since?'
+ },
+ {
+ config: 'authToken',
+ type: 'input',
+ message: '(optional) Provide a personal access token. This will allow 5000 requests per hour rather than 60 - use if nothing is generated.'
+ }
+ ]
+ }
}
},
// Clean the directory.
clean: {
- apigen: {
+ apidocs: {
src: [ 'wc-apidocs' ]
}
},
@@ -268,8 +294,7 @@ module.exports = function( grunt ) {
// PHP Code Sniffer.
phpcs: {
options: {
- bin: 'vendor/bin/phpcs',
- standard: './phpcs.ruleset.xml'
+ bin: 'vendor/bin/phpcs'
},
dist: {
src: [
@@ -284,51 +309,85 @@ module.exports = function( grunt ) {
'!vendor/**' // Exclude vendor/
]
}
+ },
+
+ // Autoprefixer.
+ postcss: {
+ options: {
+ processors: [
+ require( 'autoprefixer' )({
+ browsers: [
+ '> 0.1%',
+ 'ie 8',
+ 'ie 9'
+ ]
+ })
+ ]
+ },
+ dist: {
+ src: [
+ '<%= dirs.css %>/*.css'
+ ]
+ }
}
});
- // Load NPM tasks to be used here
+ // Load NPM tasks to be used here.
+ grunt.loadNpmTasks( 'grunt-sass' );
grunt.loadNpmTasks( 'grunt-shell' );
- grunt.loadNpmTasks( 'grunt-wp-i18n' );
+ grunt.loadNpmTasks( 'grunt-phpcs' );
grunt.loadNpmTasks( 'grunt-rtlcss' );
+ grunt.loadNpmTasks( 'grunt-postcss' );
+ grunt.loadNpmTasks( 'grunt-stylelint' );
+ grunt.loadNpmTasks( 'grunt-wp-i18n' );
grunt.loadNpmTasks( 'grunt-checktextdomain' );
grunt.loadNpmTasks( 'grunt-contrib-jshint' );
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
- grunt.loadNpmTasks( 'grunt-contrib-sass' );
grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
grunt.loadNpmTasks( 'grunt-contrib-concat' );
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.loadNpmTasks( 'grunt-contrib-clean' );
- grunt.loadNpmTasks( 'grunt-stylelint' );
- grunt.loadNpmTasks( 'grunt-phpcs' );
+ grunt.loadNpmTasks( 'grunt-prompt' );
- // Register tasks
+ // Register tasks.
grunt.registerTask( 'default', [
- 'jshint',
- 'uglify',
- 'css'
+ 'js',
+ 'css',
+ 'i18n'
]);
grunt.registerTask( 'js', [
'jshint',
'uglify:admin',
- 'uglify:frontend'
+ 'uglify:frontend',
+ 'uglify:flexslider'
]);
grunt.registerTask( 'css', [
'sass',
'rtlcss',
+ 'postcss',
'cssmin',
'concat'
]);
grunt.registerTask( 'docs', [
- 'clean:apigen',
- 'shell:apigen'
+ 'clean:apidocs',
+ 'shell:apidocs'
]);
+ grunt.registerTask( 'contributors', [
+ 'prompt:contributors',
+ 'shell:contributors'
+ ]);
+
+ // Only an alias to 'default' task.
grunt.registerTask( 'dev', [
- 'default',
+ 'default'
+ ]);
+
+ grunt.registerTask( 'i18n', [
+ 'checktextdomain',
'makepot'
]);
@@ -336,6 +395,10 @@ module.exports = function( grunt ) {
'shell:e2e_tests'
]);
+ grunt.registerTask( 'e2e-tests-grep', [
+ 'shell:e2e_tests_grep'
+ ]);
+
grunt.registerTask( 'e2e-test', [
'shell:e2e_test'
]);
diff --git a/README.md b/README.md
index 57b074cb901..4b67ef66c61 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,14 @@
-# [WooCommerce](https://woocommerce.com/) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) [![Build Status](https://travis-ci.org/woocommerce/woocommerce.svg?branch=master)](https://travis-ci.org/woocommerce/woocommerce) [![Code Coverage](https://scrutinizer-ci.com/g/woocommerce/woocommerce/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/woocommerce/woocommerce/?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/woocommerce/woocommerce/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/woocommerce/woocommerce/?branch=master) [![Code Climate](https://codeclimate.com/github/woocommerce/woocommerce/badges/gpa.svg)](https://codeclimate.com/github/woocommerce/woocommerce)
+
+
+
+
+
+
+
+
+
+
+
Welcome to the WooCommerce repository on GitHub. Here you can browse the source, look at open issues and keep track of development. We recommend all developers to follow the [WooCommerce development blog](https://woocommerce.wordpress.com/) to stay up to date about everything happening in the project. You can also [follow @DevelopWC](https://twitter.com/DevelopWC) on Twitter for the latest development updates.
@@ -13,7 +23,7 @@ If you are not a developer, please use the [WooCommerce plugin page](https://wor
To disclose a security issue to our team, [please submit a report via HackerOne here](https://hackerone.com/automattic/).
## Support
-This repository is not suitable for support. Please don't use our issue tracker for support requests, but for core, WooCommerce issues only. Support can take place through the appropriate channels:
+This repository is not suitable for support. Please don't use our issue tracker for support requests, but for core WooCommerce issues only. Support can take place through the appropriate channels:
* The [WooCommerce premium support portal](https://woocommerce.com/my-account/create-a-ticket/) for customers who have purchased themes or extensions.
* [Our community forum on wp.org](https://wordpress.org/support/plugin/woocommerce) which is available for all WooCommerce users.
@@ -22,3 +32,6 @@ Support requests in issues on this repository will be closed on sight.
## Contributing to WooCommerce
If you have a patch or have stumbled upon an issue with WooCommerce core, you can contribute this back to the code. Please read our [contributor guidelines](https://github.com/woocommerce/woocommerce/blob/master/.github/CONTRIBUTING.md) for more information how you can do this.
+
+## Contributing new features to the WooCommerce REST API
+If you'd like to add a feature to the next version of the REST API, contribute here: https://github.com/woocommerce/wc-api-dev
diff --git a/apigen.neon b/apigen.neon
index d8a09352fd7..33cbe52eb1c 100644
--- a/apigen.neon
+++ b/apigen.neon
@@ -1,53 +1,20 @@
-source: ./
-
destination: wc-apidocs
-
templateConfig: apigen/theme-woocommerce/config.neon
-
-# list of scanned file extensions (e.g. php5, phpt...)
extensions: [php]
-
-# directories and files matching this file mask will not be parsed
+source:
+ - woocommerce.php
+ - includes
exclude:
- includes/libraries/
- includes/api/legacy/
- - i18n/
- - node_modules/
- - wc-apidocs/
- - tmp/
- - tests/
- - .sass-cache/
- - apigen/
-
-# character set of source files; if you use only one across your files, we recommend you name it
charset: [UTF-8]
-
-# elements with this name prefix will be considered as the "main project" (the rest will be considered as libraries)
main: WC
-
-# title of generated documentation
-title: WooCommerce 3.0.x Code Reference
-
-# base url used for sitemap (useful for public doc)
+title: WooCommerce Code Reference
baseUrl: https://docs.woocommerce.com/wc-apidocs/
-
-# choose ApiGen template theme
templateTheme: default
-
-# generate documentation for PHP internal classes
php: false
-
-# generate highlighted source code for elements
sourceCode: true
-
-# generate tree view of classes, interfaces, traits and exceptions
tree: true
-
-# generate documentation for deprecated elements
deprecated: true
-
-# generate list of tasks with @ todo annotation
todo: true
-
-# add link to ZIP archive of documentation
download: false
diff --git a/apigen/hook-docs.php b/apigen/hook-docs.php
index 7de5461a75d..74087e50198 100644
--- a/apigen/hook-docs.php
+++ b/apigen/hook-docs.php
@@ -58,34 +58,42 @@ class WC_HookFinder {
}
public static function process_hooks() {
- // If we have one, get the PHP files from it.
- $template_files = self::get_files( '*.php', GLOB_MARK, '../templates/' );
- $template_files[] = '../includes/wc-template-functions.php';
- $template_files[] = '../includes/wc-template-hooks.php';
+ self::$files_to_scan = array();
- $shortcode_files = self::get_files( '*.php', GLOB_MARK, '../includes/shortcodes/' );
- $widget_files = self::get_files( '*.php', GLOB_MARK, '../includes/widgets/' );
- $admin_files = self::get_files( '*.php', GLOB_MARK, '../includes/admin/' );
- $class_files = self::get_files( '*.php', GLOB_MARK, '../includes/' );
- $other_files = array(
- '../woocommerce.php'
+ self::$files_to_scan['Template Files'] = self::get_files( '*.php', GLOB_MARK, '../templates/' );
+ self::$files_to_scan['Template Functions'] = array( '../includes/wc-template-functions.php', '../includes/wc-template-hooks.php' );
+ self::$files_to_scan['Shortcodes'] = self::get_files( '*.php', GLOB_MARK, '../includes/shortcodes/' );
+ self::$files_to_scan['Widgets'] = self::get_files( '*.php', GLOB_MARK, '../includes/widgets/' );
+ self::$files_to_scan['Data Stores'] = self::get_files( '*.php', GLOB_MARK, '../includes/data-stores' );
+ self::$files_to_scan['Core Classes'] = array_merge(
+ self::get_files( '*.php', GLOB_MARK, '../includes/' ),
+ self::get_files( '*.php', GLOB_MARK, '../includes/abstracts/' ),
+ self::get_files( '*.php', GLOB_MARK, '../includes/customizer/' ),
+ self::get_files( '*.php', GLOB_MARK, '../includes/emails/' ),
+ self::get_files( '*.php', GLOB_MARK, '../includes/export/' ),
+ self::get_files( '*.php', GLOB_MARK, '../includes/gateways/' ),
+ self::get_files( '*.php', GLOB_MARK, '../includes/import/' ),
+ self::get_files( '*.php', GLOB_MARK, '../includes/shipping/' )
);
- self::$files_to_scan = array(
- 'Template Hooks' => $template_files,
- 'Shortcode Hooks' => $shortcode_files,
- 'Widget Hooks' => $widget_files,
- 'Class Hooks' => $class_files,
- 'Admin Hooks' => $admin_files,
- 'Other Hooks' => $other_files,
- );
+ self::$files_to_scan = array_filter( self::$files_to_scan );
$scanned = array();
ob_start();
+ $index = array();
+
+ foreach ( self::$files_to_scan as $heading => $files ) {
+ $index[] = '' . $heading . '';
+ }
+
echo '
';
echo '
Action and Filter Hook Reference
';
+ echo '
+
This is simply a list of action and filter hooks found within WooCommerce files. View the source to see supported params and usage.
");c.unblock()}})}});new b}(jQuery);
\ No newline at end of file
+!function(e){new(Backbone.View.extend({el:e("#key-fields"),events:{"click input#update_api_key":"saveKey"},initialize:function(){_.bindAll(this,"saveKey")},block:function(){e(this.el).block({message:null,overlayCSS:{background:"#fff",opacity:.6}})},unblock:function(){e(this.el).unblock()},initTipTip:function(i){e(document.body).on("click",i,function(o){o.preventDefault(),document.queryCommandSupported("copy")?(e("#copy-error").text(""),wcClearClipboard(),wcSetClipboard(e.trim(e(this).prev("input").val()),e(i))):(e(i).parent().find("input").focus().select(),e("#copy-error").text(woocommerce_admin_api_keys.clipboard_failed))}).on("aftercopy",i,function(){e("#copy-error").text(""),e(i).tipTip({attribute:"data-tip",activation:"focus",fadeIn:50,fadeOut:50,delay:0}).focus()}).on("aftercopyerror",i,function(){e(i).parent().find("input").focus().select(),e("#copy-error").text(woocommerce_admin_api_keys.clipboard_failed)})},createQRCode:function(i,o){e("#keys-qrcode").qrcode({text:i+"|"+o,width:120,height:120})},saveKey:function(i){i.preventDefault();var o=this;o.block(),Backbone.ajax({method:"POST",dataType:"json",url:woocommerce_admin_api_keys.ajax_url,data:{action:"woocommerce_update_api_key",security:woocommerce_admin_api_keys.update_api_nonce,key_id:e("#key_id",o.el).val(),description:e("#key_description",o.el).val(),user:e("#key_user",o.el).val(),permissions:e("#key_permissions",o.el).val()},success:function(i){if(e(".wc-api-message",o.el).remove(),i.success){var t=i.data;if(e("h2, h3",o.el).first().append('
",title:null,draggable:!0,theme:!1,css:{padding:0,margin:0,width:"30%",top:"40%",left:"35%",textAlign:"center",color:"#000",border:"3px solid #aaa",backgroundColor:"#fff",cursor:"wait"},themedCSS:{width:"30%",top:"40%",left:"35%"},overlayCSS:{backgroundColor:"#000",opacity:.6,cursor:"wait"},cursorReset:"default",growlCSS:{width:"350px",top:"10px",left:"",right:"10px",border:"none",padding:"5px",opacity:.6,cursor:"default",color:"#fff",backgroundColor:"#000","-webkit-border-radius":"10px","-moz-border-radius":"10px","border-radius":"10px"},iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank",forceIframe:!1,baseZ:1e3,centerX:!0,centerY:!0,allowBodyStretch:!0,bindEvents:!0,constrainTabKey:!0,fadeIn:200,fadeOut:400,timeout:0,showOverlay:!0,focusInput:!0,focusableElements:":input:enabled:visible",onBlock:null,onUnblock:null,onOverlayClick:null,quirksmodeOffsetHack:4,blockMsgClass:"blockMsg",ignoreIfBlocked:!1};var n=null,o=[]}"function"==typeof define&&define.amd&&define.amd.jQuery?define(["jquery"],a):a(jQuery)}();
\ No newline at end of file
+!function(){"use strict";function e(e){function t(t,n){var s,h,k=t==window,y=n&&n.message!==undefined?n.message:undefined;if(!(n=e.extend({},e.blockUI.defaults,n||{})).ignoreIfBlocked||!e(t).data("blockUI.isBlocked")){if(n.overlayCSS=e.extend({},e.blockUI.defaults.overlayCSS,n.overlayCSS||{}),s=e.extend({},e.blockUI.defaults.css,n.css||{}),n.onOverlayClick&&(n.overlayCSS.cursor="pointer"),h=e.extend({},e.blockUI.defaults.themedCSS,n.themedCSS||{}),y=y===undefined?n.message:y,k&&p&&o(window,{fadeOut:0}),y&&"string"!=typeof y&&(y.parentNode||y.jquery)){var m=y.jquery?y[0]:y,g={};e(t).data("blockUI.history",g),g.el=m,g.parent=m.parentNode,g.display=m.style.display,g.position=m.style.position,g.parent&&g.parent.removeChild(m)}e(t).data("blockUI.onUnblock",n.onUnblock);var v,I,w,U,x=n.baseZ;v=e(r||n.forceIframe?'':''),I=e(n.theme?'':''),n.theme&&k?(U='
"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:.5}}}};a.plot.plugins.push({init:b,options:e,name:"pie",version:"1.1"})}(jQuery);
\ No newline at end of file
+!function(e){var i=10,s=.95,t={series:{pie:{show:!1,radius:"auto",innerRadius:0,startAngle:1.5,tilt:1,shadow:{left:5,top:15,alpha:.02},offset:{top:0,left:"auto"},stroke:{color:"#fff",width:1},label:{show:"auto",formatter:function(e,i){return"
").css("width",b.width+"px").css("height",b.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",b.background),e=b.width/c.getModuleCount(),f=b.height/c.getModuleCount(),g=0;g").css("height",f+"px").appendTo(d),i=0;i").css("width",e+"px").css("background-color",c.isDark(g,i)?b.foreground:b.background).appendTo(h);return d};return this.each(function(){var e="canvas"==b.render?c():d();a(e).appendTo(this)})}}(jQuery);
\ No newline at end of file
+function QR8bitByte(t){this.mode=QRMode.MODE_8BIT_BYTE,this.data=t}function QRCode(t,e){this.typeNumber=t,this.errorCorrectLevel=e,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=new Array}function QRPolynomial(t,e){if(t.length==undefined)throw new Error(t.length+"/"+e);for(var r=0;r=7&&this.setupTypeNumber(t),null==this.dataCache&&(this.dataCache=QRCode.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,e)},setupPositionProbePattern:function(t,e){for(var r=-1;r<=7;r++)if(!(t+r<=-1||this.moduleCount<=t+r))for(var o=-1;o<=7;o++)e+o<=-1||this.moduleCount<=e+o||(this.modules[t+r][e+o]=0<=r&&r<=6&&(0==o||6==o)||0<=o&&o<=6&&(0==r||6==r)||2<=r&&r<=4&&2<=o&&o<=4)},getBestMaskPattern:function(){for(var t=0,e=0,r=0;r<8;r++){this.makeImpl(!0,r);var o=QRUtil.getLostPoint(this);(0==r||t>o)&&(t=o,e=r)}return e},createMovieClip:function(t,e,r){var o=t.createEmptyMovieClip(e,r);this.make();for(var n=0;n>r&1);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=o}for(r=0;r<18;r++){var o=!t&&1==(e>>r&1);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=o}},setupTypeInfo:function(t,e){for(var r=this.errorCorrectLevel<<3|e,o=QRUtil.getBCHTypeInfo(r),n=0;n<15;n++){i=!t&&1==(o>>n&1);n<6?this.modules[n][8]=i:n<8?this.modules[n+1][8]=i:this.modules[this.moduleCount-15+n][8]=i}for(n=0;n<15;n++){var i=!t&&1==(o>>n&1);n<8?this.modules[8][this.moduleCount-n-1]=i:n<9?this.modules[8][15-n-1+1]=i:this.modules[8][15-n-1]=i}this.modules[this.moduleCount-8][8]=!t},mapData:function(t,e){for(var r=-1,o=this.moduleCount-1,n=7,i=0,a=this.moduleCount-1;a>0;a-=2)for(6==a&&a--;;){for(var s=0;s<2;s++)if(null==this.modules[o][a-s]){var u=!1;i>>n&1)),QRUtil.getMask(e,o,a-s)&&(u=!u),this.modules[o][a-s]=u,-1==--n&&(i++,n=7)}if((o+=r)<0||this.moduleCount<=o){o-=r,r=-r;break}}}},QRCode.PAD0=236,QRCode.PAD1=17,QRCode.createData=function(t,e,r){for(var o=QRRSBlock.getRSBlocks(t,e),n=new QRBitBuffer,i=0;i8*s)throw new Error("code length overflow. ("+n.getLengthInBits()+">"+8*s+")");for(n.getLengthInBits()+4<=8*s&&n.put(0,4);n.getLengthInBits()%8!=0;)n.putBit(!1);for(;;){if(n.getLengthInBits()>=8*s)break;if(n.put(QRCode.PAD0,8),n.getLengthInBits()>=8*s)break;n.put(QRCode.PAD1,8)}return QRCode.createBytes(n,o)},QRCode.createBytes=function(t,e){for(var r=0,o=0,n=0,i=new Array(e.length),a=new Array(e.length),s=0;s=0?f.get(g):0}}for(var d=0,R=0;R=0;)e^=QRUtil.G15<=0;)e^=QRUtil.G18<>>=1;return e},getPatternPosition:function(t){return QRUtil.PATTERN_POSITION_TABLE[t-1]},getMask:function(t,e,r){switch(t){case QRMaskPattern.PATTERN000:return(e+r)%2==0;case QRMaskPattern.PATTERN001:return e%2==0;case QRMaskPattern.PATTERN010:return r%3==0;case QRMaskPattern.PATTERN011:return(e+r)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(e/2)+Math.floor(r/3))%2==0;case QRMaskPattern.PATTERN101:return e*r%2+e*r%3==0;case QRMaskPattern.PATTERN110:return(e*r%2+e*r%3)%2==0;case QRMaskPattern.PATTERN111:return(e*r%3+(e+r)%2)%2==0;default:throw new Error("bad maskPattern:"+t)}},getErrorCorrectPolynomial:function(t){for(var e=new QRPolynomial([1],0),r=0;r5&&(r+=3+n-5)}for(o=0;o=256;)t-=255;return QRMath.EXP_TABLE[t]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},i=0;i<8;i++)QRMath.EXP_TABLE[i]=1<>>7-t%8&1)},put:function(t,e){for(var r=0;r>>e-r-1&1))},getLengthInBits:function(){return this.length},putBit:function(t){var e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),t&&(this.buffer[e]|=128>>>this.length%8),this.length++}},function(t){t.fn.qrcode=function(e){"string"==typeof e&&(e={text:e}),e=t.extend({},{render:"canvas",width:256,height:256,typeNumber:-1,correctLevel:QRErrorCorrectLevel.H,background:"#ffffff",foreground:"#000000"},e);var r=function(){var t=new QRCode(e.typeNumber,e.correctLevel);t.addData(e.text),t.make();var r=document.createElement("canvas");r.width=e.width,r.height=e.height;for(var o=r.getContext("2d"),n=e.width/t.getModuleCount(),i=e.height/t.getModuleCount(),a=0;a").css("width",e.width+"px").css("height",e.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",e.background),n=e.width/r.getModuleCount(),i=e.height/r.getModuleCount(),a=0;a").css("height",i+"px").appendTo(o),u=0;u").css("width",n+"px").css("background-color",r.isDark(a,u)?e.foreground:e.background).appendTo(s);return o};return this.each(function(){var n="canvas"==e.render?r():o();t(n).appendTo(this)})}}(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery-serializejson/jquery.serializejson.js b/assets/js/jquery-serializejson/jquery.serializejson.js
index 8560cc77461..e4259ac91e6 100644
--- a/assets/js/jquery-serializejson/jquery.serializejson.js
+++ b/assets/js/jquery-serializejson/jquery.serializejson.js
@@ -1,33 +1,55 @@
/*!
SerializeJSON jQuery plugin.
https://github.com/marioizquierdo/jquery.serializeJSON
- version 2.6.1 (May, 2015)
+ version 2.8.1 (Dec, 2016)
- Copyright (c) 2012, 2015 Mario Izquierdo
+ Copyright (c) 2012, 2017 Mario Izquierdo
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*/
-(function ($) {
+(function (factory) {
+ if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof exports === 'object') { // Node/CommonJS
+ var jQuery = require('jquery');
+ module.exports = factory(jQuery);
+ } else { // Browser globals (zepto supported)
+ factory(window.jQuery || window.Zepto || window.$); // Zepto supported on browsers as well
+ }
+
+}(function ($) {
"use strict";
// jQuery('form').serializeJSON()
$.fn.serializeJSON = function (options) {
- var serializedObject, formAsArray, keys, type, value, _ref, f, opts;
+ var f, $form, opts, formAsArray, serializedObject, name, value, parsedValue, _obj, nameWithNoType, type, keys, skipFalsy;
f = $.serializeJSON;
- opts = f.setupOpts(options); // calculate values for options {parseNumbers, parseBoolens, parseNulls}
- formAsArray = this.serializeArray(); // array of objects {name, value}
- f.readCheckboxUncheckedValues(formAsArray, this, opts); // add {name, value} of unchecked checkboxes if needed
+ $form = this; // NOTE: the set of matched elements is most likely a form, but it could also be a group of inputs
+ opts = f.setupOpts(options); // calculate values for options {parseNumbers, parseBoolens, parseNulls, ...} with defaults
+ // Use native `serializeArray` function to get an array of {name, value} objects.
+ formAsArray = $form.serializeArray();
+ f.readCheckboxUncheckedValues(formAsArray, opts, $form); // add objects to the array from unchecked checkboxes if needed
+
+ // Convert the formAsArray into a serializedObject with nested keys
serializedObject = {};
- $.each(formAsArray, function (i, input) {
- keys = f.splitInputNameIntoKeysArray(input.name, opts);
- type = keys.pop(); // the last element is always the type ("string" by default)
- if (type !== 'skip') { // easy way to skip a value
- value = f.parseValue(input.value, type, opts); // string, number, boolean or null
- if (opts.parseWithFunction && type === '_') { // allow for custom parsing
- value = opts.parseWithFunction(value, input.name);
+ $.each(formAsArray, function (i, obj) {
+ name = obj.name; // original input name
+ value = obj.value; // input value
+ _obj = f.extractTypeAndNameWithNoType(name);
+ nameWithNoType = _obj.nameWithNoType; // input name with no type (i.e. "foo:string" => "foo")
+ type = _obj.type; // type defined from the input name in :type colon notation
+ if (!type) type = f.attrFromInputWithName($form, name, 'data-value-type');
+ f.validateType(name, type, opts); // make sure that the type is one of the valid types if defined
+
+ if (type !== 'skip') { // ignore inputs with type 'skip'
+ keys = f.splitInputNameIntoKeysArray(nameWithNoType);
+ parsedValue = f.parseValue(value, name, type, opts); // convert to string, number, boolean, null or customType
+
+ skipFalsy = !parsedValue && f.shouldSkipFalsy($form, name, nameWithNoType, type, opts); // ignore falsy inputs if specified
+ if (!skipFalsy) {
+ f.deepSet(serializedObject, keys, parsedValue, opts);
}
- f.deepSet(serializedObject, keys, value, opts);
}
});
return serializedObject;
@@ -46,6 +68,9 @@
parseAll: false, // all of the above
parseWithFunction: null, // to use custom parser, a function like: function(val){ return parsed_val; }
+ skipFalsyValuesForTypes: [], // skip serialization of falsy values for listed value types
+ skipFalsyValuesForFields: [], // skip serialization of falsy values for listed field names
+
customTypes: {}, // override defaultTypes
defaultTypes: {
"string": function(str) { return String(str); },
@@ -54,7 +79,8 @@
"null": function(str) { var falses = ["false", "null", "undefined", "", "0"]; return falses.indexOf(str) === -1 ? str : null; },
"array": function(str) { return JSON.parse(str); },
"object": function(str) { return JSON.parse(str); },
- "auto": function(str) { return $.serializeJSON.parseValue(str, null, {parseNumbers: true, parseBooleans: true, parseNulls: true}); } // try again with something like "parseAll"
+ "auto": function(str) { return $.serializeJSON.parseValue(str, null, null, {parseNumbers: true, parseBooleans: true, parseNulls: true}); }, // try again with something like "parseAll"
+ "skip": null // skip is a special type that makes it easy to ignore elements
},
useIntKeysAsArrayIndex: false // name="foo[2]" value="v" => {foo: [null, null, "v"]}, instead of {foo: ["2": "v"]}
@@ -69,7 +95,7 @@
defaultOptions = f.defaultOptions || {}; // defaultOptions
// Make sure that the user didn't misspell an option
- validOpts = ['checkboxUncheckedValue', 'parseNumbers', 'parseBooleans', 'parseNulls', 'parseAll', 'parseWithFunction', 'customTypes', 'defaultTypes', 'useIntKeysAsArrayIndex']; // re-define because the user may override the defaultOptions
+ validOpts = ['checkboxUncheckedValue', 'parseNumbers', 'parseBooleans', 'parseNulls', 'parseAll', 'parseWithFunction', 'skipFalsyValuesForTypes', 'skipFalsyValuesForFields', 'customTypes', 'defaultTypes', 'useIntKeysAsArrayIndex']; // re-define because the user may override the defaultOptions
for (opt in options) {
if (validOpts.indexOf(opt) === -1) {
throw new Error("serializeJSON ERROR: invalid option '" + opt + "'. Please use one of " + validOpts.join(', '));
@@ -89,6 +115,8 @@
parseNulls: parseAll || optWithDefault('parseNulls'),
parseWithFunction: optWithDefault('parseWithFunction'),
+ skipFalsyValuesForTypes: optWithDefault('skipFalsyValuesForTypes'),
+ skipFalsyValuesForFields: optWithDefault('skipFalsyValuesForFields'),
typeFunctions: $.extend({}, optWithDefault('defaultTypes'), optWithDefault('customTypes')),
useIntKeysAsArrayIndex: optWithDefault('useIntKeysAsArrayIndex')
@@ -96,21 +124,25 @@
},
// Given a string, apply the type or the relevant "parse" options, to return the parsed value
- parseValue: function(str, type, opts) {
- var typeFunction, f;
+ parseValue: function(valStr, inputName, type, opts) {
+ var f, parsedVal;
f = $.serializeJSON;
+ parsedVal = valStr; // if no parsing is needed, the returned value will be the same
- // Parse with a type if available
- typeFunction = opts.typeFunctions && opts.typeFunctions[type];
- if (typeFunction) { return typeFunction(str); } // use specific type
+ if (opts.typeFunctions && type && opts.typeFunctions[type]) { // use a type if available
+ parsedVal = opts.typeFunctions[type](valStr);
+ } else if (opts.parseNumbers && f.isNumeric(valStr)) { // auto: number
+ parsedVal = Number(valStr);
+ } else if (opts.parseBooleans && (valStr === "true" || valStr === "false")) { // auto: boolean
+ parsedVal = (valStr === "true");
+ } else if (opts.parseNulls && valStr == "null") { // auto: null
+ parsedVal = null;
+ }
+ if (opts.parseWithFunction && !type) { // custom parse function (apply after previous parsing options, but not if there's a specific type)
+ parsedVal = opts.parseWithFunction(parsedVal, inputName);
+ }
- // Otherwise, check if there is any auto-parse option enabled and use it.
- if (opts.parseNumbers && f.isNumeric(str)) { return Number(str); } // auto: number
- if (opts.parseBooleans && (str === "true" || str === "false")) { return str === "true"; } // auto: boolean
- if (opts.parseNulls && str == "null") { return null; } // auto: null
-
- // If none applies, just return the str
- return str;
+ return parsedVal;
},
isObject: function(obj) { return obj === Object(obj); }, // is it an Object?
@@ -120,50 +152,115 @@
optionKeys: function(obj) { if (Object.keys) { return Object.keys(obj); } else { var key, keys = []; for(key in obj){ keys.push(key); } return keys;} }, // polyfill Object.keys to get option keys in IE<9
- // Split the input name in programatically readable keys.
- // The last element is always the type (default "_").
- // Examples:
- // "foo" => ['foo', '_']
- // "foo:string" => ['foo', 'string']
- // "foo:boolean" => ['foo', 'boolean']
- // "[foo]" => ['foo', '_']
- // "foo[inn][bar]" => ['foo', 'inn', 'bar', '_']
- // "foo[inn[bar]]" => ['foo', 'inn', 'bar', '_']
- // "foo[inn][arr][0]" => ['foo', 'inn', 'arr', '0', '_']
- // "arr[][val]" => ['arr', '', 'val', '_']
- // "arr[][val]:null" => ['arr', '', 'val', 'null']
- splitInputNameIntoKeysArray: function(name, opts) {
- var keys, nameWithoutType, type, _ref, f;
+
+ // Fill the formAsArray object with values for the unchecked checkbox inputs,
+ // using the same format as the jquery.serializeArray function.
+ // The value of the unchecked values is determined from the opts.checkboxUncheckedValue
+ // and/or the data-unchecked-value attribute of the inputs.
+ readCheckboxUncheckedValues: function (formAsArray, opts, $form) {
+ var selector, $uncheckedCheckboxes, $el, uncheckedValue, f, name;
+ if (opts == null) { opts = {}; }
f = $.serializeJSON;
- _ref = f.extractTypeFromInputName(name, opts); nameWithoutType = _ref[0]; type = _ref[1];
- keys = nameWithoutType.split('['); // split string into array
- keys = $.map(keys, function (key) { return key.replace(/\]/g, ''); }); // remove closing brackets
- if (keys[0] === '') { keys.shift(); } // ensure no opening bracket ("[foo][inn]" should be same as "foo[inn]")
- keys.push(type); // add type at the end
- return keys;
+
+ selector = 'input[type=checkbox][name]:not(:checked):not([disabled])';
+ $uncheckedCheckboxes = $form.find(selector).add($form.filter(selector));
+ $uncheckedCheckboxes.each(function (i, el) {
+ // Check data attr first, then the option
+ $el = $(el);
+ uncheckedValue = $el.attr('data-unchecked-value');
+ if (uncheckedValue == null) {
+ uncheckedValue = opts.checkboxUncheckedValue;
+ }
+
+ // If there's an uncheckedValue, push it into the serialized formAsArray
+ if (uncheckedValue != null) {
+ if (el.name && el.name.indexOf("[][") !== -1) { // identify a non-supported
+ throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+el.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");
+ }
+ formAsArray.push({name: el.name, value: uncheckedValue});
+ }
+ });
},
- // Returns [name-without-type, type] from name.
- // "foo" => ["foo", '_']
- // "foo:boolean" => ["foo", 'boolean']
- // "foo[bar]:null" => ["foo[bar]", 'null']
- extractTypeFromInputName: function(name, opts) {
- var match, validTypes, f;
- if (match = name.match(/(.*):([^:]+)$/)){
- f = $.serializeJSON;
-
- validTypes = f.optionKeys(opts ? opts.typeFunctions : f.defaultOptions.defaultTypes);
- validTypes.push('skip'); // skip is a special type that makes it easy to remove
- if (validTypes.indexOf(match[2]) !== -1) {
- return [match[1], match[2]];
- } else {
- throw new Error("serializeJSON ERROR: Invalid type " + match[2] + " found in input name '" + name + "', please use one of " + validTypes.join(', '));
- }
+ // Returns and object with properties {name_without_type, type} from a given name.
+ // The type is null if none specified. Example:
+ // "foo" => {nameWithNoType: "foo", type: null}
+ // "foo:boolean" => {nameWithNoType: "foo", type: "boolean"}
+ // "foo[bar]:null" => {nameWithNoType: "foo[bar]", type: "null"}
+ extractTypeAndNameWithNoType: function(name) {
+ var match;
+ if (match = name.match(/(.*):([^:]+)$/)) {
+ return {nameWithNoType: match[1], type: match[2]};
} else {
- return [name, '_']; // no defined type, then use parse options
+ return {nameWithNoType: name, type: null};
}
},
+
+ // Check if this input should be skipped when it has a falsy value,
+ // depending on the options to skip values by name or type, and the data-skip-falsy attribute.
+ shouldSkipFalsy: function($form, name, nameWithNoType, type, opts) {
+ var f = $.serializeJSON;
+
+ var skipFromDataAttr = f.attrFromInputWithName($form, name, 'data-skip-falsy');
+ if (skipFromDataAttr != null) {
+ return skipFromDataAttr !== 'false'; // any value is true, except if explicitly using 'false'
+ }
+
+ var optForFields = opts.skipFalsyValuesForFields;
+ if (optForFields && (optForFields.indexOf(nameWithNoType) !== -1 || optForFields.indexOf(name) !== -1)) {
+ return true;
+ }
+
+ var optForTypes = opts.skipFalsyValuesForTypes;
+ if (type == null) type = 'string'; // assume fields with no type are targeted as string
+ if (optForTypes && optForTypes.indexOf(type) !== -1) {
+ return true
+ }
+
+ return false;
+ },
+
+ // Finds the first input in $form with this name, and get the given attr from it.
+ // Returns undefined if no input or no attribute was found.
+ attrFromInputWithName: function($form, name, attrName) {
+ var escapedName, selector, $input, attrValue;
+ escapedName = name.replace(/(:|\.|\[|\]|\s)/g,'\\$1'); // every non-standard character need to be escaped by \\
+ selector = '[name="' + escapedName + '"]';
+ $input = $form.find(selector).add($form.filter(selector)); // NOTE: this returns only the first $input element if multiple are matched with the same name (i.e. an "array[]"). So, arrays with different element types specified through the data-value-type attr is not supported.
+ return $input.attr(attrName);
+ },
+
+ // Raise an error if the type is not recognized.
+ validateType: function(name, type, opts) {
+ var validTypes, f;
+ f = $.serializeJSON;
+ validTypes = f.optionKeys(opts ? opts.typeFunctions : f.defaultOptions.defaultTypes);
+ if (!type || validTypes.indexOf(type) !== -1) {
+ return true;
+ } else {
+ throw new Error("serializeJSON ERROR: Invalid type " + type + " found in input name '" + name + "', please use one of " + validTypes.join(', '));
+ }
+ },
+
+
+ // Split the input name in programatically readable keys.
+ // Examples:
+ // "foo" => ['foo']
+ // "[foo]" => ['foo']
+ // "foo[inn][bar]" => ['foo', 'inn', 'bar']
+ // "foo[inn[bar]]" => ['foo', 'inn', 'bar']
+ // "foo[inn][arr][0]" => ['foo', 'inn', 'arr', '0']
+ // "arr[][val]" => ['arr', '', 'val']
+ splitInputNameIntoKeysArray: function(nameWithNoType) {
+ var keys, f;
+ f = $.serializeJSON;
+ keys = nameWithNoType.split('['); // split string into array
+ keys = $.map(keys, function (key) { return key.replace(/\]/g, ''); }); // remove closing brackets
+ if (keys[0] === '') { keys.shift(); } // ensure no opening bracket ("[foo][inn]" should be same as "foo[inn]")
+ return keys;
+ },
+
// Set a value in an object or array, using multiple keys to set in a nested object or array:
//
// deepSet(obj, ['foo'], v) // obj['foo'] = v
@@ -236,32 +333,8 @@
tail = keys.slice(1);
f.deepSet(o[key], tail, value, opts);
}
- },
-
- // Fill the formAsArray object with values for the unchecked checkbox inputs,
- // using the same format as the jquery.serializeArray function.
- // The value of the unchecked values is determined from the opts.checkboxUncheckedValue
- // and/or the data-unchecked-value attribute of the inputs.
- readCheckboxUncheckedValues: function (formAsArray, $form, opts) {
- var selector, $uncheckedCheckboxes, $el, dataUncheckedValue, f;
- if (opts == null) { opts = {}; }
- f = $.serializeJSON;
-
- selector = 'input[type=checkbox][name]:not(:checked):not([disabled])';
- $uncheckedCheckboxes = $form.find(selector).add($form.filter(selector));
- $uncheckedCheckboxes.each(function (i, el) {
- $el = $(el);
- dataUncheckedValue = $el.attr('data-unchecked-value');
- if(dataUncheckedValue) { // data-unchecked-value has precedence over option opts.checkboxUncheckedValue
- formAsArray.push({name: el.name, value: dataUncheckedValue});
- } else {
- if (!f.isUndefined(opts.checkboxUncheckedValue)) {
- formAsArray.push({name: el.name, value: opts.checkboxUncheckedValue});
- }
- }
- });
}
};
-}(window.jQuery || window.Zepto || window.$));
+}));
diff --git a/assets/js/jquery-serializejson/jquery.serializejson.min.js b/assets/js/jquery-serializejson/jquery.serializejson.min.js
index 8248d4951f4..731cffe739c 100644
--- a/assets/js/jquery-serializejson/jquery.serializejson.min.js
+++ b/assets/js/jquery-serializejson/jquery.serializejson.min.js
@@ -1,10 +1,10 @@
/*!
SerializeJSON jQuery plugin.
https://github.com/marioizquierdo/jquery.serializeJSON
- version 2.6.1 (May, 2015)
+ version 2.8.1 (Dec, 2016)
- Copyright (c) 2012, 2015 Mario Izquierdo
+ Copyright (c) 2012, 2017 Mario Izquierdo
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*/
-!function(a){"use strict";a.fn.serializeJSON=function(b){var c,d,e,f,g,h,i;return h=a.serializeJSON,i=h.setupOpts(b),d=this.serializeArray(),h.readCheckboxUncheckedValues(d,this,i),c={},a.each(d,function(a,b){e=h.splitInputNameIntoKeysArray(b.name,i),f=e.pop(),"skip"!==f&&(g=h.parseValue(b.value,f,i),i.parseWithFunction&&"_"===f&&(g=i.parseWithFunction(g,b.name)),h.deepSet(c,e,g,i))}),c},a.serializeJSON={defaultOptions:{checkboxUncheckedValue:void 0,parseNumbers:!1,parseBooleans:!1,parseNulls:!1,parseAll:!1,parseWithFunction:null,customTypes:{},defaultTypes:{string:function(a){return String(a)},number:function(a){return Number(a)},boolean:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1},null:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1?a:null},array:function(a){return JSON.parse(a)},object:function(a){return JSON.parse(a)},auto:function(b){return a.serializeJSON.parseValue(b,null,{parseNumbers:!0,parseBooleans:!0,parseNulls:!0})}},useIntKeysAsArrayIndex:!1},setupOpts:function(b){var c,d,e,f,g,h;h=a.serializeJSON,null==b&&(b={}),e=h.defaultOptions||{},d=["checkboxUncheckedValue","parseNumbers","parseBooleans","parseNulls","parseAll","parseWithFunction","customTypes","defaultTypes","useIntKeysAsArrayIndex"];for(c in b)if(d.indexOf(c)===-1)throw new Error("serializeJSON ERROR: invalid option '"+c+"'. Please use one of "+d.join(", "));return f=function(a){return b[a]!==!1&&""!==b[a]&&(b[a]||e[a])},g=f("parseAll"),{checkboxUncheckedValue:f("checkboxUncheckedValue"),parseNumbers:g||f("parseNumbers"),parseBooleans:g||f("parseBooleans"),parseNulls:g||f("parseNulls"),parseWithFunction:f("parseWithFunction"),typeFunctions:a.extend({},f("defaultTypes"),f("customTypes")),useIntKeysAsArrayIndex:f("useIntKeysAsArrayIndex")}},parseValue:function(b,c,d){var e,f;return f=a.serializeJSON,e=d.typeFunctions&&d.typeFunctions[c],e?e(b):d.parseNumbers&&f.isNumeric(b)?Number(b):!d.parseBooleans||"true"!==b&&"false"!==b?d.parseNulls&&"null"==b?null:b:"true"===b},isObject:function(a){return a===Object(a)},isUndefined:function(a){return void 0===a},isValidArrayIndex:function(a){return/^[0-9]+$/.test(String(a))},isNumeric:function(a){return a-parseFloat(a)>=0},optionKeys:function(a){if(Object.keys)return Object.keys(a);var b,c=[];for(b in a)c.push(b);return c},splitInputNameIntoKeysArray:function(b,c){var d,e,f,g,h;return h=a.serializeJSON,g=h.extractTypeFromInputName(b,c),e=g[0],f=g[1],d=e.split("["),d=a.map(d,function(a){return a.replace(/\]/g,"")}),""===d[0]&&d.shift(),d.push(f),d},extractTypeFromInputName:function(b,c){var d,e,f;if(d=b.match(/(.*):([^:]+)$/)){if(f=a.serializeJSON,e=f.optionKeys(c?c.typeFunctions:f.defaultOptions.defaultTypes),e.push("skip"),e.indexOf(d[2])!==-1)return[d[1],d[2]];throw new Error("serializeJSON ERROR: Invalid type "+d[2]+" found in input name '"+b+"', please use one of "+e.join(", "))}return[b,"_"]},deepSet:function(b,c,d,e){var f,g,h,i,j,k;if(null==e&&(e={}),k=a.serializeJSON,k.isUndefined(b))throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined");if(!c||0===c.length)throw new Error("ArgumentError: param 'keys' expected to be an array with least one element");f=c[0],1===c.length?""===f?b.push(d):b[f]=d:(g=c[1],""===f&&(i=b.length-1,j=b[i],f=k.isObject(j)&&(k.isUndefined(j[g])||c.length>2)?i:i+1),""===g?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):e.useIntKeysAsArrayIndex&&k.isValidArrayIndex(g)?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):!k.isUndefined(b[f])&&k.isObject(b[f])||(b[f]={}),h=c.slice(1),k.deepSet(b[f],h,d,e))},readCheckboxUncheckedValues:function(b,c,d){var e,f,g,h,i;null==d&&(d={}),i=a.serializeJSON,e="input[type=checkbox][name]:not(:checked):not([disabled])",f=c.find(e).add(c.filter(e)),f.each(function(c,e){g=a(e),h=g.attr("data-unchecked-value"),h?b.push({name:e.name,value:h}):i.isUndefined(d.checkboxUncheckedValue)||b.push({name:e.name,value:d.checkboxUncheckedValue})})}}}(window.jQuery||window.Zepto||window.$);
\ No newline at end of file
+!function(e){if("function"==typeof define&&define.amd)define(["jquery"],e);else if("object"==typeof exports){var n=require("jquery");module.exports=e(n)}else e(window.jQuery||window.Zepto||window.$)}(function(e){"use strict";e.fn.serializeJSON=function(n){var r,s,t,a,i,u,l,o,p,c,d,f,y;return r=e.serializeJSON,s=this,t=r.setupOpts(n),a=s.serializeArray(),r.readCheckboxUncheckedValues(a,t,s),i={},e.each(a,function(e,n){u=n.name,l=n.value,p=r.extractTypeAndNameWithNoType(u),c=p.nameWithNoType,(d=p.type)||(d=r.attrFromInputWithName(s,u,"data-value-type")),r.validateType(u,d,t),"skip"!==d&&(f=r.splitInputNameIntoKeysArray(c),o=r.parseValue(l,u,d,t),(y=!o&&r.shouldSkipFalsy(s,u,c,d,t))||r.deepSet(i,f,o,t))}),i},e.serializeJSON={defaultOptions:{checkboxUncheckedValue:undefined,parseNumbers:!1,parseBooleans:!1,parseNulls:!1,parseAll:!1,parseWithFunction:null,skipFalsyValuesForTypes:[],skipFalsyValuesForFields:[],customTypes:{},defaultTypes:{string:function(e){return String(e)},number:function(e){return Number(e)},"boolean":function(e){return-1===["false","null","undefined","","0"].indexOf(e)},"null":function(e){return-1===["false","null","undefined","","0"].indexOf(e)?e:null},array:function(e){return JSON.parse(e)},object:function(e){return JSON.parse(e)},auto:function(n){return e.serializeJSON.parseValue(n,null,null,{parseNumbers:!0,parseBooleans:!0,parseNulls:!0})},skip:null},useIntKeysAsArrayIndex:!1},setupOpts:function(n){var r,s,t,a,i,u;u=e.serializeJSON,null==n&&(n={}),t=u.defaultOptions||{},s=["checkboxUncheckedValue","parseNumbers","parseBooleans","parseNulls","parseAll","parseWithFunction","skipFalsyValuesForTypes","skipFalsyValuesForFields","customTypes","defaultTypes","useIntKeysAsArrayIndex"];for(r in n)if(-1===s.indexOf(r))throw new Error("serializeJSON ERROR: invalid option '"+r+"'. Please use one of "+s.join(", "));return a=function(e){return!1!==n[e]&&""!==n[e]&&(n[e]||t[e])},i=a("parseAll"),{checkboxUncheckedValue:a("checkboxUncheckedValue"),parseNumbers:i||a("parseNumbers"),parseBooleans:i||a("parseBooleans"),parseNulls:i||a("parseNulls"),parseWithFunction:a("parseWithFunction"),skipFalsyValuesForTypes:a("skipFalsyValuesForTypes"),skipFalsyValuesForFields:a("skipFalsyValuesForFields"),typeFunctions:e.extend({},a("defaultTypes"),a("customTypes")),useIntKeysAsArrayIndex:a("useIntKeysAsArrayIndex")}},parseValue:function(n,r,s,t){var a,i;return a=e.serializeJSON,i=n,t.typeFunctions&&s&&t.typeFunctions[s]?i=t.typeFunctions[s](n):t.parseNumbers&&a.isNumeric(n)?i=Number(n):!t.parseBooleans||"true"!==n&&"false"!==n?t.parseNulls&&"null"==n&&(i=null):i="true"===n,t.parseWithFunction&&!s&&(i=t.parseWithFunction(i,r)),i},isObject:function(e){return e===Object(e)},isUndefined:function(e){return void 0===e},isValidArrayIndex:function(e){return/^[0-9]+$/.test(String(e))},isNumeric:function(e){return e-parseFloat(e)>=0},optionKeys:function(e){if(Object.keys)return Object.keys(e);var n,r=[];for(n in e)r.push(n);return r},readCheckboxUncheckedValues:function(n,r,s){var t,a,i;null==r&&(r={}),e.serializeJSON,t="input[type=checkbox][name]:not(:checked):not([disabled])",s.find(t).add(s.filter(t)).each(function(s,t){if(a=e(t),null==(i=a.attr("data-unchecked-value"))&&(i=r.checkboxUncheckedValue),null!=i){if(t.name&&-1!==t.name.indexOf("[]["))throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+t.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");n.push({name:t.name,value:i})}})},extractTypeAndNameWithNoType:function(e){var n;return(n=e.match(/(.*):([^:]+)$/))?{nameWithNoType:n[1],type:n[2]}:{nameWithNoType:e,type:null}},shouldSkipFalsy:function(n,r,s,t,a){var i=e.serializeJSON.attrFromInputWithName(n,r,"data-skip-falsy");if(null!=i)return"false"!==i;var u=a.skipFalsyValuesForFields;if(u&&(-1!==u.indexOf(s)||-1!==u.indexOf(r)))return!0;var l=a.skipFalsyValuesForTypes;return null==t&&(t="string"),!(!l||-1===l.indexOf(t))},attrFromInputWithName:function(e,n,r){var s,t;return s=n.replace(/(:|\.|\[|\]|\s)/g,"\\$1"),t='[name="'+s+'"]',e.find(t).add(e.filter(t)).attr(r)},validateType:function(n,r,s){var t,a;if(a=e.serializeJSON,t=a.optionKeys(s?s.typeFunctions:a.defaultOptions.defaultTypes),r&&-1===t.indexOf(r))throw new Error("serializeJSON ERROR: Invalid type "+r+" found in input name '"+n+"', please use one of "+t.join(", "));return!0},splitInputNameIntoKeysArray:function(n){var r;return e.serializeJSON,r=n.split("["),""===(r=e.map(r,function(e){return e.replace(/\]/g,"")}))[0]&&r.shift(),r},deepSet:function(n,r,s,t){var a,i,u,l,o,p;if(null==t&&(t={}),(p=e.serializeJSON).isUndefined(n))throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined");if(!r||0===r.length)throw new Error("ArgumentError: param 'keys' expected to be an array with least one element");a=r[0],1===r.length?""===a?n.push(s):n[a]=s:(i=r[1],""===a&&(o=n[l=n.length-1],a=p.isObject(o)&&(p.isUndefined(o[i])||r.length>2)?l:l+1),""===i?!p.isUndefined(n[a])&&e.isArray(n[a])||(n[a]=[]):t.useIntKeysAsArrayIndex&&p.isValidArrayIndex(i)?!p.isUndefined(n[a])&&e.isArray(n[a])||(n[a]=[]):!p.isUndefined(n[a])&&p.isObject(n[a])||(n[a]={}),u=r.slice(1),p.deepSet(n[a],u,s,t))}}});
\ No newline at end of file
diff --git a/assets/js/jquery-tiptip/jquery.tipTip.min.js b/assets/js/jquery-tiptip/jquery.tipTip.min.js
index 8fd09bf9600..2afafe2a606 100644
--- a/assets/js/jquery-tiptip/jquery.tipTip.min.js
+++ b/assets/js/jquery-tiptip/jquery.tipTip.min.js
@@ -1 +1 @@
-!function(a){a.fn.tipTip=function(b){var c={activation:"hover",keepAlive:!1,maxWidth:"200px",edgeOffset:3,defaultPosition:"bottom",delay:400,fadeIn:200,fadeOut:200,attribute:"title",content:!1,enter:function(){},exit:function(){}},d=a.extend(c,b);if(a("#tiptip_holder").length<=0){var e=a(''),f=a(''),g=a('');a("body").append(e.html(f).prepend(g.html('')))}else var e=a("#tiptip_holder"),f=a("#tiptip_content"),g=a("#tiptip_arrow");return this.each(function(){function b(){d.enter.call(this),f.html(i),e.hide().removeAttr("class").css("margin","0"),g.removeAttr("style");var b=parseInt(h.offset().top),c=parseInt(h.offset().left),k=parseInt(h.outerWidth()),l=parseInt(h.outerHeight()),m=e.outerWidth(),n=e.outerHeight(),o=Math.round((k-m)/2),p=Math.round((l-n)/2),q=Math.round(c+o),r=Math.round(b+l+d.edgeOffset),s="",t="",u=Math.round(m-12)/2;"bottom"==d.defaultPosition?s="_bottom":"top"==d.defaultPosition?s="_top":"left"==d.defaultPosition?s="_left":"right"==d.defaultPosition&&(s="_right");var v=o+cparseInt(a(window).width());v&&o<0||"_right"==s&&!w||"_left"==s&&cparseInt(a(window).height()+a(window).scrollTop()),y=b+l-(d.edgeOffset+n+8)<0;x||"_bottom"==s&&x||"_top"==s&&!y?("_top"==s||"_bottom"==s?s="_top":s+="_top",t=n,r=Math.round(b-(n+5+d.edgeOffset))):(y|("_top"==s&&y)||"_bottom"==s&&!x)&&("_top"==s||"_bottom"==s?s="_bottom":s+="_bottom",t=-12,r=Math.round(b+l+d.edgeOffset)),"_right_top"==s||"_left_top"==s?r+=5:"_right_bottom"!=s&&"_left_bottom"!=s||(r-=5),"_left_top"!=s&&"_left_bottom"!=s||(q+=5),g.css({"margin-left":u+"px","margin-top":t+"px"}),e.css({"margin-left":q+"px","margin-top":r+"px"}).attr("class","tip"+s),j&&clearTimeout(j),j=setTimeout(function(){e.stop(!0,!0).fadeIn(d.fadeIn)},d.delay)}function c(){d.exit.call(this),j&&clearTimeout(j),e.fadeOut(d.fadeOut)}var h=a(this);if(d.content)var i=d.content;else var i=h.attr(d.attribute);if(""!=i){d.content||h.removeAttr(d.attribute);var j=!1;"hover"==d.activation?(h.hover(function(){b()},function(){d.keepAlive||c()}),d.keepAlive&&e.hover(function(){},function(){c()})):"focus"==d.activation?h.focus(function(){b()}).blur(function(){c()}):"click"==d.activation&&(h.click(function(){return b(),!1}).hover(function(){},function(){d.keepAlive||c()}),d.keepAlive&&e.hover(function(){},function(){c()}))}})}}(jQuery);
\ No newline at end of file
+!function(t){t.fn.tipTip=function(e){var o={activation:"hover",keepAlive:!1,maxWidth:"200px",edgeOffset:3,defaultPosition:"bottom",delay:400,fadeIn:200,fadeOut:200,attribute:"title",content:!1,enter:function(){},exit:function(){}},i=t.extend(o,e);if(t("#tiptip_holder").length<=0){var n=t(''),r=t(''),a=t('');t("body").append(n.html(r).prepend(a.html('')))}else var n=t("#tiptip_holder"),r=t("#tiptip_content"),a=t("#tiptip_arrow");return this.each(function(){function e(){i.enter.call(this),r.html(d),n.hide().removeAttr("class").css("margin","0"),a.removeAttr("style");var e=parseInt(f.offset().top),o=parseInt(f.offset().left),p=parseInt(f.outerWidth()),l=parseInt(f.outerHeight()),h=n.outerWidth(),c=n.outerHeight(),s=Math.round((p-h)/2),_=Math.round((l-c)/2),v=Math.round(o+s),m=Math.round(e+l+i.edgeOffset),g="",b="",M=Math.round(h-12)/2;"bottom"==i.defaultPosition?g="_bottom":"top"==i.defaultPosition?g="_top":"left"==i.defaultPosition?g="_left":"right"==i.defaultPosition&&(g="_right");var w=s+oparseInt(t(window).width());w&&s<0||"_right"==g&&!O||"_left"==g&&oparseInt(t(window).height()+t(window).scrollTop()),I=e+l-(i.edgeOffset+c+8)<0;x||"_bottom"==g&&x||"_top"==g&&!I?("_top"==g||"_bottom"==g?g="_top":g+="_top",b=c,m=Math.round(e-(c+5+i.edgeOffset))):(I|("_top"==g&&I)||"_bottom"==g&&!x)&&("_top"==g||"_bottom"==g?g="_bottom":g+="_bottom",b=-12,m=Math.round(e+l+i.edgeOffset)),"_right_top"==g||"_left_top"==g?m+=5:"_right_bottom"!=g&&"_left_bottom"!=g||(m-=5),"_left_top"!=g&&"_left_bottom"!=g||(v+=5),a.css({"margin-left":M+"px","margin-top":b+"px"}),n.css({"margin-left":v+"px","margin-top":m+"px"}).attr("class","tip"+g),u&&clearTimeout(u),u=setTimeout(function(){n.stop(!0,!0).fadeIn(i.fadeIn)},i.delay)}function o(){i.exit.call(this),u&&clearTimeout(u),n.fadeOut(i.fadeOut)}var f=t(this);if(i.content)d=i.content;else var d=f.attr(i.attribute);if(""!=d){i.content||f.removeAttr(i.attribute);var u=!1;"hover"==i.activation?(f.hover(function(){e()},function(){i.keepAlive||o()}),i.keepAlive&&n.hover(function(){},function(){o()})):"focus"==i.activation?f.focus(function(){e()}).blur(function(){o()}):"click"==i.activation&&(f.click(function(){return e(),!1}).hover(function(){},function(){i.keepAlive||o()}),i.keepAlive&&n.hover(function(){},function(){o()}))}})}}(jQuery);
\ No newline at end of file
diff --git a/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch.min.js b/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch.min.js
index 6bdc16e32d7..d4d30a2c37d 100644
--- a/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch.min.js
+++ b/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch.min.js
@@ -8,4 +8,4 @@
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
-!function(a){function b(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var c,d=a.ui.mouse.prototype,e=d._mouseInit,f=d._mouseDestroy;d._touchStart=function(a){var d=this;!c&&d._mouseCapture(a.originalEvent.changedTouches[0])&&(c=!0,d._touchMoved=!1,b(a,"mouseover"),b(a,"mousemove"),b(a,"mousedown"))},d._touchMove=function(a){c&&(this._touchMoved=!0,b(a,"mousemove"))},d._touchEnd=function(a){c&&(b(a,"mouseup"),b(a,"mouseout"),this._touchMoved||b(a,"click"),c=!1)},d._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),e.call(b)},d._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),f.call(b)}}}(jQuery);
\ No newline at end of file
+!function(o){function t(o,t){if(!(o.originalEvent.touches.length>1)){o.preventDefault();var e=o.originalEvent.changedTouches[0],u=document.createEvent("MouseEvents");u.initMouseEvent(t,!0,!0,window,1,e.screenX,e.screenY,e.clientX,e.clientY,!1,!1,!1,!1,0,null),o.target.dispatchEvent(u)}}if(o.support.touch="ontouchend"in document,o.support.touch){var e,u=o.ui.mouse.prototype,n=u._mouseInit,c=u._mouseDestroy;u._touchStart=function(o){var u=this;!e&&u._mouseCapture(o.originalEvent.changedTouches[0])&&(e=!0,u._touchMoved=!1,t(o,"mouseover"),t(o,"mousemove"),t(o,"mousedown"))},u._touchMove=function(o){e&&(this._touchMoved=!0,t(o,"mousemove"))},u._touchEnd=function(o){e&&(t(o,"mouseup"),t(o,"mouseout"),this._touchMoved||t(o,"click"),e=!1)},u._mouseInit=function(){var t=this;t.element.bind({touchstart:o.proxy(t,"_touchStart"),touchmove:o.proxy(t,"_touchMove"),touchend:o.proxy(t,"_touchEnd")}),n.call(t)},u._mouseDestroy=function(){var t=this;t.element.unbind({touchstart:o.proxy(t,"_touchStart"),touchmove:o.proxy(t,"_touchMove"),touchend:o.proxy(t,"_touchEnd")}),c.call(t)}}}(jQuery);
\ No newline at end of file
diff --git a/assets/js/js-cookie/js.cookie.js b/assets/js/js-cookie/js.cookie.js
old mode 100755
new mode 100644
diff --git a/assets/js/js-cookie/js.cookie.min.js b/assets/js/js-cookie/js.cookie.min.js
index 11145b4c255..ab19f878e02 100644
--- a/assets/js/js-cookie/js.cookie.min.js
+++ b/assets/js/js-cookie/js.cookie.min.js
@@ -5,4 +5,4 @@
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
* Released under the MIT license
*/
-!function(a){var b=!1;if("function"==typeof define&&define.amd&&(define(a),b=!0),"object"==typeof exports&&(module.exports=a(),b=!0),!b){var c=window.Cookies,d=window.Cookies=a();d.noConflict=function(){return window.Cookies=c,d}}}(function(){function a(){for(var a=0,b={};a1){if(f=a({path:"/"},d.defaults,f),"number"==typeof f.expires){var h=new Date;h.setMilliseconds(h.getMilliseconds()+864e5*f.expires),f.expires=h}f.expires=f.expires?f.expires.toUTCString():"";try{g=JSON.stringify(e),/^[\{\[]/.test(g)&&(e=g)}catch(a){}e=c.write?c.write(e,b):encodeURIComponent(String(e)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),b=encodeURIComponent(String(b)),b=b.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),b=b.replace(/[\(\)]/g,escape);var i="";for(var j in f)f[j]&&(i+="; "+j,f[j]!==!0&&(i+="="+f[j]));return document.cookie=b+"="+e+i}b||(g={});for(var k=document.cookie?document.cookie.split("; "):[],l=/(%[0-9A-Z]{2})+/g,m=0;m1){if("number"==typeof(i=e({path:"/"},t.defaults,i)).expires){var a=new Date;a.setMilliseconds(a.getMilliseconds()+864e5*i.expires),i.expires=a}i.expires=i.expires?i.expires.toUTCString():"";try{c=JSON.stringify(r),/^[\{\[]/.test(c)&&(r=c)}catch(m){}r=o.write?o.write(r,n):encodeURIComponent(String(r)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),n=(n=(n=encodeURIComponent(String(n))).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent)).replace(/[\(\)]/g,escape);var f="";for(var s in i)i[s]&&(f+="; "+s,!0!==i[s]&&(f+="="+i[s]));return document.cookie=n+"="+r+f}n||(c={});for(var p=document.cookie?document.cookie.split("; "):[],d=/(%[0-9A-Z]{2})+/g,u=0;u-1&&(c.onTap(),d=!0);if(d){a.stopPropagation&&a.stopPropagation(),r=!0;var h=b.features.isOldAndroid?600:30;s=setTimeout(function(){r=!1},h)}},B=function(){return!a.likelyTouchDevice||q.mouseUsed||screen.width>q.fitControlsWidth},C=function(a,c,d){b[(d?"add":"remove")+"Class"](a,"pswp__"+c)},D=function(){var a=1===q.getNumItemsFn();a!==p&&(C(d,"ui--one-slide",a),p=a)},E=function(){C(i,"share-modal--hidden",y)},F=function(){return y=!y,y?(b.removeClass(i,"pswp__share-modal--fade-in"),setTimeout(function(){y&&E()},300)):(E(),setTimeout(function(){y||b.addClass(i,"pswp__share-modal--fade-in")},30)),y||H(),!1},G=function(b){b=b||window.event;var c=b.target||b.srcElement;return a.shout("shareLinkClick",b,c),!!c.href&&(!!c.hasAttribute("download")||(window.open(c.href,"pswp_share","scrollbars=yes,resizable=yes,toolbar=no,location=yes,width=550,height=420,top=100,left="+(window.screen?Math.round(screen.width/2-275):100)),y||F(),!1))},H=function(){for(var a,b,c,d,e,f="",g=0;g"+a.label+"",q.parseShareButtonOut&&(f=q.parseShareButtonOut(a,f));i.children[0].innerHTML=f,i.children[0].onclick=G},I=function(a){for(var c=0;c=.95&&v.showControls()});var a;l("onPinchClose",function(b){x&&b<.9?(v.hideControls(),a=!0):a&&!x&&b>.9&&v.showControls()}),l("zoomGestureEnded",function(){a=!1,a&&!x&&v.showControls()})},S=[{name:"caption",option:"captionEl",onInit:function(a){e=a}},{name:"share-modal",option:"shareEl",onInit:function(a){i=a},onTap:function(){F()}},{name:"button--share",option:"shareEl",onInit:function(a){h=a},onTap:function(){F()}},{name:"button--zoom",option:"zoomEl",onTap:a.toggleDesktopZoom},{name:"counter",option:"counterEl",onInit:function(a){g=a}},{name:"button--close",option:"closeEl",onTap:a.close},{name:"button--arrow--left",option:"arrowEl",onTap:a.prev},{name:"button--arrow--right",option:"arrowEl",onTap:a.next},{name:"button--fs",option:"fullscreenEl",onTap:function(){c.isFullscreen()?c.exit():c.enter()}},{name:"preloader",option:"preloaderEl",onInit:function(a){m=a}}],T=function(){var a,c,e,f=function(d){if(d)for(var f=d.length,g=0;g-1&&(q[e.option]?(b.removeClass(a,"pswp__element--disabled"),e.onInit&&e.onInit(a)):b.addClass(a,"pswp__element--disabled"))}};f(d.children);var g=b.getChildByClass(d,"pswp__top-bar");g&&f(g.children)};v.init=function(){b.extend(a.options,z,!0),q=a.options,d=b.getChildByClass(a.scrollWrap,"pswp__ui"),l=a.listen,R(),l("beforeChange",v.update),l("doubleTap",function(b){var c=a.currItem.initialZoomLevel;a.getZoomLevel()!==c?a.zoomTo(c,b,333):a.zoomTo(q.getDoubleTapZoom(!1,a.currItem),b,333)}),l("preventDragEvent",function(a,b,c){var d=a.target||a.srcElement;d&&d.getAttribute("class")&&a.type.indexOf("mouse")>-1&&(d.getAttribute("class").indexOf("__caption")>0||/(SMALL|STRONG|EM)/i.test(d.tagName))&&(c.prevent=!1)}),l("bindEvents",function(){b.bind(d,"pswpTap click",A),b.bind(a.scrollWrap,"pswpTap",v.onGlobalTap),a.likelyTouchDevice||b.bind(a.scrollWrap,"mouseover",v.onMouseOver)}),l("unbindEvents",function(){y||F(),t&&clearInterval(t),b.unbind(document,"mouseout",L),b.unbind(document,"mousemove",K),b.unbind(d,"pswpTap click",A),b.unbind(a.scrollWrap,"pswpTap",v.onGlobalTap),b.unbind(a.scrollWrap,"mouseover",v.onMouseOver),c&&(b.unbind(document,c.eventK,v.updateFullscreen),c.isFullscreen()&&(q.hideAnimationDuration=0,c.exit()),c=null)}),l("destroy",function(){q.captionEl&&(f&&d.removeChild(f),b.removeClass(e,"pswp__caption--empty")),i&&(i.children[0].onclick=null),b.removeClass(d,"pswp__ui--over-close"),b.addClass(d,"pswp__ui--hidden"),v.setIdle(!1)}),q.showAnimationDuration||b.removeClass(d,"pswp__ui--hidden"),l("initialZoomIn",function(){q.showAnimationDuration&&b.removeClass(d,"pswp__ui--hidden")}),l("initialZoomOut",function(){b.addClass(d,"pswp__ui--hidden")}),l("parseVerticalMargin",P),T(),q.shareEl&&h&&i&&(y=!0),D(),Q(),M(),N()},v.setIdle=function(a){k=a,C(d,"ui--idle",a)},v.update=function(){x&&a.currItem?(v.updateIndexIndicator(),q.captionEl&&(q.addCaptionHTMLFn(a.currItem,e),C(e,"caption--empty",!a.currItem.title)),w=!0):w=!1,y||F(),D()},v.updateFullscreen=function(d){d&&setTimeout(function(){a.setScrollOffset(0,b.getScrollY())},50),b[(c.isFullscreen()?"add":"remove")+"Class"](a.template,"pswp--fs")},v.updateIndexIndicator=function(){q.counterEl&&(g.innerHTML=a.getCurrentIndex()+1+q.indexIndicatorSep+q.getNumItemsFn())},v.onGlobalTap=function(c){c=c||window.event;var d=c.target||c.srcElement;if(!r)if(c.detail&&"mouse"===c.detail.pointerType){if(I(d))return void a.close();b.hasClass(d,"pswp__img")&&(1===a.getZoomLevel()&&a.getZoomLevel()<=a.currItem.fitRatio?q.clickToCloseNonZoomable&&a.close():a.toggleDesktopZoom(c.detail.releasePoint))}else if(q.tapToToggleControls&&(x?v.hideControls():v.showControls()),q.tapToClose&&(b.hasClass(d,"pswp__img")||I(d)))return void a.close()},v.onMouseOver=function(a){a=a||window.event;var b=a.target||a.srcElement;C(d,"ui--over-close",I(b))},v.hideControls=function(){b.addClass(d,"pswp__ui--hidden"),x=!1},v.showControls=function(){x=!0,w||v.update(),b.removeClass(d,"pswp__ui--hidden")},v.supportsFullscreen=function(){var a=document;return!!(a.exitFullscreen||a.mozCancelFullScreen||a.webkitExitFullscreen||a.msExitFullscreen)},v.getFullscreenAPI=function(){var b,c=document.documentElement,d="fullscreenchange";return c.requestFullscreen?b={enterK:"requestFullscreen",exitK:"exitFullscreen",elementK:"fullscreenElement",eventK:d}:c.mozRequestFullScreen?b={enterK:"mozRequestFullScreen",exitK:"mozCancelFullScreen",elementK:"mozFullScreenElement",eventK:"moz"+d}:c.webkitRequestFullscreen?b={enterK:"webkitRequestFullscreen",exitK:"webkitExitFullscreen",elementK:"webkitFullscreenElement",eventK:"webkit"+d}:c.msRequestFullscreen&&(b={enterK:"msRequestFullscreen",exitK:"msExitFullscreen",elementK:"msFullscreenElement",eventK:"MSFullscreenChange"}),b&&(b.enter=function(){return j=q.closeOnScroll,q.closeOnScroll=!1,"webkitRequestFullscreen"!==this.enterK?a.template[this.enterK]():void a.template[this.enterK](Element.ALLOW_KEYBOARD_INPUT)},b.exit=function(){return q.closeOnScroll=j,document[this.exitK]()},b.isFullscreen=function(){return document[this.elementK]}),b}};return a});
\ No newline at end of file
+!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.PhotoSwipeUI_Default=t()}(this,function(){"use strict";return function(e,t){var n,o,l,r,i,s,a,u,c,p,d,m,f,h,w,g,v,b,_,C=this,T=!1,I=!0,E=!0,F={barsSize:{top:44,bottom:"auto"},closeElClasses:["item","caption","zoom-wrap","ui","top-bar"],timeToIdle:4e3,timeToIdleOutside:1e3,loadingIndicatorDelay:1e3,addCaptionHTMLFn:function(e,t){return e.title?(t.children[0].innerHTML=e.title,!0):(t.children[0].innerHTML="",!1)},closeEl:!0,captionEl:!0,fullscreenEl:!0,zoomEl:!0,shareEl:!0,counterEl:!0,arrowEl:!0,preloaderEl:!0,tapToClose:!1,tapToToggleControls:!0,clickToCloseNonZoomable:!0,shareButtons:[{id:"facebook",label:"Share on Facebook",url:"https://www.facebook.com/sharer/sharer.php?u={{url}}"},{id:"twitter",label:"Tweet",url:"https://twitter.com/intent/tweet?text={{text}}&url={{url}}"},{id:"pinterest",label:"Pin it",url:"http://www.pinterest.com/pin/create/button/?url={{url}}&media={{image_url}}&description={{text}}"},{id:"download",label:"Download image",url:"{{raw_image_url}}",download:!0}],getImageURLForShare:function(){return e.currItem.src||""},getPageURLForShare:function(){return window.location.href},getTextForShare:function(){return e.currItem.title||""},indexIndicatorSep:" / ",fitControlsWidth:1200},x=function(e){if(g)return!0;e=e||window.event,w.timeToIdle&&w.mouseUsed&&!c&&D();for(var n,o,l=(e.target||e.srcElement).getAttribute("class")||"",r=0;r-1&&(n.onTap(),o=!0);if(o){e.stopPropagation&&e.stopPropagation(),g=!0;var i=t.features.isOldAndroid?600:30;v=setTimeout(function(){g=!1},i)}},S=function(){return!e.likelyTouchDevice||w.mouseUsed||screen.width>w.fitControlsWidth},k=function(e,n,o){t[(o?"add":"remove")+"Class"](e,"pswp__"+n)},K=function(){var e=1===w.getNumItemsFn();e!==h&&(k(o,"ui--one-slide",e),h=e)},L=function(){k(a,"share-modal--hidden",E)},O=function(){return(E=!E)?(t.removeClass(a,"pswp__share-modal--fade-in"),setTimeout(function(){E&&L()},300)):(L(),setTimeout(function(){E||t.addClass(a,"pswp__share-modal--fade-in")},30)),E||y(),!1},R=function(t){var n=(t=t||window.event).target||t.srcElement;return e.shout("shareLinkClick",t,n),!(!n.href||!n.hasAttribute("download")&&(window.open(n.href,"pswp_share","scrollbars=yes,resizable=yes,toolbar=no,location=yes,width=550,height=420,top=100,left="+(window.screen?Math.round(screen.width/2-275):100)),E||O(),1))},y=function(){for(var e,t,n,o,l="",r=0;r"+e.label+"",w.parseShareButtonOut&&(l=w.parseShareButtonOut(e,l));a.children[0].innerHTML=l,a.children[0].onclick=R},z=function(e){for(var n=0;n=.95&&C.showControls()});var e;p("onPinchClose",function(t){I&&t<.9?(C.hideControls(),e=!0):e&&!I&&t>.9&&C.showControls()}),p("zoomGestureEnded",function(){(e=!1)&&!I&&C.showControls()})},N=[{name:"caption",option:"captionEl",onInit:function(e){l=e}},{name:"share-modal",option:"shareEl",onInit:function(e){a=e},onTap:function(){O()}},{name:"button--share",option:"shareEl",onInit:function(e){s=e},onTap:function(){O()}},{name:"button--zoom",option:"zoomEl",onTap:e.toggleDesktopZoom},{name:"counter",option:"counterEl",onInit:function(e){i=e}},{name:"button--close",option:"closeEl",onTap:e.close},{name:"button--arrow--left",option:"arrowEl",onTap:e.prev},{name:"button--arrow--right",option:"arrowEl",onTap:e.next},{name:"button--fs",option:"fullscreenEl",onTap:function(){n.isFullscreen()?n.exit():n.enter()}},{name:"preloader",option:"preloaderEl",onInit:function(e){d=e}}],W=function(){var e,n,l,r=function(o){if(o)for(var r=o.length,i=0;i-1&&(w[l.option]?(t.removeClass(e,"pswp__element--disabled"),l.onInit&&l.onInit(e)):t.addClass(e,"pswp__element--disabled"))}};r(o.children);var i=t.getChildByClass(o,"pswp__top-bar");i&&r(i.children)};C.init=function(){t.extend(e.options,F,!0),w=e.options,o=t.getChildByClass(e.scrollWrap,"pswp__ui"),p=e.listen,H(),p("beforeChange",C.update),p("doubleTap",function(t){var n=e.currItem.initialZoomLevel;e.getZoomLevel()!==n?e.zoomTo(n,t,333):e.zoomTo(w.getDoubleTapZoom(!1,e.currItem),t,333)}),p("preventDragEvent",function(e,t,n){var o=e.target||e.srcElement;o&&o.getAttribute("class")&&e.type.indexOf("mouse")>-1&&(o.getAttribute("class").indexOf("__caption")>0||/(SMALL|STRONG|EM)/i.test(o.tagName))&&(n.prevent=!1)}),p("bindEvents",function(){t.bind(o,"pswpTap click",x),t.bind(e.scrollWrap,"pswpTap",C.onGlobalTap),e.likelyTouchDevice||t.bind(e.scrollWrap,"mouseover",C.onMouseOver)}),p("unbindEvents",function(){E||O(),b&&clearInterval(b),t.unbind(document,"mouseout",A),t.unbind(document,"mousemove",D),t.unbind(o,"pswpTap click",x),t.unbind(e.scrollWrap,"pswpTap",C.onGlobalTap),t.unbind(e.scrollWrap,"mouseover",C.onMouseOver),n&&(t.unbind(document,n.eventK,C.updateFullscreen),n.isFullscreen()&&(w.hideAnimationDuration=0,n.exit()),n=null)}),p("destroy",function(){w.captionEl&&(r&&o.removeChild(r),t.removeClass(l,"pswp__caption--empty")),a&&(a.children[0].onclick=null),t.removeClass(o,"pswp__ui--over-close"),t.addClass(o,"pswp__ui--hidden"),C.setIdle(!1)}),w.showAnimationDuration||t.removeClass(o,"pswp__ui--hidden"),p("initialZoomIn",function(){w.showAnimationDuration&&t.removeClass(o,"pswp__ui--hidden")}),p("initialZoomOut",function(){t.addClass(o,"pswp__ui--hidden")}),p("parseVerticalMargin",q),W(),w.shareEl&&s&&a&&(E=!0),K(),B(),P(),U()},C.setIdle=function(e){c=e,k(o,"ui--idle",e)},C.update=function(){I&&e.currItem?(C.updateIndexIndicator(),w.captionEl&&(w.addCaptionHTMLFn(e.currItem,l),k(l,"caption--empty",!e.currItem.title)),T=!0):T=!1,E||O(),K()},C.updateFullscreen=function(o){o&&setTimeout(function(){e.setScrollOffset(0,t.getScrollY())},50),t[(n.isFullscreen()?"add":"remove")+"Class"](e.template,"pswp--fs")},C.updateIndexIndicator=function(){w.counterEl&&(i.innerHTML=e.getCurrentIndex()+1+w.indexIndicatorSep+w.getNumItemsFn())},C.onGlobalTap=function(n){var o=(n=n||window.event).target||n.srcElement;if(!g)if(n.detail&&"mouse"===n.detail.pointerType){if(z(o))return void e.close();t.hasClass(o,"pswp__img")&&(1===e.getZoomLevel()&&e.getZoomLevel()<=e.currItem.fitRatio?w.clickToCloseNonZoomable&&e.close():e.toggleDesktopZoom(n.detail.releasePoint))}else if(w.tapToToggleControls&&(I?C.hideControls():C.showControls()),w.tapToClose&&(t.hasClass(o,"pswp__img")||z(o)))return void e.close()},C.onMouseOver=function(e){var t=(e=e||window.event).target||e.srcElement;k(o,"ui--over-close",z(t))},C.hideControls=function(){t.addClass(o,"pswp__ui--hidden"),I=!1},C.showControls=function(){I=!0,T||C.update(),t.removeClass(o,"pswp__ui--hidden")},C.supportsFullscreen=function(){var e=document;return!!(e.exitFullscreen||e.mozCancelFullScreen||e.webkitExitFullscreen||e.msExitFullscreen)},C.getFullscreenAPI=function(){var t,n=document.documentElement,o="fullscreenchange";return n.requestFullscreen?t={enterK:"requestFullscreen",exitK:"exitFullscreen",elementK:"fullscreenElement",eventK:o}:n.mozRequestFullScreen?t={enterK:"mozRequestFullScreen",exitK:"mozCancelFullScreen",elementK:"mozFullScreenElement",eventK:"moz"+o}:n.webkitRequestFullscreen?t={enterK:"webkitRequestFullscreen",exitK:"webkitExitFullscreen",elementK:"webkitFullscreenElement",eventK:"webkit"+o}:n.msRequestFullscreen&&(t={enterK:"msRequestFullscreen",exitK:"msExitFullscreen",elementK:"msFullscreenElement",eventK:"MSFullscreenChange"}),t&&(t.enter=function(){if(u=w.closeOnScroll,w.closeOnScroll=!1,"webkitRequestFullscreen"!==this.enterK)return e.template[this.enterK]();e.template[this.enterK](Element.ALLOW_KEYBOARD_INPUT)},t.exit=function(){return w.closeOnScroll=u,document[this.exitK]()},t.isFullscreen=function(){return document[this.elementK]}),t}}});
\ No newline at end of file
diff --git a/assets/js/photoswipe/photoswipe.min.js b/assets/js/photoswipe/photoswipe.min.js
index 4d60954f971..0636cfaa423 100644
--- a/assets/js/photoswipe/photoswipe.min.js
+++ b/assets/js/photoswipe/photoswipe.min.js
@@ -1,4 +1,4 @@
/*! PhotoSwipe - v4.1.1 - 2015-12-24
* http://photoswipe.com
* Copyright (c) 2015 Dmitry Semenov; */
-!function(a,b){"function"==typeof define&&define.amd?define(b):"object"==typeof exports?module.exports=b():a.PhotoSwipe=b()}(this,function(){"use strict";var a=function(a,b,c,d){var e={features:null,bind:function(a,b,c,d){var e=(d?"remove":"add")+"EventListener";b=b.split(" ");for(var f=0;f0&&(g=parseInt(g[1],10),g>=1&&g<8&&(d.isOldIOSPhone=!0))}var h=f.match(/Android\s([0-9\.]*)/),i=h?h[1]:0;i=parseFloat(i),i>=1&&(i<4.4&&(d.isOldAndroid=!0),d.androidVersion=i),d.isMobileOpera=/opera mini|opera mobi/i.test(f)}for(var j,k,l=["transform","perspective","animationName"],m=["","webkit","Moz","ms","O"],n=0;n<4;n++){c=m[n];for(var o=0;o<3;o++)j=l[o],k=c+(c?j.charAt(0).toUpperCase()+j.slice(1):j),!d[j]&&k in b&&(d[j]=k);c&&!d.raf&&(c=c.toLowerCase(),d.raf=window[c+"RequestAnimationFrame"],d.raf&&(d.caf=window[c+"CancelAnimationFrame"]||window[c+"CancelRequestAnimationFrame"]))}if(!d.raf){var p=0;d.raf=function(a){var b=(new Date).getTime(),c=Math.max(0,16-(b-p)),d=window.setTimeout(function(){a(b+c)},c);return p=b+c,d},d.caf=function(a){clearTimeout(a)}}return d.svg=!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect,e.features=d,d}};e.detectFeatures(),e.features.oldIE&&(e.bind=function(a,b,c,d){b=b.split(" ");for(var e,f=(d?"detach":"attach")+"Event",g=function(){c.handleEvent.call(c)},h=0;hb-1?a-b:a<0?b+a:a},Aa={},Ba=function(a,b){return Aa[a]||(Aa[a]=[]),Aa[a].push(b)},Ca=function(a){var b=Aa[a];if(b){var c=Array.prototype.slice.call(arguments);c.shift();for(var d=0;df.currItem.fitRatio?xa||(lc(f.currItem,!1,!0),xa=!0):xa&&(lc(f.currItem),xa=!1)),Fa(da,oa.x,oa.y,s))},Ha=function(a){a.container&&Fa(a.container.style,a.initialPosition.x,a.initialPosition.y,a.initialZoomLevel,a)},Ia=function(a,b){b[E]=u+a+"px, 0px"+v},Ja=function(a,b){if(!i.loop&&b){var c=m+(sa.x*qa-a)/sa.x,d=Math.round(a-sb.x);(c<0&&d>0||c>=_b()-1&&d<0)&&(a=sb.x+d*i.mainScrollEndFriction)}sb.x=a,Ia(a,n)},Ka=function(a,b){var c=tb[a]-ra[a];return na[a]+ma[a]+c-c*(b/t)},La=function(a,b){a.x=b.x,a.y=b.y,b.id&&(a.id=b.id)},Ma=function(a){a.x=Math.round(a.x),a.y=Math.round(a.y)},Na=null,Oa=function(){Na&&(e.unbind(document,"mousemove",Oa),e.addClass(a,"pswp--has_mouse"),i.mouseUsed=!0,Ca("mouseUsed")),Na=setTimeout(function(){Na=null},100)},Pa=function(){e.bind(document,"keydown",f),N.transform&&e.bind(f.scrollWrap,"click",f),i.mouseUsed||e.bind(document,"mousemove",Oa),e.bind(window,"resize scroll",f),Ca("bindEvents")},Qa=function(){e.unbind(window,"resize",f),e.unbind(window,"scroll",r.scroll),e.unbind(document,"keydown",f),e.unbind(document,"mousemove",Oa),N.transform&&e.unbind(f.scrollWrap,"click",f),U&&e.unbind(window,p,f),Ca("unbindEvents")},Ra=function(a,b){var c=hc(f.currItem,pa,a);return b&&(ca=c),c},Sa=function(a){return a||(a=f.currItem),a.initialZoomLevel},Ta=function(a){return a||(a=f.currItem),a.w>0?i.maxSpreadZoom:1},Ua=function(a,b,c,d){return d===f.currItem.initialZoomLevel?(c[a]=f.currItem.initialPosition[a],!0):(c[a]=Ka(a,d),c[a]>b.min[a]?(c[a]=b.min[a],!0):c[a]1?1:a.fitRatio,c=a.container.style,d=b*a.w,e=b*a.h;c.width=d+"px",c.height=e+"px",c.left=a.initialPosition.x+"px",c.top=a.initialPosition.y+"px"},Ga=function(){if(da){var a=da,b=f.currItem,c=b.fitRatio>1?1:b.fitRatio,d=c*b.w,e=c*b.h;a.width=d+"px",a.height=e+"px",a.left=oa.x+"px",a.top=oa.y+"px"}}},Wa=function(a){var b="";i.escKey&&27===a.keyCode?b="close":i.arrowKeys&&(37===a.keyCode?b="prev":39===a.keyCode&&(b="next")),b&&(a.ctrlKey||a.altKey||a.shiftKey||a.metaKey||(a.preventDefault?a.preventDefault():a.returnValue=!1,f[b]()))},Xa=function(a){a&&(X||W||ea||S)&&(a.preventDefault(),a.stopPropagation())},Ya=function(){f.setScrollOffset(0,e.getScrollY())},Za={},$a=0,_a=function(a){Za[a]&&(Za[a].raf&&I(Za[a].raf),$a--,delete Za[a])},ab=function(a){Za[a]&&_a(a),Za[a]||($a++,Za[a]={})},bb=function(){for(var a in Za)Za.hasOwnProperty(a)&&_a(a)},cb=function(a,b,c,d,e,f,g){var h,i=Da();ab(a);var j=function(){if(Za[a]){if(h=Da()-i,h>=d)return _a(a),f(c),void(g&&g());f((c-b)*e(h/d)+b),Za[a].raf=H(j)}};j()},db={shout:Ca,listen:Ba,viewportSize:pa,options:i,isMainScrollAnimating:function(){return ea},getZoomLevel:function(){return s},getCurrentIndex:function(){return m},isDragging:function(){return U},isZooming:function(){return _},setScrollOffset:function(a,b){ra.x=a,M=ra.y=b,Ca("updateScrollOffset",ra)},applyZoomPan:function(a,b,c,d){oa.x=b,oa.y=c,s=a,Ga(d)},init:function(){if(!j&&!k){var c;f.framework=e,f.template=a,f.bg=e.getChildByClass(a,"pswp__bg"),J=a.className,j=!0,N=e.detectFeatures(),H=N.raf,I=N.caf,E=N.transform,L=N.oldIE,f.scrollWrap=e.getChildByClass(a,"pswp__scroll-wrap"),f.container=e.getChildByClass(f.scrollWrap,"pswp__container"),n=f.container.style,f.itemHolders=y=[{el:f.container.children[0],wrap:0,index:-1},{el:f.container.children[1],wrap:0,index:-1},{el:f.container.children[2],wrap:0,index:-1}],y[0].el.style.display=y[2].el.style.display="none",Va(),r={resize:f.updateSize,scroll:Ya,keydown:Wa,click:Xa};var d=N.isOldIOSPhone||N.isOldAndroid||N.isMobileOpera;for(N.animationName&&N.transform&&!d||(i.showAnimationDuration=i.hideAnimationDuration=0),c=0;c=_b())&&(m=0),f.currItem=$b(m),(N.isOldIOSPhone||N.isOldAndroid)&&(ua=!1),a.setAttribute("aria-hidden","false"),i.modal&&(ua?a.style.position="fixed":(a.style.position="absolute",a.style.top=e.getScrollY()+"px")),void 0===M&&(Ca("initialLayout"),M=K=e.getScrollY());var l="pswp--open ";for(i.mainClass&&(l+=i.mainClass+" "),i.showHideOpacity&&(l+="pswp--animate_opacity "),l+=G?"pswp--touch":"pswp--notouch",l+=N.animationName?" pswp--css_animation":"",l+=N.svg?" pswp--svg":"",e.addClass(a,l),f.updateSize(),o=-1,ta=null,c=0;cca.min.x?a=ca.min.x:aca.min.y?b=ca.min.y:b=h&&(o+=ta+(ta>0?-h:h),c=h);for(var d=0;d0?(b=y.shift(),y[h-1]=b,o++,Ia((o+2)*sa.x,b.el.style),f.setContent(b,m-c+d+1+1)):(b=y.pop(),y.unshift(b),o--,Ia(o*sa.x,b.el.style),f.setContent(b,m+c-d-1-1));if(da&&1===Math.abs(ta)){var e=$b(z);e.initialZoomLevel!==s&&(hc(e,pa),lc(e),Ha(e))}ta=0,f.updateCurrZoomItem(),z=m,Ca("afterChange")}}},updateSize:function(b){if(!ua&&i.modal){var c=e.getScrollY();if(M!==c&&(a.style.top=c+"px",M=c),!b&&wa.x===window.innerWidth&&wa.y===window.innerHeight)return;wa.x=window.innerWidth,wa.y=window.innerHeight,a.style.height=wa.y+"px"}if(pa.x=f.scrollWrap.clientWidth,pa.y=f.scrollWrap.clientHeight,Ya(),sa.x=pa.x+Math.round(pa.x*i.spacing),sa.y=pa.y,Ja(sa.x*qa),Ca("beforeResize"),void 0!==o){for(var d,g,j,k=0;k2&&(j=za(j)),g=$b(j),g&&(x||g.needsUpdate||!g.bounds)?(f.cleanSlide(g),f.setContent(d,j),1===k&&(f.currItem=g,f.updateCurrZoomItem(!0)),g.needsUpdate=!1):d.index===-1&&j>=0&&f.setContent(d,j),g&&g.container&&(hc(g,pa),lc(g),Ha(g));x=!1}t=s=f.currItem.initialZoomLevel,ca=f.currItem.bounds,ca&&(oa.x=ca.center.x,oa.y=ca.center.y,Ga(!0)),Ca("resize")},zoomTo:function(a,b,c,d,f){b&&(t=s,tb.x=Math.abs(b.x)-oa.x,tb.y=Math.abs(b.y)-oa.y,La(na,oa));var g=Ra(a,!1),h={};Ua("x",g,h,a),Ua("y",g,h,a);var i=s,j={x:oa.x,y:oa.y};Ma(h);var k=function(b){1===b?(s=a,oa.x=h.x,oa.y=h.y):(s=(a-i)*b+i,oa.x=(h.x-j.x)*b+j.x,oa.y=(h.y-j.y)*b+j.y),f&&f(b),Ga(1===b)};c?cb("customZoomTo",0,1,c,d||e.easing.sine.inOut,k):k(1)}},eb=30,fb=10,gb={},hb={},ib={},jb={},kb={},lb=[],mb={},nb=[],ob={},pb=0,qb=la(),rb=0,sb=la(),tb=la(),ub=la(),vb=function(a,b){return a.x===b.x&&a.y===b.y},wb=function(a,b){return Math.abs(a.x-b.x)-1)&&(b(a)?a:Bb(a.parentNode,b)))},Cb={},Db=function(a,b){return Cb.prevent=!Bb(a.target,i.isClickableElement),Ca("preventDragEvent",a,b,Cb),Cb.prevent},Eb=function(a,b){return b.x=a.pageX,b.y=a.pageY,b.id=a.identifier,b},Fb=function(a,b,c){c.x=.5*(a.x+b.x),c.y=.5*(a.y+b.y)},Gb=function(a,b,c){if(a-P>50){var d=nb.length>2?nb.shift():{};d.x=b,d.y=c,nb.push(d),P=a}},Hb=function(){var a=oa.y-f.currItem.initialPosition.y;return 1-Math.abs(a/(pa.y/2))},Ib={},Jb={},Kb=[],Lb=function(a){for(;Kb.length>0;)Kb.pop();return F?(ka=0,lb.forEach(function(a){0===ka?Kb[0]=a:1===ka&&(Kb[1]=a),ka++})):a.type.indexOf("touch")>-1?a.touches&&a.touches.length>0&&(Kb[0]=Eb(a.touches[0],Ib),a.touches.length>1&&(Kb[1]=Eb(a.touches[1],Jb))):(Ib.x=a.pageX,Ib.y=a.pageY,Ib.id="",Kb[0]=Ib),Kb},Mb=function(a,b){var c,d,e,g,h=0,j=oa[a]+b[a],k=b[a]>0,l=sb.x+b.x,m=sb.x-mb.x;return c=j>ca.min[a]||jca.min[a]&&(c=i.panEndFriction,h=ca.min[a]-j,d=ca.min[a]-na[a]),(d<=0||m<0)&&_b()>1?(g=l,m<0&&l>mb.x&&(g=mb.x)):ca.min.x!==ca.max.x&&(e=j)):(j0)&&_b()>1?(g=l,m>0&&lf.currItem.fitRatio&&(oa[a]+=b[a]*c)):(void 0!==g&&(Ja(g,!0),Z=g!==mb.x),ca.min.x!==ca.max.x&&(void 0!==e?oa.x=e:Z||(oa.x+=b.x*c)),void 0!==g)},Nb=function(a){if(!("mousedown"===a.type&&a.button>0)){if(Zb)return void a.preventDefault();if(!T||"mousedown"!==a.type){if(Db(a,!0)&&a.preventDefault(),Ca("pointerDown"),F){var b=e.arraySearch(lb,a.pointerId,"id");b<0&&(b=lb.length),lb[b]={x:a.pageX,y:a.pageY,id:a.pointerId}}var c=Lb(a),d=c.length;$=null,bb(),U&&1!==d||(U=ga=!0,e.bind(window,p,f),R=ja=ha=S=Z=X=V=W=!1,fa=null,Ca("firstTouchStart",c),La(na,oa),ma.x=ma.y=0,La(jb,c[0]),La(kb,jb),mb.x=sa.x*qa,nb=[{x:jb.x,y:jb.y}],P=O=Da(),Ra(s,!0),yb(),zb()),!_&&d>1&&!ea&&!Z&&(t=s,W=!1,_=V=!0,ma.y=ma.x=0,La(na,oa),La(gb,c[0]),La(hb,c[1]),Fb(gb,hb,ub),tb.x=Math.abs(ub.x)-oa.x,tb.y=Math.abs(ub.y)-oa.y,aa=ba=xb(gb,hb))}}},Ob=function(a){if(a.preventDefault(),F){var b=e.arraySearch(lb,a.pointerId,"id");if(b>-1){var c=lb[b];c.x=a.pageX,c.y=a.pageY}}if(U){var d=Lb(a);if(fa||X||_)$=d;else if(sb.x!==sa.x*qa)fa="h";else{var f=Math.abs(d[0].x-jb.x)-Math.abs(d[0].y-jb.y);Math.abs(f)>=fb&&(fa=f>0?"h":"v",$=d)}}},Pb=function(){if($){var a=$.length;if(0!==a)if(La(gb,$[0]),ib.x=gb.x-jb.x,ib.y=gb.y-jb.y,_&&a>1){if(jb.x=gb.x,jb.y=gb.y,!ib.x&&!ib.y&&vb($[1],hb))return;La(hb,$[1]),W||(W=!0,Ca("zoomGestureStarted"));var b=xb(gb,hb),c=Ub(b);c>f.currItem.initialZoomLevel+f.currItem.initialZoomLevel/15&&(ja=!0);var d=1,e=Sa(),g=Ta();if(c1&&(d=1),c=e-d*(e/3);else c>g&&(d=(c-g)/(6*e),d>1&&(d=1),c=g+d*e);d<0&&(d=0),aa=b,Fb(gb,hb,qb),ma.x+=qb.x-ub.x,ma.y+=qb.y-ub.y,La(ub,qb),oa.x=Ka("x",c),oa.y=Ka("y",c),R=c>s,s=c,Ga()}else{if(!fa)return;if(ga&&(ga=!1,Math.abs(ib.x)>=fb&&(ib.x-=$[0].x-kb.x),Math.abs(ib.y)>=fb&&(ib.y-=$[0].y-kb.y)),jb.x=gb.x,jb.y=gb.y,0===ib.x&&0===ib.y)return;if("v"===fa&&i.closeOnVerticalDrag&&!Ab()){ma.y+=ib.y,oa.y+=ib.y;var k=Hb();return S=!0,Ca("onVerticalDrag",k),Ea(k),void Ga()}Gb(Da(),gb.x,gb.y),X=!0,ca=f.currItem.bounds;var l=Mb("x",ib);l||(Mb("y",ib),Ma(oa),Ga())}}},Qb=function(a){if(N.isOldAndroid){if(T&&"mouseup"===a.type)return;a.type.indexOf("touch")>-1&&(clearTimeout(T),T=setTimeout(function(){T=0},600))}Ca("pointerUp"),Db(a,!1)&&a.preventDefault();var b;if(F){var c=e.arraySearch(lb,a.pointerId,"id");if(c>-1)if(b=lb.splice(c,1)[0],navigator.pointerEnabled)b.type=a.pointerType||"mouse";else{var d={4:"mouse",2:"touch",3:"pen"};b.type=d[a.pointerType],b.type||(b.type=a.pointerType||"mouse")}}var g,h=Lb(a),j=h.length;if("mouseup"===a.type&&(j=0),2===j)return $=null,!0;1===j&&La(kb,h[0]),0!==j||fa||ea||(b||("mouseup"===a.type?b={x:a.pageX,y:a.pageY,type:"mouse"}:a.changedTouches&&a.changedTouches[0]&&(b={x:a.changedTouches[0].pageX,y:a.changedTouches[0].pageY,type:"touch"})),Ca("touchRelease",a,b));var k=-1;if(0===j&&(U=!1,e.unbind(window,p,f),yb(),_?k=0:rb!==-1&&(k=Da()-rb)),rb=1===j?Da():-1,g=k!==-1&&k<150?"zoom":"swipe",_&&j<2&&(_=!1,1===j&&(g="zoomPointerUp"),Ca("zoomGestureEnded")),$=null,X||W||ea||S)if(bb(),Q||(Q=Rb()),Q.calculateSwipeSpeed("x"),S){var l=Hb();if(lf.currItem.fitRatio&&Sb(Q))}},Rb=function(){var a,b,c={lastFlickOffset:{},lastFlickDist:{},lastFlickSpeed:{},slowDownRatio:{},slowDownRatioReverse:{},speedDecelerationRatio:{},speedDecelerationRatioAbs:{},distanceOffset:{},backAnimDestination:{},backAnimStarted:{},calculateSwipeSpeed:function(d){nb.length>1?(a=Da()-P+50,b=nb[nb.length-2][d]):(a=Da()-O,b=kb[d]),c.lastFlickOffset[d]=jb[d]-b,c.lastFlickDist[d]=Math.abs(c.lastFlickOffset[d]),c.lastFlickDist[d]>20?c.lastFlickSpeed[d]=c.lastFlickOffset[d]/a:c.lastFlickSpeed[d]=0,Math.abs(c.lastFlickSpeed[d])<.1&&(c.lastFlickSpeed[d]=0),c.slowDownRatio[d]=.95,c.slowDownRatioReverse[d]=1-c.slowDownRatio[d],c.speedDecelerationRatio[d]=1},calculateOverBoundsAnimOffset:function(a,b){c.backAnimStarted[a]||(oa[a]>ca.min[a]?c.backAnimDestination[a]=ca.min[a]:oa[a]eb&&(h||b.lastFlickOffset.x>20)?d=-1:g<-eb&&(h||b.lastFlickOffset.x<-20)&&(d=1)}var j;d&&(m+=d,m<0?(m=i.loop?_b()-1:0,j=!0):m>=_b()&&(m=i.loop?0:_b()-1,j=!0),j&&!i.loop||(ta+=d,qa-=d,c=!0));var k,l=sa.x*qa,n=Math.abs(l-sb.x);return c||l>sb.x==b.lastFlickSpeed.x>0?(k=Math.abs(b.lastFlickSpeed.x)>0?n/Math.abs(b.lastFlickSpeed.x):333,k=Math.min(k,400),k=Math.max(k,250)):k=333,pb===m&&(c=!1),ea=!0,Ca("mainScrollAnimStart"),cb("mainScroll",sb.x,l,k,e.easing.cubic.out,Ja,function(){bb(),ea=!1,pb=-1,(c||pb!==m)&&f.updateCurrItem(),Ca("mainScrollAnimComplete")}),c&&f.updateCurrItem(!0),c},Ub=function(a){return 1/ba*a*t},Vb=function(){var a=s,b=Sa(),c=Ta();sc&&(a=c);var d,g=1,h=ia;return ha&&!R&&!ja&&s1||navigator.msMaxTouchPoints>1),f.likelyTouchDevice=G,r[A]=Nb,r[B]=Ob,r[C]=Qb,D&&(r[D]=r[C]),N.touch&&(q+=" mousedown",p+=" mousemove mouseup",r.mousedown=r[A],r.mousemove=r[B],r.mouseup=r[C]),G||(i.allowPanToNext=!1)}}});var Wb,Xb,Yb,Zb,$b,_b,ac,bc=function(b,c,d,g){Wb&&clearTimeout(Wb),Zb=!0,Yb=!0;var h;b.initialLayout?(h=b.initialLayout,b.initialLayout=null):h=i.getThumbBoundsFn&&i.getThumbBoundsFn(m);var j=d?i.hideAnimationDuration:i.showAnimationDuration,k=function(){_a("initialZoom"),d?(f.template.removeAttribute("style"),f.bg.removeAttribute("style")):(Ea(1),c&&(c.style.display="block"),e.addClass(a,"pswp--animated-in"),Ca("initialZoom"+(d?"OutEnd":"InEnd"))),g&&g(),Zb=!1};if(!j||!h||void 0===h.x)return Ca("initialZoom"+(d?"Out":"In")),s=b.initialZoomLevel,La(oa,b.initialPosition),Ga(),a.style.opacity=d?0:1,Ea(1),void(j?setTimeout(function(){k()},j):k());var n=function(){var c=l,g=!f.currItem.src||f.currItem.loadError||i.showHideOpacity;b.miniImg&&(b.miniImg.style.webkitBackfaceVisibility="hidden"),d||(s=h.w/b.w,oa.x=h.x,oa.y=h.y-K,f[g?"template":"bg"].style.opacity=.001,Ga()),ab("initialZoom"),d&&!c&&e.removeClass(a,"pswp--animated-in"),g&&(d?e[(c?"remove":"add")+"Class"](a,"pswp--animate_opacity"):setTimeout(function(){e.addClass(a,"pswp--animate_opacity")},30)),Wb=setTimeout(function(){if(Ca("initialZoom"+(d?"Out":"In")),d){var f=h.w/b.w,i={x:oa.x,y:oa.y},l=s,m=ia,n=function(b){1===b?(s=f,oa.x=h.x,oa.y=h.y-M):(s=(f-l)*b+l,oa.x=(h.x-i.x)*b+i.x,oa.y=(h.y-M-i.y)*b+i.y),Ga(),g?a.style.opacity=1-b:Ea(m-b*m)};c?cb("initialZoom",0,1,j,e.easing.cubic.out,n,k):(n(1),Wb=setTimeout(k,j+20))}else s=b.initialZoomLevel,La(oa,b.initialPosition),Ga(),Ea(1),g?a.style.opacity=1:Ea(1),Wb=setTimeout(k,j+20)},d?25:90)};n()},cc={},dc=[],ec={index:0,errorMsg:'
' . sprintf(
+ /* translators: %s: Documentation URL */
+ __( 'Should you need help understanding, using, or extending WooCommerce, please read our documentation. You will find all kinds of resources including snippets, tutorials and much more.', 'woocommerce' ),
+ 'https://docs.woocommerce.com/documentation/plugins/woocommerce/?utm_source=helptab&utm_medium=product&utm_content=docs&utm_campaign=woocommerceplugin'
+ ) . '
' .
+ '
' . sprintf(
+ /* translators: %s: Forum URL */
+ __( 'For further assistance with WooCommerce core you can use the community forum. If you need help with premium extensions sold by WooCommerce, please use our helpdesk.', 'woocommerce' ),
+ 'https://wordpress.org/support/plugin/woocommerce',
+ 'https://woocommerce.com/my-account/tickets/?utm_source=helptab&utm_medium=product&utm_content=tickets&utm_campaign=woocommerceplugin'
+ ) . '
' .
+ '
' . __( 'Before asking for help we recommend checking the system status page to identify any problems with your configuration.', 'woocommerce' ) . '
' . sprintf( __( 'If you find a bug within WooCommerce core you can create a ticket via Github issues. Ensure you read the contribution guide prior to submitting your report. To help us solve your issue, please be as descriptive as possible and include your system status report.', 'woocommerce' ), 'https://github.com/woocommerce/woocommerce/issues?state=open', 'https://github.com/woocommerce/woocommerce/blob/master/.github/CONTRIBUTING.md', admin_url( 'admin.php?page=wc-status' ) ) . '
' . __( 'If you would like to learn about using WooCommerce from an expert, consider a WooCommerce course to further your education.', 'woocommerce' ) . '
' . sprintf(
- __( 'Should you need help understanding, using, or extending WooCommerce, please read our documentation. You will find all kinds of resources including snippets, tutorials and much more.' , 'woocommerce' ),
- 'https://docs.woocommerce.com/documentation/plugins/woocommerce/?utm_source=helptab&utm_medium=product&utm_content=docs&utm_campaign=woocommerceplugin'
- ) . '
' .
- '
' . sprintf(
- __( 'For further assistance with WooCommerce core you can use the community forum. If you need help with premium extensions sold by WooCommerce, please use our helpdesk.', 'woocommerce' ),
- 'https://wordpress.org/support/plugin/woocommerce',
- 'https://woocommerce.com/my-account/tickets/?utm_source=helptab&utm_medium=product&utm_content=tickets&utm_campaign=woocommerceplugin'
- ) . '
' .
- '
' . __( 'Before asking for help we recommend checking the system status page to identify any problems with your configuration.', 'woocommerce' ) . '
' . sprintf( __( 'If you find a bug within WooCommerce core you can create a ticket via Github issues. Ensure you read the contribution guide prior to submitting your report. To help us solve your issue, please be as descriptive as possible and include your system status report.', 'woocommerce' ), 'https://github.com/woocommerce/woocommerce/issues?state=open', 'https://github.com/woocommerce/woocommerce/blob/master/.github/CONTRIBUTING.md', admin_url( 'admin.php?page=wc-status' ) ) . '
' . __( 'If you would like to learn about using WooCommerce from an expert, consider following a WooCommerce course offered by one of our educational partners.', 'woocommerce' ) . '
@@ -291,10 +338,10 @@ class WC_Admin_Menus {
* Add the "Visit Store" link in admin bar main menu.
*
* @since 2.4.0
- * @param WP_Admin_Bar $wp_admin_bar
+ * @param WP_Admin_Bar $wp_admin_bar Admin bar instance.
*/
public function admin_bar_menus( $wp_admin_bar ) {
- if ( ! is_admin() || ! is_user_logged_in() ) {
+ if ( ! is_admin() || ! is_admin_bar_showing() ) {
return;
}
@@ -304,20 +351,20 @@ class WC_Admin_Menus {
}
// Don't display when shop page is the same of the page on front.
- if ( get_option( 'page_on_front' ) == wc_get_page_id( 'shop' ) ) {
+ if ( intval( get_option( 'page_on_front' ) ) === wc_get_page_id( 'shop' ) ) {
return;
}
// Add an option to visit the store.
- $wp_admin_bar->add_node( array(
- 'parent' => 'site-name',
- 'id' => 'view-store',
- 'title' => __( 'Visit Store', 'woocommerce' ),
- 'href' => wc_get_page_permalink( 'shop' ),
- ) );
+ $wp_admin_bar->add_node(
+ array(
+ 'parent' => 'site-name',
+ 'id' => 'view-store',
+ 'title' => __( 'Visit Store', 'woocommerce' ),
+ 'href' => wc_get_page_permalink( 'shop' ),
+ )
+ );
}
}
-endif;
-
return new WC_Admin_Menus();
diff --git a/includes/admin/class-wc-admin-meta-boxes.php b/includes/admin/class-wc-admin-meta-boxes.php
index 2b3eb957e90..81fced20a5d 100644
--- a/includes/admin/class-wc-admin-meta-boxes.php
+++ b/includes/admin/class-wc-admin-meta-boxes.php
@@ -31,7 +31,7 @@ class WC_Admin_Meta_Boxes {
*
* @var array
*/
- public static $meta_box_errors = array();
+ public static $meta_box_errors = array();
/**
* Constructor.
@@ -65,7 +65,7 @@ class WC_Admin_Meta_Boxes {
add_action( 'woocommerce_process_shop_coupon_meta', 'WC_Meta_Box_Coupon_Data::save', 10, 2 );
// Save Rating Meta Boxes.
- add_action( 'comment_edit_redirect', 'WC_Meta_Box_Product_Reviews::save', 1, 2 );
+ add_filter( 'wp_update_comment_data', 'WC_Meta_Box_Product_Reviews::save', 1 );
// Error handling (for showing errors from meta boxes on next page load).
add_action( 'admin_notices', array( $this, 'output_errors' ) );
@@ -74,6 +74,7 @@ class WC_Admin_Meta_Boxes {
/**
* Add an error message.
+ *
* @param string $text
*/
public static function add_error( $text ) {
@@ -168,9 +169,8 @@ class WC_Admin_Meta_Boxes {
global $post;
// Comments/Reviews
- if ( isset( $post ) && ( 'publish' == $post->post_status || 'private' == $post->post_status ) ) {
+ if ( isset( $post ) && ( 'publish' == $post->post_status || 'private' == $post->post_status ) && post_type_supports( 'product', 'comments' ) ) {
remove_meta_box( 'commentsdiv', 'product', 'normal' );
-
add_meta_box( 'commentsdiv', __( 'Reviews', 'woocommerce' ), 'post_comment_meta_box', 'product', 'normal' );
}
}
@@ -178,7 +178,7 @@ class WC_Admin_Meta_Boxes {
/**
* Check if we're saving, the trigger an action based on the post type.
*
- * @param int $post_id
+ * @param int $post_id
* @param object $post
*/
public function save_meta_boxes( $post_id, $post ) {
@@ -188,7 +188,7 @@ class WC_Admin_Meta_Boxes {
}
// Dont' save meta boxes for revisions or autosaves
- if ( defined( 'DOING_AUTOSAVE' ) || is_int( wp_is_post_revision( $post ) ) || is_int( wp_is_post_autosave( $post ) ) ) {
+ if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || is_int( wp_is_post_revision( $post ) ) || is_int( wp_is_post_autosave( $post ) ) ) {
return;
}
diff --git a/includes/admin/class-wc-admin-notices.php b/includes/admin/class-wc-admin-notices.php
index 45020eb38f6..b190b1caede 100644
--- a/includes/admin/class-wc-admin-notices.php
+++ b/includes/admin/class-wc-admin-notices.php
@@ -2,15 +2,11 @@
/**
* Display notices in admin
*
- * @author WooThemes
- * @category Admin
- * @package WooCommerce/Admin
- * @version 2.3.0
+ * @package WooCommerce\Admin
+ * @version 3.4.0
*/
-if ( ! defined( 'ABSPATH' ) ) {
- exit;
-}
+defined( 'ABSPATH' ) || exit;
/**
* WC_Admin_Notices Class.
@@ -19,22 +15,26 @@ class WC_Admin_Notices {
/**
* Stores notices.
+ *
* @var array
*/
private static $notices = array();
/**
* Array of notices - name => callback.
+ *
* @var array
*/
private static $core_notices = array(
- 'install' => 'install_notice',
- 'update' => 'update_notice',
- 'template_files' => 'template_file_check_notice',
- 'theme_support' => 'theme_check_notice',
- 'legacy_shipping' => 'legacy_shipping_notice',
- 'no_shipping_methods' => 'no_shipping_methods_notice',
- 'simplify_commerce' => 'simplify_commerce_notice',
+ 'install' => 'install_notice',
+ 'update' => 'update_notice',
+ 'template_files' => 'template_file_check_notice',
+ 'legacy_shipping' => 'legacy_shipping_notice',
+ 'no_shipping_methods' => 'no_shipping_methods_notice',
+ 'simplify_commerce' => 'simplify_commerce_notice',
+ 'regenerating_thumbnails' => 'regenerating_thumbnails_notice',
+ 'no_secure_connection' => 'secure_connection_notice',
+ 'wootenberg' => 'wootenberg_feature_plugin_notice',
);
/**
@@ -50,6 +50,7 @@ class WC_Admin_Notices {
if ( current_user_can( 'manage_woocommerce' ) ) {
add_action( 'admin_print_styles', array( __CLASS__, 'add_notices' ) );
+ add_action( 'activate_gutenberg/gutenberg.php', array( __CLASS__, 'add_wootenberg_feature_plugin_notice_on_gutenberg_activate' ) );
}
}
@@ -62,6 +63,7 @@ class WC_Admin_Notices {
/**
* Get notices
+ *
* @return array
*/
public static function get_notices() {
@@ -79,23 +81,25 @@ class WC_Admin_Notices {
* Reset notices for themes when switched or a new version of WC is installed.
*/
public static function reset_admin_notices() {
- if ( ! current_theme_supports( 'woocommerce' ) && ! in_array( get_option( 'template' ), wc_get_core_supported_themes() ) ) {
- self::add_notice( 'theme_support' );
- }
-
$simplify_options = get_option( 'woocommerce_simplify_commerce_settings', array() );
$location = wc_get_base_location();
- if ( ! class_exists( 'WC_Gateway_Simplify_Commerce_Loader' ) && ! empty( $simplify_options['enabled'] ) && 'yes' === $simplify_options['enabled'] && in_array( $location['country'], apply_filters( 'woocommerce_gateway_simplify_commerce_supported_countries', array( 'US', 'IE' ) ) ) ) {
- WC_Admin_Notices::add_notice( 'simplify_commerce' );
+ if ( ! class_exists( 'WC_Gateway_Simplify_Commerce_Loader' ) && ! empty( $simplify_options['enabled'] ) && 'yes' === $simplify_options['enabled'] && in_array( $location['country'], apply_filters( 'woocommerce_gateway_simplify_commerce_supported_countries', array( 'US', 'IE' ) ), true ) ) {
+ self::add_notice( 'simplify_commerce' );
}
+ if ( ! self::is_ssl() ) {
+ self::add_notice( 'no_secure_connection' );
+ }
+
+ self::add_wootenberg_feature_plugin_notice();
self::add_notice( 'template_files' );
}
/**
* Show a notice.
- * @param string $name
+ *
+ * @param string $name Notice name.
*/
public static function add_notice( $name ) {
self::$notices = array_unique( array_merge( self::get_notices(), array( $name ) ) );
@@ -103,7 +107,8 @@ class WC_Admin_Notices {
/**
* Remove a notice from being displayed.
- * @param string $name
+ *
+ * @param string $name Notice name.
*/
public static function remove_notice( $name ) {
self::$notices = array_diff( self::get_notices(), array( $name ) );
@@ -112,28 +117,34 @@ class WC_Admin_Notices {
/**
* See if a notice is being shown.
- * @param string $name
+ *
+ * @param string $name Notice name.
+ *
* @return boolean
*/
public static function has_notice( $name ) {
- return in_array( $name, self::get_notices() );
+ return in_array( $name, self::get_notices(), true );
}
/**
* Hide a notice if the GET variable is set.
*/
public static function hide_notices() {
- if ( isset( $_GET['wc-hide-notice'] ) && isset( $_GET['_wc_notice_nonce'] ) ) {
- if ( ! wp_verify_nonce( $_GET['_wc_notice_nonce'], 'woocommerce_hide_notices_nonce' ) ) {
- wp_die( __( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
+ if ( isset( $_GET['wc-hide-notice'] ) && isset( $_GET['_wc_notice_nonce'] ) ) { // WPCS: input var ok, CSRF ok.
+ if ( ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_wc_notice_nonce'] ) ), 'woocommerce_hide_notices_nonce' ) ) { // WPCS: input var ok, CSRF ok.
+ wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
}
if ( ! current_user_can( 'manage_woocommerce' ) ) {
- wp_die( __( 'Cheatin’ huh?', 'woocommerce' ) );
+ wp_die( esc_html__( 'You don’t have permission to do this.', 'woocommerce' ) );
}
- $hide_notice = sanitize_text_field( $_GET['wc-hide-notice'] );
+ $hide_notice = sanitize_text_field( wp_unslash( $_GET['wc-hide-notice'] ) ); // WPCS: input var ok, CSRF ok.
+
self::remove_notice( $hide_notice );
+
+ update_user_meta( get_current_user_id(), 'dismissed_' . $hide_notice . '_notice', true );
+
do_action( 'woocommerce_hide_' . $hide_notice . '_notice' );
}
}
@@ -144,22 +155,41 @@ class WC_Admin_Notices {
public static function add_notices() {
$notices = self::get_notices();
- if ( ! empty( $notices ) ) {
- wp_enqueue_style( 'woocommerce-activation', plugins_url( '/assets/css/activation.css', WC_PLUGIN_FILE ) );
- foreach ( $notices as $notice ) {
- if ( ! empty( self::$core_notices[ $notice ] ) && apply_filters( 'woocommerce_show_admin_notice', true, $notice ) ) {
- add_action( 'admin_notices', array( __CLASS__, self::$core_notices[ $notice ] ) );
- } else {
- add_action( 'admin_notices', array( __CLASS__, 'output_custom_notices' ) );
- }
+ if ( empty( $notices ) ) {
+ return;
+ }
+
+ $screen = get_current_screen();
+ $screen_id = $screen ? $screen->id : '';
+ $show_on_screens = array(
+ 'dashboard',
+ 'plugins',
+ );
+
+ // Notices should only show on WooCommerce screens, the main dashboard, and on the plugins screen.
+ if ( ! in_array( $screen_id, wc_get_screen_ids(), true ) && ! in_array( $screen_id, $show_on_screens, true ) ) {
+ return;
+ }
+
+ wp_enqueue_style( 'woocommerce-activation', plugins_url( '/assets/css/activation.css', WC_PLUGIN_FILE ), array(), WC_VERSION );
+
+ // Add RTL support.
+ wp_style_add_data( 'woocommerce-activation', 'rtl', 'replace' );
+
+ foreach ( $notices as $notice ) {
+ if ( ! empty( self::$core_notices[ $notice ] ) && apply_filters( 'woocommerce_show_admin_notice', true, $notice ) ) {
+ add_action( 'admin_notices', array( __CLASS__, self::$core_notices[ $notice ] ) );
+ } else {
+ add_action( 'admin_notices', array( __CLASS__, 'output_custom_notices' ) );
}
}
}
/**
* Add a custom notice.
- * @param string $name
- * @param string $notice_html
+ *
+ * @param string $name Notice name.
+ * @param string $notice_html Notice HTML.
*/
public static function add_custom_notice( $name, $notice_html ) {
self::add_notice( $name );
@@ -178,7 +208,7 @@ class WC_Admin_Notices {
$notice_html = get_option( 'woocommerce_admin_notice_' . $notice );
if ( $notice_html ) {
- include( 'views/html-notice-custom.php' );
+ include dirname( __FILE__ ) . '/views/html-notice-custom.php';
}
}
}
@@ -191,13 +221,13 @@ class WC_Admin_Notices {
public static function update_notice() {
if ( version_compare( get_option( 'woocommerce_db_version' ), WC_VERSION, '<' ) ) {
$updater = new WC_Background_Updater();
- if ( $updater->is_updating() || ! empty( $_GET['do_update_woocommerce'] ) ) {
- include( 'views/html-notice-updating.php' );
+ if ( $updater->is_updating() || ! empty( $_GET['do_update_woocommerce'] ) ) { // WPCS: input var ok, CSRF ok.
+ include dirname( __FILE__ ) . '/views/html-notice-updating.php';
} else {
- include( 'views/html-notice-update.php' );
+ include dirname( __FILE__ ) . '/views/html-notice-update.php';
}
} else {
- include( 'views/html-notice-updated.php' );
+ include dirname( __FILE__ ) . '/views/html-notice-updated.php';
}
}
@@ -205,17 +235,19 @@ class WC_Admin_Notices {
* If we have just installed, show a message with the install pages button.
*/
public static function install_notice() {
- include( 'views/html-notice-install.php' );
+ include dirname( __FILE__ ) . '/views/html-notice-install.php';
}
/**
* Show the Theme Check notice.
+ *
+ * @todo Remove this next major release.
*/
public static function theme_check_notice() {
- if ( ! current_theme_supports( 'woocommerce' ) && ! in_array( get_option( 'template' ), wc_get_core_supported_themes() ) ) {
- include( 'views/html-notice-theme-support.php' );
- } else {
- self::remove_notice( 'theme_support' );
+ wc_deprecated_function( 'WC_Admin_Notices::theme_check_notice', '3.3.0' );
+
+ if ( ! current_theme_supports( 'woocommerce' ) ) {
+ include dirname( __FILE__ ) . '/views/html-notice-theme-support.php';
}
}
@@ -231,12 +263,12 @@ class WC_Admin_Notices {
$theme_file = false;
if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/' . $file;
- } elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) {
- $theme_file = get_stylesheet_directory() . '/woocommerce/' . $file;
+ } elseif ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . $file ) ) {
+ $theme_file = get_stylesheet_directory() . '/' . WC()->template_path() . $file;
} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
$theme_file = get_template_directory() . '/' . $file;
- } elseif ( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) {
- $theme_file = get_template_directory() . '/woocommerce/' . $file;
+ } elseif ( file_exists( get_template_directory() . '/' . WC()->template_path() . $file ) ) {
+ $theme_file = get_template_directory() . '/' . WC()->template_path() . $file;
}
if ( false !== $theme_file ) {
@@ -251,7 +283,7 @@ class WC_Admin_Notices {
}
if ( $outdated ) {
- include( 'views/html-notice-template-check.php' );
+ include dirname( __FILE__ ) . '/views/html-notice-template-check.php';
} else {
self::remove_notice( 'template_files' );
}
@@ -272,7 +304,7 @@ class WC_Admin_Notices {
}
if ( $enabled ) {
- include( 'views/html-notice-legacy-shipping.php' );
+ include dirname( __FILE__ ) . '/views/html-notice-legacy-shipping.php';
} else {
self::remove_notice( 'template_files' );
}
@@ -282,14 +314,12 @@ class WC_Admin_Notices {
* No shipping methods.
*/
public static function no_shipping_methods_notice() {
- if ( wc_shipping_enabled() && ( empty( $_GET['page'] ) || empty( $_GET['tab'] ) || 'wc-settings' !== $_GET['page'] || 'shipping' !== $_GET['tab'] ) ) {
- global $wpdb;
-
+ if ( wc_shipping_enabled() && ( empty( $_GET['page'] ) || empty( $_GET['tab'] ) || 'wc-settings' !== $_GET['page'] || 'shipping' !== $_GET['tab'] ) ) { // WPCS: input var ok, CSRF ok.
$product_count = wp_count_posts( 'product' );
$method_count = wc_get_shipping_method_count();
if ( $product_count->publish > 0 && 0 === $method_count ) {
- include( 'views/html-notice-no-shipping-methods.php' );
+ include dirname( __FILE__ ) . '/views/html-notice-no-shipping-methods.php';
}
if ( $method_count > 0 ) {
@@ -304,14 +334,81 @@ class WC_Admin_Notices {
public static function simplify_commerce_notice() {
$location = wc_get_base_location();
- if ( class_exists( 'WC_Gateway_Simplify_Commerce_Loader' ) || ! in_array( $location['country'], apply_filters( 'woocommerce_gateway_simplify_commerce_supported_countries', array( 'US', 'IE' ) ) ) ) {
+ if ( class_exists( 'WC_Gateway_Simplify_Commerce_Loader' ) || ! in_array( $location['country'], apply_filters( 'woocommerce_gateway_simplify_commerce_supported_countries', array( 'US', 'IE' ) ), true ) ) {
self::remove_notice( 'simplify_commerce' );
return;
}
- if ( empty( $_GET['action'] ) ) {
- include( 'views/html-notice-simplify-commerce.php' );
+ if ( empty( $_GET['action'] ) ) { // WPCS: input var ok, CSRF ok.
+ include dirname( __FILE__ ) . '/views/html-notice-simplify-commerce.php';
}
}
+
+ /**
+ * Notice shown when regenerating thumbnails background process is running.
+ */
+ public static function regenerating_thumbnails_notice() {
+ include dirname( __FILE__ ) . '/views/html-notice-regenerating-thumbnails.php';
+ }
+
+ /**
+ * Notice about secure connection.
+ */
+ public static function secure_connection_notice() {
+ if ( self::is_ssl() || get_user_meta( get_current_user_id(), 'dismissed_no_secure_connection_notice', true ) ) {
+ return;
+ }
+
+ include dirname( __FILE__ ) . '/views/html-notice-secure-connection.php';
+ }
+
+ /**
+ * If Gutenberg is active, tell people about the Products block feature plugin.
+ *
+ * @since 3.4.3
+ * @todo Remove this notice and associated code once the feature plugin has been merged into core.
+ */
+ public static function add_wootenberg_feature_plugin_notice() {
+ if ( ( is_plugin_active( 'gutenberg/gutenberg.php' ) || version_compare( get_bloginfo( 'version' ), '5.0', '>=' ) ) && ! is_plugin_active( 'woo-gutenberg-products-block/woocommerce-gutenberg-products-block.php' ) ) {
+ self::add_notice( 'wootenberg' );
+ }
+ }
+
+ /**
+ * Tell people about the Products block feature plugin when they activate Gutenberg.
+ *
+ * @since 3.4.3
+ * @todo Remove this notice and associated code once the feature plugin has been merged into core.
+ */
+ public static function add_wootenberg_feature_plugin_notice_on_gutenberg_activate() {
+ if ( ! is_plugin_active( 'woo-gutenberg-products-block/woocommerce-gutenberg-products-block.php' ) && version_compare( get_bloginfo( 'version' ), '5.0', '<' ) ) {
+ self::add_notice( 'wootenberg' );
+ }
+ }
+
+ /**
+ * Notice about trying the Products block.
+ */
+ public static function wootenberg_feature_plugin_notice() {
+ if ( get_user_meta( get_current_user_id(), 'dismissed_wootenberg_notice', true ) || is_plugin_active( 'woo-gutenberg-products-block/woocommerce-gutenberg-products-block.php' ) ) {
+ self::remove_notice( 'wootenberg' );
+ return;
+ }
+
+ include dirname( __FILE__ ) . '/views/html-notice-wootenberg.php';
+ }
+
+ /**
+ * Determine if the store is running SSL.
+ *
+ * @return bool Flag SSL enabled.
+ * @since 3.5.1
+ */
+ protected static function is_ssl() {
+ $shop_page = 0 < wc_get_page_id( 'shop' ) ? get_permalink( wc_get_page_id( 'shop' ) ) : get_home_url();
+
+ return ( is_ssl() && 'https' === substr( $shop_page, 0, 5 ) );
+ }
+
}
WC_Admin_Notices::init();
diff --git a/includes/admin/class-wc-admin-permalink-settings.php b/includes/admin/class-wc-admin-permalink-settings.php
index ad50c0ebd43..ec6534cc142 100644
--- a/includes/admin/class-wc-admin-permalink-settings.php
+++ b/includes/admin/class-wc-admin-permalink-settings.php
@@ -13,7 +13,9 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
-if ( ! class_exists( 'WC_Admin_Permalink_Settings', false ) ) :
+if ( class_exists( 'WC_Admin_Permalink_Settings', false ) ) {
+ return new WC_Admin_Permalink_Settings();
+}
/**
* WC_Admin_Permalink_Settings Class.
@@ -39,30 +41,28 @@ class WC_Admin_Permalink_Settings {
* Init our settings.
*/
public function settings_init() {
- // Add a section to the permalinks page
add_settings_section( 'woocommerce-permalink', __( 'Product permalinks', 'woocommerce' ), array( $this, 'settings' ), 'permalink' );
- // Add our settings
add_settings_field(
- 'woocommerce_product_category_slug', // id
- __( 'Product category base', 'woocommerce' ), // setting title
- array( $this, 'product_category_slug_input' ), // display callback
- 'permalink', // settings page
- 'optional' // settings section
+ 'woocommerce_product_category_slug',
+ __( 'Product category base', 'woocommerce' ),
+ array( $this, 'product_category_slug_input' ),
+ 'permalink',
+ 'optional'
);
add_settings_field(
- 'woocommerce_product_tag_slug', // id
- __( 'Product tag base', 'woocommerce' ), // setting title
- array( $this, 'product_tag_slug_input' ), // display callback
- 'permalink', // settings page
- 'optional' // settings section
+ 'woocommerce_product_tag_slug',
+ __( 'Product tag base', 'woocommerce' ),
+ array( $this, 'product_tag_slug_input' ),
+ 'permalink',
+ 'optional'
);
add_settings_field(
- 'woocommerce_product_attribute_slug', // id
- __( 'Product attribute base', 'woocommerce' ), // setting title
- array( $this, 'product_attribute_slug_input' ), // display callback
- 'permalink', // settings page
- 'optional' // settings section
+ 'woocommerce_product_attribute_slug',
+ __( 'Product attribute base', 'woocommerce' ),
+ array( $this, 'product_attribute_slug_input' ),
+ 'permalink',
+ 'optional'
);
$this->permalinks = wc_get_permalink_structure();
@@ -73,7 +73,7 @@ class WC_Admin_Permalink_Settings {
*/
public function product_category_slug_input() {
?>
-
+
-
+
shop would make your product links like %sshop/sample-product/. This setting affects product URLs only, not things such as product categories.', 'woocommerce' ), esc_url( home_url( '/' ) ) ) ) );
- // Get shop page
- $shop_page_id = wc_get_page_id( 'shop' );
- $base_slug = urldecode( ( $shop_page_id > 0 && get_post( $shop_page_id ) ) ? get_page_uri( $shop_page_id ) : _x( 'shop', 'default-slug', 'woocommerce' ) );
- $product_base = _x( 'product', 'default-slug', 'woocommerce' );
+ $shop_page_id = wc_get_page_id( 'shop' );
+ $base_slug = urldecode( ( $shop_page_id > 0 && get_post( $shop_page_id ) ) ? get_page_uri( $shop_page_id ) : _x( 'shop', 'default-slug', 'woocommerce' ) );
+ $product_base = _x( 'product', 'default-slug', 'woocommerce' );
$structures = array(
0 => '',
@@ -115,28 +115,29 @@ class WC_Admin_Permalink_Settings {
-
+
/?product=sample-product//sample-product/
-
+
//sample-product/
-
+
//product-category/sample-product/
-
+
- must be set or WordPress will use default instead.', 'woocommerce' ); ?>
+
+
+
+
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+
+
+
+ ' . esc_html__( 'Read more about what we collect.', 'woocommerce' ) . '';
+ ?>
+
+
+
-
-
-
+
plugin_path() . '/i18n/locale-info.php';
+
+ if ( isset( $locale_info[ $country ] ) ) {
+ update_option( 'woocommerce_weight_unit', $locale_info[ $country ]['weight_unit'] );
+ update_option( 'woocommerce_dimension_unit', $locale_info[ $country ]['dimension_unit'] );
+
+ // Set currency formatting options based on chosen location and currency.
+ if ( $locale_info[ $country ]['currency_code'] === $currency_code ) {
+ update_option( 'woocommerce_currency_pos', $locale_info[ $country ]['currency_pos'] );
+ update_option( 'woocommerce_price_decimal_sep', $locale_info[ $country ]['decimal_sep'] );
+ update_option( 'woocommerce_price_num_decimals', $locale_info[ $country ]['num_decimals'] );
+ update_option( 'woocommerce_price_thousand_sep', $locale_info[ $country ]['thousand_sep'] );
+ }
+ }
+
+ if ( $tracking ) {
+ update_option( 'woocommerce_allow_tracking', 'yes' );
+ wp_schedule_single_event( time() + 10, 'woocommerce_tracker_send_event', array( true ) );
+ } else {
+ update_option( 'woocommerce_allow_tracking', 'no' );
+ }
+
WC_Install::create_pages();
- wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
+ wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
exit;
}
/**
- * Locale settings.
+ * Finishes replying to the client, but keeps the process running for further (async) code execution.
+ *
+ * @see https://core.trac.wordpress.org/ticket/41358 .
*/
- public function wc_setup_locale() {
- $user_location = WC_Geolocation::geolocate_ip();
- $country = ! empty( $user_location['country'] ) ? $user_location['country'] : 'US';
- $state = ! empty( $user_location['state'] ) ? $user_location['state'] : '*';
- $state = 'US' === $country && '*' === $state ? 'AL' : $state;
+ protected function close_http_connection() {
+ // Only 1 PHP process can access a session object at a time, close this so the next request isn't kept waiting.
+ // @codingStandardsIgnoreStart
+ if ( session_id() ) {
+ session_write_close();
+ }
+ // @codingStandardsIgnoreEnd
- // Defaults
- $currency = get_option( 'woocommerce_currency', 'GBP' );
- $currency_pos = get_option( 'woocommerce_currency_pos', 'left' );
- $decimal_sep = get_option( 'woocommerce_price_decimal_sep', '.' );
- $num_decimals = get_option( 'woocommerce_price_num_decimals', '2' );
- $thousand_sep = get_option( 'woocommerce_price_thousand_sep', ',' );
- $dimension_unit = get_option( 'woocommerce_dimension_unit', 'cm' );
- $weight_unit = get_option( 'woocommerce_weight_unit', 'kg' );
- ?>
-
-
- get_next_step_link() ) );
- exit;
- }
-
- /**
- * Shipping and taxes.
- */
- public function wc_setup_shipping_taxes() {
- ?>
-
-
- set_zone_order( 0 );
- $zone->add_location( $location['country'], 'country' );
- $zone->set_zone_name( $zone->get_formatted_location() );
- $zone->add_shipping_method( 'free_shipping' );
- $zone->save();
- }
+ // fastcgi_finish_request is the cleanest way to send the response and keep the script running, but not every server has it.
+ if ( is_callable( 'fastcgi_finish_request' ) ) {
+ fastcgi_finish_request();
} else {
- update_option( 'woocommerce_ship_to_countries', 'disabled' );
- }
-
- update_option( 'woocommerce_calc_taxes', $enable_taxes ? 'yes' : 'no' );
- update_option( 'woocommerce_prices_include_tax', sanitize_text_field( $_POST['woocommerce_prices_include_tax'] ) );
-
- if ( $enable_taxes ) {
- $locale_info = include( WC()->plugin_path() . '/i18n/locale-info.php' );
- $tax_rates = array();
- $country = WC()->countries->get_base_country();
- $state = WC()->countries->get_base_state();
-
- if ( isset( $locale_info[ $country ] ) ) {
- if ( isset( $locale_info[ $country ]['tax_rates'][ $state ] ) ) {
- $tax_rates = $locale_info[ $country ]['tax_rates'][ $state ];
- } elseif ( isset( $locale_info[ $country ]['tax_rates'][''] ) ) {
- $tax_rates = $locale_info[ $country ]['tax_rates'][''];
- }
- if ( isset( $locale_info[ $country ]['tax_rates']['*'] ) ) {
- $tax_rates = array_merge( $locale_info[ $country ]['tax_rates']['*'], $tax_rates );
- }
- }
- if ( $tax_rates ) {
- $loop = 0;
- foreach ( $tax_rates as $rate ) {
- $tax_rate = array(
- 'tax_rate_country' => $rate['country'],
- 'tax_rate_state' => $rate['state'],
- 'tax_rate' => $rate['rate'],
- 'tax_rate_name' => $rate['name'],
- 'tax_rate_priority' => isset( $rate['priority'] ) ? absint( $rate['priority'] ) : 1,
- 'tax_rate_compound' => 0,
- 'tax_rate_shipping' => $rate['shipping'] ? 1 : 0,
- 'tax_rate_order' => $loop ++,
- 'tax_rate_class' => '',
- );
- WC_Tax::_insert_tax_rate( $tax_rate );
- }
+ // Fallback: send headers and flush buffers.
+ if ( ! headers_sent() ) {
+ header( 'Connection: close' );
}
+ @ob_end_flush(); // @codingStandardsIgnoreLine.
+ flush();
}
-
- wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
- exit;
}
/**
- * Simple array of gateways to show in wizard.
+ * Function called after the HTTP request is finished, so it's executed without the client having to wait for it.
+ *
+ * @see WC_Admin_Setup_Wizard::install_plugin
+ * @see WC_Admin_Setup_Wizard::install_theme
+ */
+ public function run_deferred_actions() {
+ $this->close_http_connection();
+ foreach ( $this->deferred_actions as $action ) {
+ call_user_func_array( $action['func'], $action['args'] );
+
+ // Clear the background installation flag if this is a plugin.
+ if (
+ isset( $action['func'][1] ) &&
+ 'background_installer' === $action['func'][1] &&
+ isset( $action['args'][0] )
+ ) {
+ delete_option( 'woocommerce_setup_background_installing_' . $action['args'][0] );
+ }
+ }
+ }
+
+ /**
+ * Helper method to queue the background install of a plugin.
+ *
+ * @param string $plugin_id Plugin id used for background install.
+ * @param array $plugin_info Plugin info array containing name and repo-slug, and optionally file if different from [repo-slug].php.
+ */
+ protected function install_plugin( $plugin_id, $plugin_info ) {
+ // Make sure we don't trigger multiple simultaneous installs.
+ if ( get_option( 'woocommerce_setup_background_installing_' . $plugin_id ) ) {
+ return;
+ }
+
+ $plugin_file = isset( $plugin_info['file'] ) ? $plugin_info['file'] : $plugin_info['repo-slug'] . '.php';
+ if ( is_plugin_active( $plugin_info['repo-slug'] . '/' . $plugin_file ) ) {
+ return;
+ }
+
+ if ( empty( $this->deferred_actions ) ) {
+ add_action( 'shutdown', array( $this, 'run_deferred_actions' ) );
+ }
+
+ array_push(
+ $this->deferred_actions,
+ array(
+ 'func' => array( 'WC_Install', 'background_installer' ),
+ 'args' => array( $plugin_id, $plugin_info ),
+ )
+ );
+
+ // Set the background installation flag for this plugin.
+ update_option( 'woocommerce_setup_background_installing_' . $plugin_id, true );
+ }
+
+
+ /**
+ * Helper method to queue the background install of a theme.
+ *
+ * @param string $theme_id Theme id used for background install.
+ */
+ protected function install_theme( $theme_id ) {
+ if ( empty( $this->deferred_actions ) ) {
+ add_action( 'shutdown', array( $this, 'run_deferred_actions' ) );
+ }
+ array_push(
+ $this->deferred_actions,
+ array(
+ 'func' => array( 'WC_Install', 'theme_background_installer' ),
+ 'args' => array( $theme_id ),
+ )
+ );
+ }
+
+ /**
+ * Helper method to install Jetpack.
+ */
+ protected function install_jetpack() {
+ $this->install_plugin(
+ 'jetpack',
+ array(
+ 'name' => __( 'Jetpack', 'woocommerce' ),
+ 'repo-slug' => 'jetpack',
+ )
+ );
+ }
+
+ /**
+ * Helper method to install WooCommerce Services and its Jetpack dependency.
+ */
+ protected function install_woocommerce_services() {
+ $this->install_jetpack();
+ $this->install_plugin(
+ 'woocommerce-services',
+ array(
+ 'name' => __( 'WooCommerce Services', 'woocommerce' ),
+ 'repo-slug' => 'woocommerce-services',
+ )
+ );
+ }
+
+ /**
+ * Retrieve info for missing WooCommerce Services and/or Jetpack plugin.
+ *
* @return array
*/
- protected function get_wizard_payment_gateways() {
- $gateways = array(
- 'paypal-braintree' => array(
- 'name' => __( 'PayPal by Braintree', 'woocommerce' ),
- 'image' => WC()->plugin_url() . '/assets/images/paypal-braintree.png',
- 'description' => __( "Safe and secure payments using credit cards or your customer's PayPal account.", 'woocommerce' ) . ' ' . __( 'Learn more about PayPal', 'woocommerce' ) . '',
- 'class' => 'featured featured-row-last',
- 'repo-slug' => 'woocommerce-gateway-paypal-powered-by-braintree',
- ),
- 'paypal-ec' => array(
- 'name' => __( 'PayPal Express Checkout', 'woocommerce' ),
- 'image' => WC()->plugin_url() . '/assets/images/paypal.png',
- 'description' => __( "Safe and secure payments using credit cards or your customer's PayPal account.", 'woocommerce' ) . ' ' . __( 'Learn more about PayPal', 'woocommerce' ) . '',
- 'class' => 'featured featured-row-last',
- 'repo-slug' => 'woocommerce-gateway-paypal-express-checkout',
- ),
- 'stripe' => array(
- 'name' => __( 'Stripe', 'woocommerce' ),
- 'image' => WC()->plugin_url() . '/assets/images/stripe.png',
- 'description' => sprintf( __( 'A modern and robust way to accept credit card payments on your store. Learn more about Stripe.', 'woocommerce' ), 'https://wordpress.org/plugins/woocommerce-gateway-stripe/' ),
- 'class' => 'featured featured-row-first',
- 'repo-slug' => 'woocommerce-gateway-stripe',
- ),
- 'paypal' => array(
- 'name' => __( 'PayPal Standard', 'woocommerce' ),
- 'description' => __( 'Accept payments via PayPal using account balance or credit card.', 'woocommerce' ),
- 'image' => '',
- 'class' => '',
+ protected function get_wcs_requisite_plugins() {
+ $plugins = array();
+ if ( ! is_plugin_active( 'woocommerce-services/woocommerce-services.php' ) && ! get_option( 'woocommerce_setup_background_installing_woocommerce-services' ) ) {
+ $plugins[] = array(
+ 'name' => __( 'WooCommerce Services', 'woocommerce' ),
+ 'slug' => 'woocommerce-services',
+ );
+ }
+ if ( ! is_plugin_active( 'jetpack/jetpack.php' ) && ! get_option( 'woocommerce_setup_background_installing_jetpack' ) ) {
+ $plugins[] = array(
+ 'name' => __( 'Jetpack', 'woocommerce' ),
+ 'slug' => 'jetpack',
+ );
+ }
+ return $plugins;
+ }
+
+ /**
+ * Plugin install info message markup with heading.
+ */
+ public function plugin_install_info() {
+ ?>
+
+
+
+
+ array(
+ 'name' => __( 'Flat Rate', 'woocommerce' ),
+ 'description' => __( 'Set a fixed price to cover shipping costs.', 'woocommerce' ),
'settings' => array(
- 'email' => array(
- 'label' => __( 'PayPal email address', 'woocommerce' ),
- 'type' => 'email',
- 'value' => get_option( 'admin_email' ),
- 'placeholder' => __( 'PayPal email address', 'woocommerce' ),
+ 'cost' => array(
+ 'type' => 'text',
+ 'default_value' => __( 'Cost', 'woocommerce' ),
+ 'description' => __( 'What would you like to charge for flat rate shipping?', 'woocommerce' ),
+ 'required' => true,
),
),
),
+ 'free_shipping' => array(
+ 'name' => __( 'Free Shipping', 'woocommerce' ),
+ 'description' => __( "Don't charge for shipping.", 'woocommerce' ),
+ ),
+ );
+
+ return $shipping_methods;
+ }
+
+ /**
+ * Render the available shipping methods for a given country code.
+ *
+ * @param string $country_code Country code.
+ * @param string $currency_code Currency code.
+ * @param string $input_prefix Input prefix.
+ */
+ protected function shipping_method_selection_form( $country_code, $currency_code, $input_prefix ) {
+ $selected = 'flat_rate';
+ $shipping_methods = $this->get_wizard_shipping_methods( $country_code, $currency_code );
+ ?>
+
+
+
+
+
+ $method ) : ?>
+
+
+
+
+
+
+
+
+ $method ) : ?>
+
+
+ $setting ) : ?>
+
+
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ countries->get_base_country();
+ $country_name = WC()->countries->countries[ $country_code ];
+ $prefixed_country_name = WC()->countries->estimated_for_prefix( $country_code ) . $country_name;
+ $currency_code = get_woocommerce_currency();
+ $existing_zones = WC_Shipping_Zones::get_zones();
+ $intro_text = '';
+
+ if ( empty( $existing_zones ) ) {
+ $intro_text = sprintf(
+ /* translators: %s: country name including the 'the' prefix if needed */
+ __( "We've created two Shipping Zones - for %s and for the rest of the world. Below you can set Flat Rate shipping costs for these Zones or offer Free Shipping.", 'woocommerce' ),
+ $prefixed_country_name
+ );
+ }
+
+ $is_wcs_labels_supported = $this->is_wcs_shipping_labels_supported_country( $country_code );
+ $is_shipstation_supported = $this->is_shipstation_supported_country( $country_code );
+
+ ?>
+
+
+
+
+
+ install_woocommerce_services();
+ }
+
+ if ( $setup_shipstation ) {
+ $this->install_plugin(
+ 'woocommerce-shipstation-integration',
+ array(
+ 'name' => __( 'ShipStation', 'woocommerce' ),
+ 'repo-slug' => 'woocommerce-shipstation-integration',
+ 'file' => 'woocommerce-shipstation.php',
+ )
+ );
+ }
+
+ // For now, limit this setup to the first run.
+ if ( ! empty( $existing_zones ) ) {
+ wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
+ exit;
+ }
+
+ /*
+ * If enabled, create a shipping zone containing the country the
+ * store is located in, with the selected method preconfigured.
+ */
+ if ( $setup_domestic ) {
+ $country = WC()->countries->get_base_country();
+
+ $zone = new WC_Shipping_Zone( null );
+ $zone->set_zone_order( 0 );
+ $zone->add_location( $country, 'country' );
+ $instance_id = $zone->add_shipping_method( $domestic_method );
+ $zone->save();
+
+ // Save chosen shipping method settings (using REST controller for convenience).
+ if ( isset( $instance_id ) && ! empty( $_POST['shipping_zones']['domestic'][ $domestic_method ] ) ) { // WPCS: input var ok.
+ $method_controller = new WC_REST_Shipping_Zone_Methods_Controller();
+ // @codingStandardsIgnoreStart
+ $method_controller->update_item( array(
+ 'zone_id' => $zone->get_id(),
+ 'instance_id' => $instance_id,
+ 'settings' => wp_unslash( $_POST['shipping_zones']['domestic'][ $domestic_method ] ),
+ ) );
+ // @codingStandardsIgnoreEnd
+ }
+ }
+
+ // If enabled, set the selected method for the "rest of world" zone.
+ if ( $setup_intl ) {
+ $zone = new WC_Shipping_Zone( 0 );
+ $instance_id = $zone->add_shipping_method( $intl_method );
+
+ $zone->save();
+
+ // Save chosen shipping method settings (using REST controller for convenience).
+ if ( isset( $instance_id ) && ! empty( $_POST['shipping_zones']['intl'][ $intl_method ] ) ) { // WPCS: input var ok.
+ $method_controller = new WC_REST_Shipping_Zone_Methods_Controller();
+ // @codingStandardsIgnoreStart
+ $method_controller->update_item( array(
+ 'zone_id' => $zone->get_id(),
+ 'instance_id' => $instance_id,
+ 'settings' => wp_unslash( $_POST['shipping_zones']['intl'][ $intl_method ] ),
+ ) );
+ // @codingStandardsIgnoreEnd
+ }
+ }
+
+ // Notify the user that no shipping methods are configured.
+ if ( ! $setup_domestic && ! $setup_intl ) {
+ WC_Admin_Notices::add_notice( 'no_shipping_methods' );
+ }
+
+ wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
+ exit;
+ }
+
+ /**
+ * Is Stripe country supported
+ * https://stripe.com/global .
+ *
+ * @param string $country_code Country code.
+ */
+ protected function is_stripe_supported_country( $country_code ) {
+ $stripe_supported_countries = array(
+ 'AU',
+ 'AT',
+ 'BE',
+ 'CA',
+ 'DK',
+ 'FI',
+ 'FR',
+ 'DE',
+ 'HK',
+ 'IE',
+ 'JP',
+ 'LU',
+ 'NL',
+ 'NZ',
+ 'NO',
+ 'SG',
+ 'ES',
+ 'SE',
+ 'CH',
+ 'GB',
+ 'US',
+ );
+
+ return in_array( $country_code, $stripe_supported_countries, true );
+ }
+
+ /**
+ * Is PayPal currency supported.
+ *
+ * @param string $currency Currency code.
+ * @return boolean
+ */
+ protected function is_paypal_supported_currency( $currency ) {
+ $supported_currencies = array(
+ 'AUD',
+ 'BRL',
+ 'CAD',
+ 'MXN',
+ 'NZD',
+ 'HKD',
+ 'SGD',
+ 'USD',
+ 'EUR',
+ 'JPY',
+ 'TRY',
+ 'NOK',
+ 'CZK',
+ 'DKK',
+ 'HUF',
+ 'ILS',
+ 'MYR',
+ 'PHP',
+ 'PLN',
+ 'SEK',
+ 'CHF',
+ 'TWD',
+ 'THB',
+ 'GBP',
+ 'RMB',
+ 'RUB',
+ 'INR',
+ );
+ return in_array( $currency, $supported_currencies, true );
+ }
+
+ /**
+ * Is Klarna Checkout country supported.
+ *
+ * @param string $country_code Country code.
+ */
+ protected function is_klarna_checkout_supported_country( $country_code ) {
+ $supported_countries = array(
+ 'SE', // Sweden.
+ 'FI', // Finland.
+ 'NO', // Norway.
+ 'NL', // Netherlands.
+ );
+ return in_array( $country_code, $supported_countries, true );
+ }
+
+ /**
+ * Is Klarna Payments country supported.
+ *
+ * @param string $country_code Country code.
+ */
+ protected function is_klarna_payments_supported_country( $country_code ) {
+ $supported_countries = array(
+ 'DK', // Denmark.
+ 'DE', // Germany.
+ 'AT', // Austria.
+ );
+ return in_array( $country_code, $supported_countries, true );
+ }
+
+ /**
+ * Is Square country supported
+ *
+ * @param string $country_code Country code.
+ */
+ protected function is_square_supported_country( $country_code ) {
+ $square_supported_countries = array(
+ 'US',
+ 'CA',
+ 'JP',
+ 'GB',
+ 'AU',
+ );
+ return in_array( $country_code, $square_supported_countries, true );
+ }
+
+ /**
+ * Is eWAY Payments country supported
+ *
+ * @param string $country_code Country code.
+ */
+ protected function is_eway_payments_supported_country( $country_code ) {
+ $supported_countries = array(
+ 'AU', // Australia.
+ 'NZ', // New Zealand.
+ );
+ return in_array( $country_code, $supported_countries, true );
+ }
+
+ /**
+ * Is ShipStation country supported
+ *
+ * @param string $country_code Country code.
+ */
+ protected function is_shipstation_supported_country( $country_code ) {
+ $supported_countries = array(
+ 'AU', // Australia.
+ 'CA', // Canada.
+ 'GB', // United Kingdom.
+ );
+ return in_array( $country_code, $supported_countries, true );
+ }
+
+ /**
+ * Is WooCommerce Services shipping label country supported
+ *
+ * @param string $country_code Country code.
+ */
+ protected function is_wcs_shipping_labels_supported_country( $country_code ) {
+ $supported_countries = array(
+ 'US', // United States.
+ );
+ return in_array( $country_code, $supported_countries, true );
+ }
+
+ /**
+ * Helper method to retrieve the current user's email address.
+ *
+ * @return string Email address
+ */
+ protected function get_current_user_email() {
+ $current_user = wp_get_current_user();
+ $user_email = $current_user->user_email;
+
+ return $user_email;
+ }
+
+ /**
+ * Array of all possible "in cart" gateways that can be offered.
+ *
+ * @return array
+ */
+ protected function get_wizard_available_in_cart_payment_gateways() {
+ $user_email = $this->get_current_user_email();
+
+ $stripe_description = '
' . sprintf(
+ /* translators: %s: URL */
+ __( 'Accept debit and credit cards in 135+ currencies, methods such as Alipay, and one-touch checkout with Apple Pay. Learn more.', 'woocommerce' ),
+ 'https://woocommerce.com/products/stripe/'
+ ) . '
';
+ $paypal_checkout_description = '
' . sprintf(
+ /* translators: %s: URL */
+ __( 'Safe and secure payments using credit cards or your customer\'s PayPal account. Learn more.', 'woocommerce' ),
+ 'https://woocommerce.com/products/woocommerce-gateway-paypal-checkout/'
+ ) . '
';
+ $klarna_checkout_description = '
' . sprintf(
+ /* translators: %s: URL */
+ __( 'Full checkout experience with pay now, pay later and slice it. No credit card numbers, no passwords, no worries. Learn more about Klarna.', 'woocommerce' ),
+ 'https://woocommerce.com/products/klarna-checkout/'
+ ) . '
';
+ $klarna_payments_description = '
' . sprintf(
+ /* translators: %s: URL */
+ __( 'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries. Learn more about Klarna.', 'woocommerce' ),
+ 'https://woocommerce.com/products/klarna-payments/ '
+ ) . '
';
+ $square_description = '
' . sprintf(
+ /* translators: %s: URL */
+ __( 'Securely accept credit and debit cards with one low rate, no surprise fees (custom rates available). Sell online and in store and track sales and inventory in one place. Learn more about Square.', 'woocommerce' ),
+ 'https://woocommerce.com/products/square/'
+ ) . '
should_show_theme()
+ && $this->should_show_automated_tax()
+ && $this->should_show_mailchimp()
+ ) :
+ esc_html_e( 'Select from the list below to enable automated taxes and MailChimp’s best-in-class email services — and design your store with our official, free WooCommerce theme.', 'woocommerce' );
+ else :
+ esc_html_e( 'Enhance your store with these recommended features.', 'woocommerce' );
+ endif;
+ ?>
+
+ install_theme( 'storefront' );
+ }
+
+ if ( $setup_automated_tax ) {
+ $this->install_woocommerce_services();
+ }
+
+ if ( $setup_mailchimp ) {
+ // Prevent MailChimp from redirecting to its settings page during the OBW flow.
+ add_option( 'mailchimp_woocommerce_plugin_do_activation_redirect', false );
+
+ $this->install_plugin(
+ 'mailchimp-for-woocommerce',
+ array(
+ 'name' => __( 'MailChimp for WooCommerce', 'woocommerce' ),
+ 'repo-slug' => 'mailchimp-for-woocommerce',
+ 'file' => 'mailchimp-woocommerce.php',
+ )
+ );
}
wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
@@ -763,58 +1967,359 @@ class WC_Admin_Setup_Wizard {
}
/**
- * Actions on the final step.
+ * Go to the next step if Jetpack was connected.
*/
- private function wc_setup_ready_actions() {
- WC_Admin_Notices::remove_notice( 'install' );
-
- if ( isset( $_GET['wc_tracker_optin'] ) && isset( $_GET['wc_tracker_nonce'] ) && wp_verify_nonce( $_GET['wc_tracker_nonce'], 'wc_tracker_optin' ) ) {
- update_option( 'woocommerce_allow_tracking', 'yes' );
- WC_Tracker::send_tracking_data( true );
-
- } elseif ( isset( $_GET['wc_tracker_optout'] ) && isset( $_GET['wc_tracker_nonce'] ) && wp_verify_nonce( $_GET['wc_tracker_nonce'], 'wc_tracker_optout' ) ) {
- update_option( 'woocommerce_allow_tracking', 'no' );
+ protected function wc_setup_activate_actions() {
+ if (
+ isset( $_GET['from'] ) &&
+ 'wpcom' === $_GET['from'] &&
+ class_exists( 'Jetpack' ) &&
+ Jetpack::is_active()
+ ) {
+ wp_redirect( esc_url_raw( remove_query_arg( 'from', $this->get_next_step_link() ) ) );
+ exit;
}
}
+ protected function wc_setup_activate_get_feature_list() {
+ $features = array();
+
+ $stripe_settings = get_option( 'woocommerce_stripe_settings', false );
+ $stripe_enabled = is_array( $stripe_settings )
+ && isset( $stripe_settings['create_account'] ) && 'yes' === $stripe_settings['create_account']
+ && isset( $stripe_settings['enabled'] ) && 'yes' === $stripe_settings['enabled'];
+ $ppec_settings = get_option( 'woocommerce_ppec_paypal_settings', false );
+ $ppec_enabled = is_array( $ppec_settings )
+ && isset( $ppec_settings['reroute_requests'] ) && 'yes' === $ppec_settings['reroute_requests']
+ && isset( $ppec_settings['enabled'] ) && 'yes' === $ppec_settings['enabled'];
+
+ $features['payment'] = $stripe_enabled || $ppec_enabled;
+ $features['taxes'] = (bool) get_option( 'woocommerce_setup_automated_taxes', false );
+ $features['labels'] = (bool) get_option( 'woocommerce_setup_shipping_labels', false );
+
+ return $features;
+ }
+
+ protected function wc_setup_activate_get_feature_list_str() {
+ $features = $this->wc_setup_activate_get_feature_list();
+ if ( $features['payment'] && $features['taxes'] && $features['labels'] ) {
+ return __( 'payment setup, automated taxes and discounted shipping labels', 'woocommerce' );
+ } else if ( $features['payment'] && $features['taxes'] ) {
+ return __( 'payment setup and automated taxes', 'woocommerce' );
+ } else if ( $features['payment'] && $features['labels'] ) {
+ return __( 'payment setup and discounted shipping labels', 'woocommerce' );
+ } else if ( $features['payment'] ) {
+ return __( 'payment setup', 'woocommerce' );
+ } else if ( $features['taxes'] && $features['labels'] ) {
+ return __( 'automated taxes and discounted shipping labels', 'woocommerce' );
+ } else if ( $features['taxes'] ) {
+ return __( 'automated taxes', 'woocommerce' );
+ } else if ( $features['labels'] ) {
+ return __( 'discounted shipping labels', 'woocommerce' );
+ }
+ return false;
+ }
+
+ /**
+ * Activate step.
+ */
+ public function wc_setup_activate() {
+ $this->wc_setup_activate_actions();
+
+ $jetpack_connected = class_exists( 'Jetpack' ) && Jetpack::is_active();
+
+ $has_jetpack_error = false;
+ if ( isset( $_GET['activate_error'] ) ) {
+ $has_jetpack_error = true;
+
+ $title = __( "Sorry, we couldn't connect your store to Jetpack", 'woocommerce' );
+
+ $error_message = $this->get_activate_error_message( sanitize_text_field( wp_unslash( $_GET['activate_error'] ) ) );
+ $description = $error_message;
+ } else {
+ $feature_list = $this->wc_setup_activate_get_feature_list_str();
+
+ $description = false;
+
+ if ( $feature_list ) {
+ if ( ! $jetpack_connected ) {
+ /* translators: %s: list of features, potentially comma separated */
+ $description_base = __( 'Your store is almost ready! To activate services like %s, just connect with Jetpack.', 'woocommerce' );
+ } else {
+ $description_base = __( 'Thanks for using Jetpack! Your store is almost ready: to activate services like %s, just connect your store.', 'woocommerce' );
+ }
+ $description = sprintf( $description_base, $feature_list );
+ }
+
+ if ( ! $jetpack_connected ) {
+ $title = $feature_list ?
+ __( 'Connect your store to Jetpack', 'woocommerce' ) :
+ __( 'Connect your store to Jetpack to enable extra features', 'woocommerce' );
+ $button_text = __( 'Continue with Jetpack', 'woocommerce' );
+ } elseif ( $feature_list ) {
+ $title = __( 'Connect your store to activate WooCommerce Services', 'woocommerce' );
+ $button_text = __( 'Continue with WooCommerce Services', 'woocommerce' );
+ } else {
+ wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
+ exit;
+ }
+ }
+ ?>
+
+
+
+
+
+ Terms of Service and to share details with WordPress.com', 'woocommerce' ) ),
+ 'https://wordpress.com/tos',
+ 'https://jetpack.com/support/what-data-does-jetpack-sync'
+ );
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ __( "Sorry! We tried, but we couldn't connect Jetpack just now 😭. Please go to the Plugins tab to connect Jetpack, so that you can finish setting up your store.", 'woocommerce' ),
+ 'jetpack_cant_be_installed' => __( "Sorry! We tried, but we couldn't install Jetpack for you 😭. Please go to the Plugins tab to install it, and finish setting up your store.", 'woocommerce' ),
+ 'register_http_request_failed' => __( "Sorry! We couldn't contact Jetpack just now 😭. Please make sure that your site is visible over the internet, and that it accepts incoming and outgoing requests via curl. You can also try to connect to Jetpack again, and if you run into any more issues, please contact support.", 'woocommerce' ),
+ 'siteurl_private_ip_dev' => __( "Your site might be on a private network. Jetpack can only connect to public sites. Please make sure your site is visible over the internet, and then try connecting again 🙏." , 'woocommerce' ),
+ );
+ }
+
+ protected function get_activate_error_message( $code = '' ) {
+ $errors = $this->get_all_activate_errors();
+ return array_key_exists( $code, $errors ) ? $errors[ $code ] : $errors['default'];
+ }
+
+ /**
+ * Activate step save.
+ *
+ * Install, activate, and launch connection flow for Jetpack.
+ */
+ public function wc_setup_activate_save() {
+ check_admin_referer( 'wc-setup' );
+
+ set_transient( 'wc_setup_activated', 'yes', MINUTE_IN_SECONDS * 10 );
+
+ // Leave a note for WooCommerce Services that Jetpack has been opted into.
+ update_option( 'woocommerce_setup_jetpack_opted_in', true );
+
+ if ( class_exists( 'Jetpack' ) && Jetpack::is_active() ) {
+ wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
+ exit;
+ }
+
+ WC_Install::background_installer( 'jetpack', array(
+ 'name' => __( 'Jetpack', 'woocommerce' ),
+ 'repo-slug' => 'jetpack',
+ ) );
+
+ // Did Jetpack get successfully installed?
+ if ( ! class_exists( 'Jetpack' ) ) {
+ wp_redirect( esc_url_raw( add_query_arg( 'activate_error', 'jetpack_cant_be_installed' ) ) );
+ exit;
+ }
+
+ Jetpack::maybe_set_version_option();
+ $register_result = Jetpack::try_registration();
+
+ if ( is_wp_error( $register_result ) ) {
+ $result_error_code = $register_result->get_error_code();
+ $jetpack_error_code = array_key_exists( $result_error_code, $this->get_all_activate_errors() ) ? $result_error_code : 'register';
+ wp_redirect( esc_url_raw( add_query_arg( 'activate_error', $jetpack_error_code ) ) );
+ exit;
+ }
+
+ $redirect_url = esc_url_raw( add_query_arg( array(
+ 'page' => 'wc-setup',
+ 'step' => 'activate',
+ 'from' => 'wpcom',
+ 'activate_error' => false,
+ ), admin_url() ) );
+ $connection_url = Jetpack::init()->build_connect_url( true, $redirect_url, 'woocommerce-setup-wizard' );
+
+ wp_redirect( esc_url_raw( $connection_url ) );
+ exit;
+ }
+
/**
* Final step.
*/
public function wc_setup_ready() {
- $this->wc_setup_ready_actions();
- shuffle( $this->tweets );
+ // We've made it! Don't prompt the user to run the wizard again.
+ WC_Admin_Notices::remove_notice( 'install' );
+
+ $user_email = $this->get_current_user_email();
+ $videos_url = 'https://docs.woocommerce.com/document/woocommerce-guided-tour-videos/?utm_source=setupwizard&utm_medium=product&utm_content=videos&utm_campaign=woocommerceplugin';
+ $docs_url = 'https://docs.woocommerce.com/documentation/plugins/woocommerce/getting-started/?utm_source=setupwizard&utm_medium=product&utm_content=docs&utm_campaign=woocommerceplugin';
+ $help_text = sprintf(
+ /* translators: %1$s: link to videos, %2$s: link to docs */
+ __( 'Watch our guided tour videos to learn more about WooCommerce, and visit WooCommerce.com to learn more about getting started.', 'woocommerce' ),
+ $videos_url,
+ $docs_url
+ );
?>
- Tweet
-
+
-
-
-
-
@@ -237,9 +255,9 @@ class WC_Admin_Taxonomies {
// Create the media frame.
file_frame = wp.media.frames.downloadable_file = wp.media({
- title: '',
+ title: '',
button: {
- text: ''
+ text: ''
},
multiple: false
});
@@ -275,8 +293,8 @@ class WC_Admin_Taxonomies {
/**
* save_category_fields function.
*
- * @param mixed $term_id Term ID being saved
- * @param mixed $tt_id
+ * @param mixed $term_id Term ID being saved
+ * @param mixed $tt_id
* @param string $taxonomy
*/
public function save_category_fields( $term_id, $tt_id = '', $taxonomy = '' ) {
@@ -295,6 +313,29 @@ class WC_Admin_Taxonomies {
echo wpautop( __( 'Product categories for your store can be managed here. To change the order of categories on the front-end you can drag and drop to sort them. To see more categories listed click the "screen options" link at the top-right of this page.', 'woocommerce' ) );
}
+ /**
+ * Add some notes to describe the behavior of the default category.
+ */
+ public function product_cat_notes() {
+ $category_id = get_option( 'default_product_cat', 0 );
+ $category = get_term( $category_id, 'product_cat' );
+ $category_name = ( ! $category || is_wp_error( $category ) ) ? _x( 'Uncategorized', 'Default category slug', 'woocommerce' ) : $category->name;
+ ?>
+
';
@@ -178,7 +188,7 @@ class WC_Tax_Rate_Importer extends WP_Importer {
* Performs post-import cleanup of files and the cache.
*/
public function import_end() {
- echo '
';
}
/**
@@ -230,56 +242,61 @@ class WC_Tax_Rate_Importer extends WP_Importer {
public function greet() {
echo '
';
- echo '
' . __( 'Hi there! Upload a CSV file containing tax rates to import the contents into your shop. Choose a .csv file to upload, then click "Upload file and import".', 'woocommerce' ) . '
';
+ echo '
' . esc_html__( 'Hi there! Upload a CSV file containing tax rates to import the contents into your shop. Choose a .csv file to upload, then click "Upload file and import".', 'woocommerce' ) . '
';
- echo '
' . sprintf( __( 'Tax rates need to be defined with columns in a specific order (10 columns). Click here to download a sample.', 'woocommerce' ), WC()->plugin_url() . '/dummy-data/sample_tax_rates.csv' ) . '
';
+ /* translators: 1: Link to tax rates sample file 2: Closing link. */
+ echo '
' . sprintf( esc_html__( 'Your CSV needs to include columns in a specific order. %1$sClick here to download a sample%2$s.', 'woocommerce' ), '', '' ) . '