From 3bac3089cbab8f91daa01a0d63802c1570590027 Mon Sep 17 00:00:00 2001
From: 10upbot on GitHub <10upbot+github@10up.com>
Date: Wed, 4 Mar 2020 18:18:21 +0000
Subject: [PATCH] Committing built version of
1b2d4f581af587335031cf8de70471ade562a81c
---
README.md | 64 +++-
assets/img/menu-icon.svg | 3 +
classifai.php | 13 +-
composer.json | 14 +-
config.php | 2 +-
dist/js/admin.min.js | 1 +
dist/js/media.min.js | 1 +
includes/Classifai/Admin/BulkActions.php | 132 +++++++
includes/Classifai/Admin/Notifications.php | 2 +-
includes/Classifai/Admin/SavePostHandler.php | 15 +-
.../Classifai/Command/ClassifaiCommand.php | 121 +++++++
.../Classifai/Command/RSSImporterCommand.php | 2 +-
includes/Classifai/Helpers.php | 71 +++-
includes/Classifai/Plugin.php | 6 +-
.../Providers/Azure/ComputerVision.php | 252 ++++++++++---
.../Providers/Azure/SmartCropping.php | 339 ++++++++++++++++++
includes/Classifai/Providers/Provider.php | 13 +
includes/Classifai/Providers/Watson/NLU.php | 141 ++++++--
.../Classifai/Services/ImageProcessing.php | 91 +++++
.../Classifai/Services/ServicesManager.php | 3 +-
.../Classifai/Taxonomy/TaxonomyFactory.php | 2 +-
includes/Classifai/Watson/Classifier.php | 3 +-
languages/classifai.pot | 200 ++++++++---
wpacceptance.json | 16 +
24 files changed, 1332 insertions(+), 175 deletions(-)
create mode 100644 assets/img/menu-icon.svg
create mode 100644 dist/js/admin.min.js
create mode 100644 dist/js/media.min.js
create mode 100644 includes/Classifai/Admin/BulkActions.php
create mode 100644 includes/Classifai/Providers/Azure/SmartCropping.php
create mode 100644 wpacceptance.json
diff --git a/README.md b/README.md
index 91587a099..81c344674 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,15 @@
# ![ClassifAI](https://classifaiplugin.com/wp-content/themes/classifai-theme/assets/img/logo.svg "ClassifAI")
> Enhance your WordPress content with Artificial Intelligence and Machine Learning services.
-[![Support Level](https://img.shields.io/badge/support-active-green.svg)](#support-level) [![Build Status](https://travis-ci.com/10up/classifai.svg?token=Jy6DFK4YVZbgtyNHcjm5&branch=develop)](https://travis-ci.com/10up/classifai) [![Release Version](https://img.shields.io/github/release/10up/classifai.svg)](https://github.com/10up/classifai/releases/latest) ![WordPress tested up to version](https://img.shields.io/badge/WordPress-v5.2%20tested-success.svg) [![GPLv2 License](https://img.shields.io/github/license/10up/classifai.svg)](https://github.com/10up/classifai/blob/develop/LICENSE.md)
+[![Support Level](https://img.shields.io/badge/support-active-green.svg)](#support-level) [![Build Status](https://travis-ci.com/10up/classifai.svg?token=Jy6DFK4YVZbgtyNHcjm5&branch=develop)](https://travis-ci.com/10up/classifai) [![Release Version](https://img.shields.io/github/release/10up/classifai.svg)](https://github.com/10up/classifai/releases/latest) ![WordPress tested up to version](https://img.shields.io/badge/WordPress-v5.3%20tested-success.svg) [![GPLv2 License](https://img.shields.io/github/license/10up/classifai.svg)](https://github.com/10up/classifai/blob/develop/LICENSE.md)
## Table of Contents
* [Features](#features)
* [Requirements](#requirements)
+* [Pricing](#pricing)
* [Installation](#installation)
-* [Set Up Content Tagging](#set-up-content-tagging-via-ibm-watson)
+* [Register ClassifAI account](#register-classifai-account)
+* [Set Up Language Processing](#set-up-language-processing-via-ibm-watson)
* [Set Up Image Processing](#set-up-image-processing-via-microsoft-azure)
* [WP CLI Usage Instructions](#wp-cli-usage-instructions)
* [Data Gathering](#data-gathering)
@@ -20,15 +22,25 @@
* Classify your content using [IBM Watson's Natural Language Understanding API](https://www.ibm.com/watson/services/natural-language-understanding/) and [Microsoft Azure's Computer Vision API](https://azure.microsoft.com/en-us/services/cognitive-services/computer-vision/)
* Supports Watson's [Categories](https://console.bluemix.net/docs/services/natural-language-understanding/index.html#categories), [Keywords](https://console.bluemix.net/docs/services/natural-language-understanding/index.html#keywords), [Concepts](https://console.bluemix.net/docs/services/natural-language-understanding/index.html#concepts) & [Entities](https://console.bluemix.net/docs/services/natural-language-understanding/index.html#entities) and Azure's [Describe Image](https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fe)
* Automatically classify content and images on save
+* Manually generate alt text and image tags for images
+* [Smartly crop images](https://docs.microsoft.com/en-us/rest/api/cognitiveservices/computervision/generatethumbnail) around a region of interest identified by Computer Vision
* Bulk classify content with [WP-CLI](https://wp-cli.org/)
## Requirements
* PHP 7.0+
* [WordPress](http://wordpress.org) 5.0+
-* To utilize the Lanaguage Processing functionality, you will need an active [IBM Watson](https://cloud.ibm.com/registration) account.
+* To utilize the Language Processing functionality, you will need an active [IBM Watson](https://cloud.ibm.com/registration) account.
* To utilize the Image Processing functionality, you will need an active [Microsoft Azure](https://signup.azure.com/signup) account.
+## Pricing
+
+Note that there is no cost to using ClassifAI and that both IBM Watson and Microsoft Azure have free plans for their AI services, but that above those free plans there are paid levels as well. So if you expect to process a high volume of content, then you'll want to review the pricing plans for these services to understand if you'll incur any costs. For the most part, both services' free plans are quite generous and should at least allow for testing ClassifAI to better understand its featureset and could at best allow for totally free usage.
+
+The service that powers ClassifAI's Language Processing, IBM Watson's Natural Language Understanding ("NLU"), has a ["lite" pricing tier](https://www.ibm.com/cloud/watson-natural-language-understanding/pricing) that offers 30,000 free NLU items per month.
+
+The service that powers ClassifAI's Image Processing, Microsoft Azure's Computer Vision, has a ["free" pricing tier](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/computer-vision/) that offers 20 transactions per minute and 5,000 transactions per month.
+
## Installation
#### 1. Download or Clone this repo, install dependencies and build.
@@ -37,7 +49,20 @@
#### 2. Activate Plugin
-## Set Up Content Tagging (via IBM Watson)
+## Register ClassifAI account
+
+ClassifAI is a sophisticated solution that we want organizations of all shapes and sizes to count on. To keep adopters apprised of major updates and beta testing opportunities, gather feedback, and prioritize common use cases, we're asking for a little bit of information in exchange for a free key. Your information will be kept confidential.
+
+#### 1. Register for a ClassifAI account
+- Register for a free ClassifAI account [here](https://classifaiplugin.com/#cta).
+- Check for an email from `ClassifAI Team` which contains the registration key.
+- Note that the email will be sent from `opensource@10up.com`, so please whitelist this email address if needed.
+
+#### 2. Configure ClassifAI API Keys under admin area > ClassifAI
+- In the `Registered Email` field, enter the email you used for registration.
+- In the `Registration Key` field, enter the registration key from the email in step 1 above.
+
+## Set Up Language Processing (via IBM Watson)
#### 1. Sign up for Watson services
- [Register for an IBM Cloud account](https://cloud.ibm.com/registration) or sign into your existing one.
@@ -51,7 +76,6 @@
##### If your credentials contain an API Key, then:
- In the `API URL` field enter the URL
-- In the `API User` field, enter `apikey`.
- Enter your API Key in the `API Key` field.
##### If your credentials contain a username and password, then:
@@ -61,20 +85,18 @@
#### 3. Configure Post Types to classify and IBM Watson Features to enable under ClassifAI > Language Processing
- Choose which public post types to classify when saved.
-- Chose whether to assign category, keyword, entity, and concept as well as the taxonomies used for each.
+- Choose whether to assign category, keyword, entity, and concept as well as the taxonomies used for each.
#### 4. Save Post or run WP CLI command to batch classify posts
## Set Up Image Processing (via Microsoft Azure)
-Note that [Computer Vision](https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home#image-requirements) can analyze images that meet the following requirements:
+Note that [Computer Vision](https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home#image-requirements) can analyze and crop images that meet the following requirements:
- The image must be presented in JPEG, PNG, GIF, or BMP format
- The file size of the image must be less than 4 megabytes (MB)
- The dimensions of the image must be greater than 50 x 50 pixels
- The file must be externally accessible via URL (i.e. local sites and setups that block direct file access will not work out of the box)
-Note that Computer Vision has a [free pricing tier](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/computer-vision/) that offers 20 transactions per minute and 5,000 transactions per month.
-
#### 1. Sign up for Azure services
- [Register for a Microsoft Azure account](https://azure.microsoft.com/en-us/free/) or sign into your existing one.
- Log into your account and create a new [*Computer Vision*](https://portal.azure.com/#blade/Microsoft_Azure_Marketplace/GalleryFeaturedMenuItemBlade/selectedMenuItemId/CognitiveServices_MP/dontDiscardJourney/true/launchingContext/%7B%22source%22%3A%22Resources%20Microsoft.CognitiveServices%2Faccounts%22%7D/resetMenuId/) Service if you do not already have one. It may take a minute for your account to fully populate with the default resource group to use.
@@ -175,6 +197,26 @@ Prints the normalized text that will be sent to the NLU API
default: `false`
+#### 3. Classify Image
+
+`$ wp classifai image {image_ids} [--limit=int] [--force]`
+
+Directly classify images using Azure Computer Vision.
+
+##### Options
+
+`--limit=int`
+
+Limit number of images to classify.
+
+default: `false`
+
+`--force`
+
+Force classifying images regardless of their `alt`.
+
+default: `false`
+
## Data Gathering
ClassifAI connects your WordPress site directly to your account with specific service provider(s) (e.g. Microsoft Azure AI, IBM Watson), so no data is gathered by 10up. The data gathered in our [registration form](https://classifaiplugin.com/#cta) is used simply to stay in touch with users so we can provide product updates and news. More information is available in the [Privacy Policy on ClassifAIplugin.com](https://drive.google.com/open?id=1Hn4XEWmNGqeMzLqnS7Uru2Hl2vJeLc7cI7225ztThgQ).
@@ -185,11 +227,11 @@ ClassifAI connects your WordPress site directly to your account with specific se
## Changelog
-A complete listing of all notable changes to Distributor are documented in [CHANGELOG.md](https://github.com/10up/classifai/blob/develop/CHANGELOG.md).
+A complete listing of all notable changes to ClassifAI are documented in [CHANGELOG.md](https://github.com/10up/classifai/blob/develop/CHANGELOG.md).
## Contributing
-Please read [CODE_OF_CONDUCT.md](https://github.com/10up/classifai/blob/develop/CODE_OF_CONDUCT.md) for details on our code of conduct and [CONTRIBUTING.md](https://github.com/10up/classifai/blob/develop/CONTRIBUTING.md) for details on the process for submitting pull requests to us.
+Please read [CODE_OF_CONDUCT.md](https://github.com/10up/classifai/blob/develop/CODE_OF_CONDUCT.md) for details on our code of conduct, [CONTRIBUTING.md](https://github.com/10up/classifai/blob/develop/CONTRIBUTING.md) for details on the process for submitting pull requests to us, and [CREDITS.md](https://github.com/10up/classifai/blob/develop/CREDITS.md) for a listing of maintainers, contributors, and libraries for ClassifAI.
## Like what you see?
diff --git a/assets/img/menu-icon.svg b/assets/img/menu-icon.svg
new file mode 100644
index 000000000..7c92590b4
--- /dev/null
+++ b/assets/img/menu-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/classifai.php b/classifai.php
index b8c484c36..cea9e92e4 100644
--- a/classifai.php
+++ b/classifai.php
@@ -3,7 +3,7 @@
* Plugin Name: ClassifAI
* Plugin URI: https://github.com/10up/classifai
* Description: Enhance your WordPress content with Artificial Intelligence and Machine Learning services.
- * Version: 1.4.0
+ * Version: 1.5.0
* Author: 10up
* Author URI: https://10up.com
* License: GPLv2
@@ -22,7 +22,16 @@
function() {
if ( version_compare( PHP_VERSION, '7.0.0', '<' ) ) {
wp_die(
- esc_html__( 'ClassifAI requires PHP version 7.', 'classifai' ),
+ sprintf(
+ wp_kses(
+ /* translators: PHP Update guide URL */
+ __( 'ClassifAI requires PHP version 7. Click here to learn how to update your PHP version.', 'classifai' ),
+ array(
+ 'a' => array( 'href' => array() ),
+ )
+ ),
+ esc_url( 'https://wordpress.org/support/update-php/' )
+ ),
esc_html__( 'Error Activating', 'classifai' )
);
}
diff --git a/composer.json b/composer.json
index e35c99cf2..398d3e463 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "10up/classifai",
- "description": "Classifies WordPress content using IBM Watson NLU API",
+ "description": "Enhance your WordPress content with Artificial Intelligence and Machine Learning services.",
"authors": [
{
"name": "10up",
@@ -10,8 +10,8 @@
"type": "wordpress-plugin",
"license": "GPLv2",
"require": {
- "php": ">=7.0",
- "yahnis-elsts/plugin-update-checker": "^4.4"
+ "php": ">=7.2",
+ "yahnis-elsts/plugin-update-checker": "4.6"
},
"autoload": {
"psr-4": {
@@ -22,7 +22,9 @@
]
},
"require-dev": {
- "phpunit/phpunit": "~5.7.0",
- "10up/phpcs-composer": "dev-master"
- }
+ "phpunit/phpunit": "^7.5",
+ "10up/phpcs-composer": "dev-master",
+ "10up/wpacceptance": "dev-master"
+ },
+ "minimum-stability": "dev"
}
diff --git a/config.php b/config.php
index 1d4d6005a..691b931fb 100644
--- a/config.php
+++ b/config.php
@@ -4,7 +4,7 @@
* declared here instead of a Class.
*/
-$plugin_version = '1.4.0';
+$plugin_version = '1.5.0';
if ( file_exists( __DIR__ . '/.commit' ) ) {
$plugin_version .= '-' . file_get_contents( __DIR__ . '/.commit' );
diff --git a/dist/js/admin.min.js b/dist/js/admin.min.js
new file mode 100644
index 000000000..bfc0edf72
--- /dev/null
+++ b/dist/js/admin.min.js
@@ -0,0 +1 @@
+!function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=2)}({2:function(e,t){function n(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var a,l=e[Symbol.iterator]();!(r=(a=l.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{r||null==l.return||l.return()}finally{if(i)throw o}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}!function(){var e=document.getElementById("classifai-waston-cred-toggle"),t=document.getElementById("classifai-settings-watson_username");if(null!==e&&null!==t){var r=t.closest("tr"),i=n(document.getElementById("classifai-settings-watson_password").closest("tr").getElementsByTagName("label"),1)[0];null!==e&&e.addEventListener("click",function(n){if(n.preventDefault(),r.classList.toggle("hidden"),r.classList.contains("hidden"))return e.innerText=ClassifAI.use_password,i.innerText=ClassifAI.api_key,void(t.value="apikey");e.innerText=ClassifAI.use_key,i.innerText=ClassifAI.api_password})}}()}});
\ No newline at end of file
diff --git a/dist/js/media.min.js b/dist/js/media.min.js
new file mode 100644
index 000000000..4594a1894
--- /dev/null
+++ b/dist/js/media.min.js
@@ -0,0 +1 @@
+!function(t){var e={};function n(r){if(e[r])return e[r].exports;var a=e[r]={i:r,l:!1,exports:{}};return t[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)n.d(r,a,function(e){return t[e]}.bind(null,a));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=1)}([,function(t,e){function n(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=[],r=!0,a=!1,i=void 0;try{for(var o,u=t[Symbol.iterator]();!(r=(o=u.next()).done)&&(n.push(o.value),!e||n.length!==e);r=!0);}catch(t){a=!0,i=t}finally{try{r||null==u.return||u.return()}finally{if(a)throw i}}return n}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}var r,a;r=jQuery,a=function(t){var e=t.button,r=t.endpoint,a=t.callback,i=void 0!==a&&a,o=e.getAttribute("data-id"),u=n(e.parentNode.getElementsByClassName("spinner"),1)[0],c=wp.i18n.__;e.setAttribute("disabled","disabled"),u.style.display="inline-block",u.classList.add("is-active");var l="".concat(r).concat(o);wp.apiRequest({path:l}).then(function(t){e.removeAttribute("disabled"),u.style.display="none",u.classList.remove("is-active"),e.textContent=c("Rescan","classifai"),i&&i(t)})},r(document).ready(function(){wp.media.frame&&wp.media.frame.on("edit:attachment",function(){var t=document.getElementById("classifai-rescan-alt-tags"),e=document.getElementById("classifai-rescan-image-tags");t.addEventListener("click",function(t){return a({button:t.target,endpoint:"/classifai/v1/alt-tags/",callback:function(t){t&&(document.getElementById("attachment-details-two-column-alt-text").value=t)}})}),e.addEventListener("click",function(t){return a({button:t.target,endpoint:"/classifai/v1/image-tags/"})})})})}]);
\ No newline at end of file
diff --git a/includes/Classifai/Admin/BulkActions.php b/includes/Classifai/Admin/BulkActions.php
new file mode 100644
index 000000000..6b1ae9c1c
--- /dev/null
+++ b/includes/Classifai/Admin/BulkActions.php
@@ -0,0 +1,132 @@
+save_post_handler = new SavePostHandler();
+
+ foreach ( $post_types as $post_type ) {
+ add_filter( "bulk_actions-edit-$post_type", [ $this, 'register_bulk_actions' ] );
+ add_filter( "handle_bulk_actions-edit-$post_type", [ $this, 'bulk_action_handler' ], 10, 3 );
+
+ if ( is_post_type_hierarchical( $post_type ) ) {
+ add_action( 'page_row_actions', [ $this, 'register_row_action' ], 10, 2 );
+ } else {
+ add_action( 'post_row_actions', [ $this, 'register_row_action' ], 10, 2 );
+ }
+ }
+
+ add_action( 'admin_notices', [ $this, 'bulk_action_admin_notice' ] );
+ }
+
+ /**
+ * Register Classifai bulk action.
+ *
+ * @param array $bulk_actions Current bulk actions.
+ *
+ * @return array
+ */
+ public function register_bulk_actions( $bulk_actions ) {
+ $bulk_actions['classify'] = __( 'Classify', 'classifai' );
+ return $bulk_actions;
+ }
+
+ /**
+ * Handle bulk actions.
+ *
+ * @param string $redirect_to Redirect URL after bulk actions.
+ * @param string $doaction Action ID.
+ * @param array $post_ids Post ids to apply bulk actions to.
+ *
+ * @return string
+ */
+ public function bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
+ if ( 'classify' !== $doaction ) {
+ return $redirect_to;
+ }
+ foreach ( $post_ids as $post_id ) {
+ $this->save_post_handler->classify( $post_id );
+ }
+ $redirect_to = add_query_arg( 'bulk_classified', count( $post_ids ), $redirect_to );
+ return $redirect_to;
+ }
+
+ /**
+ * Display an admin notice after classifying posts in bulk.
+ */
+ public function bulk_action_admin_notice() {
+ if ( empty( $_REQUEST['bulk_classified'] ) ) {
+ return;
+ }
+
+ $classified_posts_count = intval( $_REQUEST['bulk_classified'] );
+
+ $output = '