Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '8dfacdbbef66c52ec305');
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,258 @@
|
||||
{
|
||||
"0": "Ā",
|
||||
"1": "ā",
|
||||
"2": "Ă",
|
||||
"3": "ă",
|
||||
"4": "Ą",
|
||||
"5": "ą",
|
||||
"6": "Ć",
|
||||
"7": "ć",
|
||||
"8": "Ĉ",
|
||||
"9": "ĉ",
|
||||
"10": "Ċ",
|
||||
"11": "ċ",
|
||||
"12": "Č",
|
||||
"13": "č",
|
||||
"14": "Ď",
|
||||
"15": "ď",
|
||||
"16": "Đ",
|
||||
"17": "đ",
|
||||
"18": "Ē",
|
||||
"19": "ē",
|
||||
"20": "Ĕ",
|
||||
"21": "ĕ",
|
||||
"22": "Ė",
|
||||
"23": "ė",
|
||||
"24": "Ę",
|
||||
"25": "ę",
|
||||
"26": "Ě",
|
||||
"27": "ě",
|
||||
"28": "Ĝ",
|
||||
"29": "ĝ",
|
||||
"30": "Ğ",
|
||||
"31": "ğ",
|
||||
"32": "Ġ",
|
||||
"33": "!",
|
||||
"34": "\"",
|
||||
"35": "#",
|
||||
"36": "$",
|
||||
"37": "%",
|
||||
"38": "&",
|
||||
"39": "'",
|
||||
"40": "(",
|
||||
"41": ")",
|
||||
"42": "*",
|
||||
"43": "+",
|
||||
"44": ",",
|
||||
"45": "-",
|
||||
"46": ".",
|
||||
"47": "/",
|
||||
"48": "0",
|
||||
"49": "1",
|
||||
"50": "2",
|
||||
"51": "3",
|
||||
"52": "4",
|
||||
"53": "5",
|
||||
"54": "6",
|
||||
"55": "7",
|
||||
"56": "8",
|
||||
"57": "9",
|
||||
"58": ":",
|
||||
"59": ";",
|
||||
"60": "<",
|
||||
"61": "=",
|
||||
"62": ">",
|
||||
"63": "?",
|
||||
"64": "@",
|
||||
"65": "A",
|
||||
"66": "B",
|
||||
"67": "C",
|
||||
"68": "D",
|
||||
"69": "E",
|
||||
"70": "F",
|
||||
"71": "G",
|
||||
"72": "H",
|
||||
"73": "I",
|
||||
"74": "J",
|
||||
"75": "K",
|
||||
"76": "L",
|
||||
"77": "M",
|
||||
"78": "N",
|
||||
"79": "O",
|
||||
"80": "P",
|
||||
"81": "Q",
|
||||
"82": "R",
|
||||
"83": "S",
|
||||
"84": "T",
|
||||
"85": "U",
|
||||
"86": "V",
|
||||
"87": "W",
|
||||
"88": "X",
|
||||
"89": "Y",
|
||||
"90": "Z",
|
||||
"91": "[",
|
||||
"92": "\\",
|
||||
"93": "]",
|
||||
"94": "^",
|
||||
"95": "_",
|
||||
"96": "`",
|
||||
"97": "a",
|
||||
"98": "b",
|
||||
"99": "c",
|
||||
"100": "d",
|
||||
"101": "e",
|
||||
"102": "f",
|
||||
"103": "g",
|
||||
"104": "h",
|
||||
"105": "i",
|
||||
"106": "j",
|
||||
"107": "k",
|
||||
"108": "l",
|
||||
"109": "m",
|
||||
"110": "n",
|
||||
"111": "o",
|
||||
"112": "p",
|
||||
"113": "q",
|
||||
"114": "r",
|
||||
"115": "s",
|
||||
"116": "t",
|
||||
"117": "u",
|
||||
"118": "v",
|
||||
"119": "w",
|
||||
"120": "x",
|
||||
"121": "y",
|
||||
"122": "z",
|
||||
"123": "{",
|
||||
"124": "|",
|
||||
"125": "}",
|
||||
"126": "~",
|
||||
"127": "ġ",
|
||||
"128": "Ģ",
|
||||
"129": "ģ",
|
||||
"130": "Ĥ",
|
||||
"131": "ĥ",
|
||||
"132": "Ħ",
|
||||
"133": "ħ",
|
||||
"134": "Ĩ",
|
||||
"135": "ĩ",
|
||||
"136": "Ī",
|
||||
"137": "ī",
|
||||
"138": "Ĭ",
|
||||
"139": "ĭ",
|
||||
"140": "Į",
|
||||
"141": "į",
|
||||
"142": "İ",
|
||||
"143": "ı",
|
||||
"144": "IJ",
|
||||
"145": "ij",
|
||||
"146": "Ĵ",
|
||||
"147": "ĵ",
|
||||
"148": "Ķ",
|
||||
"149": "ķ",
|
||||
"150": "ĸ",
|
||||
"151": "Ĺ",
|
||||
"152": "ĺ",
|
||||
"153": "Ļ",
|
||||
"154": "ļ",
|
||||
"155": "Ľ",
|
||||
"156": "ľ",
|
||||
"157": "Ŀ",
|
||||
"158": "ŀ",
|
||||
"159": "Ł",
|
||||
"160": "ł",
|
||||
"161": "¡",
|
||||
"162": "¢",
|
||||
"163": "£",
|
||||
"164": "¤",
|
||||
"165": "¥",
|
||||
"166": "¦",
|
||||
"167": "§",
|
||||
"168": "¨",
|
||||
"169": "©",
|
||||
"170": "ª",
|
||||
"171": "«",
|
||||
"172": "¬",
|
||||
"173": "Ń",
|
||||
"174": "®",
|
||||
"175": "¯",
|
||||
"176": "°",
|
||||
"177": "±",
|
||||
"178": "²",
|
||||
"179": "³",
|
||||
"180": "´",
|
||||
"181": "µ",
|
||||
"182": "¶",
|
||||
"183": "·",
|
||||
"184": "¸",
|
||||
"185": "¹",
|
||||
"186": "º",
|
||||
"187": "»",
|
||||
"188": "¼",
|
||||
"189": "½",
|
||||
"190": "¾",
|
||||
"191": "¿",
|
||||
"192": "À",
|
||||
"193": "Á",
|
||||
"194": "Â",
|
||||
"195": "Ã",
|
||||
"196": "Ä",
|
||||
"197": "Å",
|
||||
"198": "Æ",
|
||||
"199": "Ç",
|
||||
"200": "È",
|
||||
"201": "É",
|
||||
"202": "Ê",
|
||||
"203": "Ë",
|
||||
"204": "Ì",
|
||||
"205": "Í",
|
||||
"206": "Î",
|
||||
"207": "Ï",
|
||||
"208": "Ð",
|
||||
"209": "Ñ",
|
||||
"210": "Ò",
|
||||
"211": "Ó",
|
||||
"212": "Ô",
|
||||
"213": "Õ",
|
||||
"214": "Ö",
|
||||
"215": "×",
|
||||
"216": "Ø",
|
||||
"217": "Ù",
|
||||
"218": "Ú",
|
||||
"219": "Û",
|
||||
"220": "Ü",
|
||||
"221": "Ý",
|
||||
"222": "Þ",
|
||||
"223": "ß",
|
||||
"224": "à",
|
||||
"225": "á",
|
||||
"226": "â",
|
||||
"227": "ã",
|
||||
"228": "ä",
|
||||
"229": "å",
|
||||
"230": "æ",
|
||||
"231": "ç",
|
||||
"232": "è",
|
||||
"233": "é",
|
||||
"234": "ê",
|
||||
"235": "ë",
|
||||
"236": "ì",
|
||||
"237": "í",
|
||||
"238": "î",
|
||||
"239": "ï",
|
||||
"240": "ð",
|
||||
"241": "ñ",
|
||||
"242": "ò",
|
||||
"243": "ó",
|
||||
"244": "ô",
|
||||
"245": "õ",
|
||||
"246": "ö",
|
||||
"247": "÷",
|
||||
"248": "ø",
|
||||
"249": "ù",
|
||||
"250": "ú",
|
||||
"251": "û",
|
||||
"252": "ü",
|
||||
"253": "ý",
|
||||
"254": "þ",
|
||||
"255": "ÿ"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
2.0.2 - 31st January 2025
|
||||
- Reverted: Caching mechanism for credit response to optimize API calls due to unforeseen issues.
|
||||
|
||||
2.0.1 - 31st January 2025
|
||||
- Improvement: Added a caching mechanism for credit response to optimize API calls.
|
||||
- Fix: Resolved an issue wherein the AI Assistant side bar would not be clickable for some teams.
|
||||
|
||||
2.0.0 - 9th December 2024
|
||||
- New: The AI Assistant is now Location Aware.
|
||||
- Improvement: Revamped the entire UI of the Assistant Sidebar.
|
||||
|
||||
1.2.4 - 1st November 2024
|
||||
- Fix: Added a function check for 'get_current_screen'.
|
||||
|
||||
1.2.3 - 23rd October 2024
|
||||
- Improvement: Added support for the 'source' parameter in the middleware URL.
|
||||
|
||||
1.2.2 - 8th October 2024
|
||||
- Excluded assets from loading via Spectra for SureForms CPTs.
|
||||
|
||||
1.2.1 - 27th September 2024
|
||||
- Improvement: Hid the chat textbox interface when the user is not authorized.
|
||||
- Improvement: Removed the GPT model parameter for real-time model updates from the middleware.
|
||||
|
||||
1.2.0 - 26th July 2024
|
||||
- Improvement: Switched from the GPT 3.5 Turbo modal to the 4o Mini modal.
|
||||
|
||||
1.1.10 - 15th July 2024
|
||||
- Fix: Resolved an issue with the AI Assistant admin-bar trigger loading order in WordPress 6.6.
|
||||
|
||||
v1.1.9 - 2nd July 2024
|
||||
- Improvement: The library's text-domain support has been removed & translation is now managed from the project level.
|
||||
|
||||
v1.1.8 - 27th June 2024
|
||||
- Improved security.
|
||||
|
||||
v1.1.7 - 24th June 2024
|
||||
- Feature: Added tooltips for icons in the Chat sidebar for improved user experience.
|
||||
- Improvement: Added disconnection status to the settings option to avoid deletion after disconnecting.
|
||||
- Fix: Resolved the empty text glitch that would occur when editing the first message in the chat.
|
||||
- Fix: Resolved PHP warnings in the widget editor for PluginSidebar and PluginSidebarMoreMenuItem.
|
||||
|
||||
v1.1.6 - 15th May 2024
|
||||
- Improvement: Added dropdown menu for common Zip AI Assistant actions in the toolbar.
|
||||
- Improvement: Upgraded the `get_credit_server_response` helper function to support data.
|
||||
|
||||
v1.1.5 - 25th April 2024
|
||||
- Fix: Copy and Regenerate buttons are now visible by default instead of being displayed on hover.
|
||||
|
||||
v1.1.4 - 23rd April 2024
|
||||
- Replaced "AI Assistant" text with a Sparkles icon for clearer visual representation.
|
||||
|
||||
v1.1.3 - 14th March 2024
|
||||
- Removed the highlight color for Richtexts.
|
||||
- Replaced ZipWP logo with the AI Sparkle icon for all AI-Assistant-related buttons.
|
||||
- Improved the AI Assistant sidebar UI on the front end.
|
||||
|
||||
v1.1.2 - 27th February 2024
|
||||
- Improvement: Added ZipWP API server helper functions to get the current plan.
|
||||
|
||||
v1.1.1 - 16th February 2024
|
||||
- Improvement: Added middleware parameter handling for the affiliate ID.
|
||||
- Improvement: Locally loaded Google Fonts for the AI Assistant sidebar.
|
||||
- Fix: Restricted front-end assets for non-admin users.
|
||||
|
||||
v1.1.0 - 17th January 2024
|
||||
- Feature: Made the AI Assistant sidebar accessible outside the editor.
|
||||
- Improvement: Added the 'Force Enabled' function to ensure that modules are enabled.
|
||||
|
||||
v1.0.9 - 11th January 2024
|
||||
- Improvement: Added middleware parameter handling for the plugin slug.
|
||||
|
||||
v1.0.8 - 18th December 2023
|
||||
- Fix: Added compatibility with PHP version 7.0 and above.
|
||||
|
||||
v1.0.7 - 2nd December 2023
|
||||
- Improvement: Updated the middleware request and the Zip AI settings that are saved.
|
||||
- Fix: Implemented proper multi-setting updation.
|
||||
|
||||
v1.0.6 - 30th November 2023
|
||||
- Improvement: Added a filter to disable the entire library from loading.
|
||||
|
||||
v1.0.5 - 30th November 2023
|
||||
- Improvement: Added a new module structure and removed the admin page from Tools.
|
||||
|
||||
v1.0.4 - 30th November 2023
|
||||
- Updating `distignore` for composer update compatibility.
|
||||
|
||||
v1.0.3 - 11th November 2023
|
||||
- Improvement: Added an option to disable Zip Ai Assistant from the sidebar.
|
||||
|
||||
v1.0.2 - 9th November 2023
|
||||
- Improvement: Better one-click command.
|
||||
|
||||
v1.0.1 - 9th November 2023
|
||||
- Initial Commit
|
||||
@@ -0,0 +1,518 @@
|
||||
<?php
|
||||
/**
|
||||
* Zip AI - Admin Configurations.
|
||||
*
|
||||
* @package zip-ai
|
||||
*/
|
||||
|
||||
namespace ZipAI\Classes;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Classes to be used, in alphabetical order.
|
||||
use ZipAI\Classes\Helper;
|
||||
use ZipAI\Classes\Module;
|
||||
use ZipAI\Classes\Utils;
|
||||
|
||||
/**
|
||||
* The Admin_Configurations Class.
|
||||
*/
|
||||
class Admin_Configurations {
|
||||
|
||||
/**
|
||||
* The menu slug.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string Menu slug.
|
||||
*/
|
||||
private $menu_slug = ZIP_AI_MENU_SLUG;
|
||||
|
||||
/**
|
||||
* Instance of this class.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var object Class object.
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* Custom Capability
|
||||
*
|
||||
* @since 1.1.8
|
||||
* @access public
|
||||
* @var string capabilities.
|
||||
*/
|
||||
public static $custom_capability = 'manage_zip_ai_assistant';
|
||||
|
||||
/**
|
||||
* Initiator of this class.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return object initialized object of this class.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor of this class.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
// Setup the Admin Scripts.
|
||||
// add_action( 'admin_init', array( $this, 'settings_admin_scripts' ) ); - This can be added later if required.
|
||||
|
||||
// Verify Zip AI Authorization.
|
||||
add_action( 'admin_init', array( $this, 'verify_authorization' ) );
|
||||
/**
|
||||
* This action hook is used to add custom capabilities to the administrator role.
|
||||
* The custom capability is 'manage_zip_ai_assistant'.
|
||||
* This action hook is triggered when the admin initiates, meaning when the admin
|
||||
* goes to the admin dashboard, this action hook is triggered.
|
||||
* The priority of this action hook is set to 10, meaning it will be executed before
|
||||
* other action hooks with lower priorities.
|
||||
* The callback function for this action hook is the 'add_custom_capabilities' method
|
||||
* of the same class.
|
||||
*/
|
||||
add_action( 'admin_init', array( $this, 'add_custom_capabilities' ), 10 );
|
||||
|
||||
// Setup the Admin Menu Page.
|
||||
// add_action( 'admin_menu', array( $this, 'setup_menu_page' ) ); - This can be added later if required.
|
||||
|
||||
// Setup the Admin Ajax Actions.
|
||||
add_action( 'wp_ajax_zip_ai_toggle_assistant_status_ajax', array( $this, 'toggle_assistant_status_ajax' ) );
|
||||
add_action( 'wp_ajax_zip_ai_disabler_ajax', array( $this, 'disabler_ajax' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom capabilities.
|
||||
*
|
||||
* @since 1.1.8
|
||||
* @return void
|
||||
*/
|
||||
public function add_custom_capabilities() {
|
||||
// Remove the custom capability from all roles except the roles specified in the filter.
|
||||
$this->remove_custom_capability_from_other_roles();
|
||||
|
||||
/**
|
||||
* Get the additional roles to add the custom capability.
|
||||
*
|
||||
* The additional roles are filtered by the `zip_ai_assistant_capability_additional_roles` filter.
|
||||
* If this filter is not used, then only the 'administrator' role will get the custom capability.
|
||||
* The default additional roles are 'administrator' and 'editor'.
|
||||
*
|
||||
* @since 1.1.8
|
||||
*
|
||||
* @return array The additional roles to add the custom capability.
|
||||
*/
|
||||
$roles = apply_filters(
|
||||
'zip_ai_assistant_capability_additional_roles',
|
||||
array( 'administrator', 'editor' )
|
||||
);
|
||||
|
||||
// Loop through each role and add the custom capability to the role object.
|
||||
foreach ( $roles as $role_slug ) {
|
||||
// Get the role object by the role slug.
|
||||
$role_object = get_role( $role_slug );
|
||||
|
||||
// Check if the role object exists.
|
||||
if ( $role_object ) {
|
||||
// Add the custom capability to the role object.
|
||||
$role_object->add_cap( self::$custom_capability );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove custom capabilities.
|
||||
*
|
||||
* @since 1.1.8
|
||||
* @return void
|
||||
*/
|
||||
public function remove_custom_capability_from_other_roles() {
|
||||
// Set the default role to retain the custom capability.
|
||||
$default_role = 'administrator';
|
||||
|
||||
// Get the default role object.
|
||||
$default_role_object = get_role( $default_role );
|
||||
|
||||
// Remove the custom capability from all roles except the default role.
|
||||
// Here, we are iterating through all the roles and removing the custom capability
|
||||
// from each role except the default role.
|
||||
if ( $default_role_object ) {
|
||||
// Get all the role names.
|
||||
$roles = wp_roles()->role_names;
|
||||
|
||||
// Exclude the default role from the list of roles.
|
||||
unset( $roles[ $default_role ] );
|
||||
|
||||
// Loop through each role.
|
||||
foreach ( $roles as $role_slug => $role_name ) {
|
||||
// Get the role object by the role slug.
|
||||
$role_object = get_role( $role_slug );
|
||||
|
||||
// Check if the role object exists and if the role object has the custom capability.
|
||||
if ( $role_object && $role_object->has_cap( self::$custom_capability ) ) {
|
||||
// Remove the custom capability from the role object.
|
||||
$role_object->remove_cap( self::$custom_capability );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the Zip AI menu page.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function setup_menu_page() {
|
||||
// If the current user does not have the required capability, then abandon ship.
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$capability = 'manage_options';
|
||||
|
||||
// Add the Zip AI Submenu.
|
||||
add_submenu_page(
|
||||
apply_filters( 'zip_ai_parent_page', 'none' ), // The parent page of this menu.
|
||||
apply_filters( 'zip_ai_page_title', 'Zip - AI Assistant' ), // The page title.
|
||||
apply_filters( 'zip_ai_menu_title', 'Zip - AI Assistant' ), // The menu title.
|
||||
apply_filters( 'zip_ai_menu_capability', $capability ), // The capability required for access to this page.
|
||||
$this->menu_slug, // The menu slug.
|
||||
array( $this, 'render_dashboard' ), // The rendered output function.
|
||||
apply_filters( 'zip_ai_menu_position', 1 ) // The position of this menu item in the menu.
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the user was given authorization to use Zip AI.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function verify_authorization() {
|
||||
// If the current user does not have the required capability or the referrer is empty, then abandon ship.
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the nonce.
|
||||
$nonce = ( isset( $_GET['nonce'] ) ) ? sanitize_key( $_GET['nonce'] ) : '';
|
||||
|
||||
// If the nonce is not valid, or if there's no token, then abandon ship.
|
||||
if ( false === wp_verify_nonce( $nonce, 'zip_ai_auth_nonce' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Redirect to the settings page if the user is trying to revoke the token.
|
||||
if ( isset( $_GET['revoke_zip_ai_authorization_token'] ) && 'definitely' === sanitize_text_field( $_GET['revoke_zip_ai_authorization_token'] ) ) {
|
||||
|
||||
// Clear out the Zip AI settings and disconnect the user.
|
||||
Helper::update_admin_settings_option( 'zip_ai_settings', [ 'status' => 'disconnected' ] );
|
||||
|
||||
// Redirect to the settings page.
|
||||
$redirection_url = apply_filters( 'zip_ai_revoke_redirection_url', admin_url() );
|
||||
wp_safe_redirect( $redirection_url );
|
||||
exit;
|
||||
}//end if
|
||||
|
||||
// If none of the required data is received, abandon ship.
|
||||
if ( ! isset( $_GET['credit_token'] ) && ! isset( $_GET['token'] ) && ! isset( $_GET['email'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the existing options, and update the auth token before updating the option.
|
||||
$db_settings_options = Helper::get_setting();
|
||||
|
||||
// At this point, the user is connected with Zip AI.
|
||||
$db_settings_options['status'] = 'connected';
|
||||
|
||||
// Update the auth token if needed.
|
||||
if ( isset( $_GET['credit_token'] ) && is_string( $_GET['credit_token'] ) ) {
|
||||
$db_settings_options['auth_token'] = Utils::encrypt( sanitize_text_field( $_GET['credit_token'] ) );
|
||||
}
|
||||
|
||||
// Update the Zip token if needed.
|
||||
if ( isset( $_GET['token'] ) && is_string( $_GET['token'] ) ) {
|
||||
$db_settings_options['zip_token'] = Utils::encrypt( sanitize_text_field( $_GET['token'] ) );
|
||||
}
|
||||
|
||||
// Update the email if needed.
|
||||
if ( isset( $_GET['email'] ) && is_string( $_GET['email'] ) ) {
|
||||
$db_settings_options['email'] = sanitize_email( $_GET['email'] );
|
||||
}
|
||||
|
||||
// Update the Zip AI settings.
|
||||
Helper::update_admin_settings_option( 'zip_ai_settings', $db_settings_options );
|
||||
|
||||
// Redirect to the settings page.
|
||||
if ( apply_filters( 'zip_ai_auth_redirection_flag', true ) ) {
|
||||
$redirection_url = apply_filters( 'zip_ai_auth_redirection_url', admin_url( 'admin.php?page=zip-ai' ) );
|
||||
wp_safe_redirect( $redirection_url );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the Ajax Event to Entirely Disable the Zip AI Library from loading.
|
||||
*
|
||||
* @since 1.0.5
|
||||
* @return void
|
||||
*/
|
||||
public function disabler_ajax() {
|
||||
// If the current user does not have the required capability, then abandon ship.
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// Verify the nonce.
|
||||
check_ajax_referer( 'zip_ai_admin_nonce', 'nonce' );
|
||||
|
||||
// Have a variable to check if the module was disabled.
|
||||
$is_module_disabled = false;
|
||||
|
||||
// Check if the Zip AI Assistant was requested to be disabled.
|
||||
if ( ! empty( $_POST['disable_zip_ai_assistant'] ) ) {
|
||||
$is_module_disabled = Module::disable( 'ai_assistant' );
|
||||
}
|
||||
|
||||
// Send the status based on whether the Zip AI Library is enabled or not.
|
||||
if ( $is_module_disabled ) {
|
||||
wp_send_json_success();
|
||||
} else {
|
||||
wp_send_json_error();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the AI Assistant Toggle Ajax.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function toggle_assistant_status_ajax() {
|
||||
// If the current user does not have the required capability, then abandon ship.
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// Verify the nonce.
|
||||
check_ajax_referer( 'zip_ai_admin_nonce', 'nonce' );
|
||||
|
||||
// If the Zip options is not an array, then send an error.
|
||||
if ( empty( $_POST['enable_zip_chat'] ) || ! is_string( $_POST['enable_zip_chat'] ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// Create a variable to check if the assistant module was toggled.
|
||||
$is_module_toggled = false;
|
||||
|
||||
// Update the enabled status.
|
||||
if ( 'enabled' === sanitize_text_field( $_POST['enable_zip_chat'] ) ) {
|
||||
$is_module_toggled = Module::enable( 'ai_assistant' );
|
||||
} else {
|
||||
$is_module_toggled = Module::disable( 'ai_assistant' );
|
||||
}
|
||||
|
||||
// Send the status based on whether the module was toggled.
|
||||
if ( $is_module_toggled ) {
|
||||
wp_send_json_success();
|
||||
} else {
|
||||
wp_send_json_error();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Zip AI Admin Settings Page.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function render_dashboard() {
|
||||
// Render the dashboard app div.
|
||||
?>
|
||||
<div id="zip-ai__dashboard-app--wrapper">
|
||||
<div id="zip-ai-dashboard-app" class="zip-ai-dashboard-app"></div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the Admin Settings and Scripts on initialization.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function settings_admin_scripts() {
|
||||
|
||||
// If the current page is not the Zip AI Settings page, then abandon ship.
|
||||
if ( empty( $_GET['page'] ) || ( $this->menu_slug !== $_GET['page'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
return;
|
||||
}
|
||||
|
||||
// Enqueue the Admin Styles and Scripts for the React App.
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles_and_scripts' ) );
|
||||
|
||||
// Add the footer link if needed.
|
||||
if ( Helper::is_authorized() ) {
|
||||
// Add the footer link.
|
||||
add_filter( 'admin_footer_text', array( $this, 'add_footer_link' ), 99 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enqueues the needed CSS/JS for Zip AI's admin settings page.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_styles_and_scripts() {
|
||||
|
||||
if ( class_exists( '\UAGB_Admin_Helper' ) && method_exists( '\UAGB_Admin_Helper', 'should_exclude_assets_for_cpt' ) ) {
|
||||
if ( \UAGB_Admin_Helper::should_exclude_assets_for_cpt() ) {
|
||||
return; // Early return to prevent loading assets.
|
||||
}
|
||||
}
|
||||
|
||||
// Enqueue the admin Google Fonts and WP Components.
|
||||
$admin_slug = 'zip-ai-admin';
|
||||
wp_enqueue_style(
|
||||
$admin_slug . '-font',
|
||||
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap',
|
||||
array(),
|
||||
ZIP_AI_VERSION
|
||||
);
|
||||
wp_enqueue_style( 'wp-components' );
|
||||
|
||||
// Set the default credit details.
|
||||
$credit_details = array(
|
||||
'used' => 0,
|
||||
'total' => 0,
|
||||
'threshold' => array(
|
||||
'medium' => ZIP_AI_CREDIT_THRESHOLD_MEDIUM,
|
||||
'high' => ZIP_AI_CREDIT_THRESHOLD_HIGH,
|
||||
),
|
||||
'percentage' => 0,
|
||||
);
|
||||
|
||||
// Get the response from the endpoint.
|
||||
$response = Helper::get_credit_server_response( 'usage' );
|
||||
|
||||
// If the response is not an error, then update the credit details.
|
||||
if (
|
||||
empty( $response['error'] )
|
||||
&& ! empty( $response['total_credits'] )
|
||||
) {
|
||||
$credit_details['used'] = ! empty( $response['total_used_credits'] ) ? $response['total_used_credits'] : 0;
|
||||
$credit_details['total'] = $response['total_credits'];
|
||||
$credit_details['percentage'] = intval( ( $credit_details['used'] / $credit_details['total'] ) * 100 );
|
||||
}
|
||||
|
||||
// Add the data to localize.
|
||||
$localize = apply_filters(
|
||||
'zip_ai_admin_localize',
|
||||
array(
|
||||
'admin_url' => admin_url(),
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'auth_middleware' => Helper::get_auth_middleware_url(),
|
||||
'auth_revoke_url' => Helper::get_auth_revoke_url(),
|
||||
'credit_topup_url' => ZIP_AI_CREDIT_TOPUP_URL,
|
||||
'is_authorized' => Helper::is_authorized(),
|
||||
'is_ai_assistant_enabled' => Module::is_enabled( 'ai_assistant' ),
|
||||
'admin_nonce' => wp_create_nonce( 'zip_ai_admin_nonce' ),
|
||||
'page_slug' => $this->menu_slug,
|
||||
'credit_details' => Helper::get_credit_details(),
|
||||
)
|
||||
);
|
||||
|
||||
// Enqueue the admin scripts.
|
||||
$this->localize_and_enqueue_admin_scripts( $localize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize and Enqueue the Admin Scripts.
|
||||
*
|
||||
* @param array $localize The data to localize.
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function localize_and_enqueue_admin_scripts( $localize ) {
|
||||
// Set the required variables.
|
||||
$handle = 'zip-ai-admin-settings';
|
||||
$build_path = ZIP_AI_DIR . 'admin/dashboard-app/build/';
|
||||
$build_url = ZIP_AI_URL . 'admin/dashboard-app/build/';
|
||||
$script_asset_path = $build_path . 'dashboard-app.asset.php';
|
||||
$script_info = file_exists( $script_asset_path )
|
||||
? include $script_asset_path
|
||||
: array(
|
||||
'dependencies' => array(),
|
||||
'version' => ZIP_AI_VERSION,
|
||||
);
|
||||
$script_dep = array_merge( $script_info['dependencies'], array( 'updates' ) );
|
||||
|
||||
// Register the admin scripts.
|
||||
wp_register_script(
|
||||
$handle,
|
||||
$build_url . 'dashboard-app.js',
|
||||
$script_dep,
|
||||
$script_info['version'],
|
||||
true
|
||||
);
|
||||
|
||||
// Register the admin styles.
|
||||
wp_register_style(
|
||||
$handle,
|
||||
$build_url . 'dashboard-app.css',
|
||||
array(),
|
||||
ZIP_AI_VERSION
|
||||
);
|
||||
|
||||
// Register the admin Google Fonts.
|
||||
wp_register_style(
|
||||
'zip-ai-admin-google-fonts',
|
||||
'https://fonts.googleapis.com/css2?family=Inter:wght@200&display=swap',
|
||||
array(),
|
||||
ZIP_AI_VERSION
|
||||
);
|
||||
|
||||
// Enqueue the admin scripts.
|
||||
wp_enqueue_script( $handle );
|
||||
// Set the script translations.
|
||||
wp_set_script_translations( $handle, apply_filters( 'zip_ai_library_textdomain', 'zip-ai' ) );
|
||||
// Enqueue the Google Fonts.
|
||||
wp_enqueue_style( 'zip-ai-admin-google-fonts' );
|
||||
// Enqueue the admin styles.
|
||||
wp_enqueue_style( $handle );
|
||||
// Set the RTL styles.
|
||||
wp_style_add_data( $handle, 'rtl', 'replace' );
|
||||
// Localize the script.
|
||||
wp_localize_script( $handle, 'zip_ai_react', $localize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the footer link.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return string The footer link.
|
||||
*/
|
||||
public function add_footer_link() {
|
||||
return '<span id="footer-thankyou">' . sprintf(
|
||||
/* translators: %1$s: HTML link start tag, %2$s: HTML link end tag. */
|
||||
__( 'Thank you for using %1$sZip AI.%2$s', 'astra-sites' ),
|
||||
'<a href="https://wpspectra.com/zip-ai/" class="focus:text-spec-hover active:text-spec-hover hover:text-spec-hover" target="_blank" rel="noopener noreferrer">',
|
||||
'</a>'
|
||||
) . '</span>';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,468 @@
|
||||
<?php
|
||||
/**
|
||||
* Zip AI - Helper.
|
||||
*
|
||||
* This file contains the helper functions of Zip AI.
|
||||
* Helpers are functions that are used throughout the library.
|
||||
*
|
||||
* @package zip-ai
|
||||
*/
|
||||
|
||||
namespace ZipAI\Classes;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Classes to be used, in alphabetical order.
|
||||
use ZipAI\Classes\Token_Calculator;
|
||||
use ZipAI\Classes\Utils;
|
||||
|
||||
/**
|
||||
* The Helper Class.
|
||||
*/
|
||||
class Helper {
|
||||
/**
|
||||
* Get an option from the database.
|
||||
*
|
||||
* @param string $key The option key.
|
||||
* @param mixed $default The option default value if option is not available.
|
||||
* @param boolean $network_override Whether to allow the network admin setting to be overridden on subsites.
|
||||
* @since 1.0.0
|
||||
* @return mixed The option value.
|
||||
*/
|
||||
public static function get_admin_settings_option( $key, $default = false, $network_override = false ) {
|
||||
// Get the site-wide option if we're in the network admin.
|
||||
return $network_override && is_multisite() ? get_site_option( $key, $default ) : get_option( $key, $default );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an option from the database.
|
||||
*
|
||||
* @param string $key The option key.
|
||||
* @param mixed $value The value to update.
|
||||
* @param bool $network_override Whether to allow the network_override admin setting to be overridden on subsites.
|
||||
* @since 1.0.0
|
||||
* @return bool True if the option was updated, false otherwise.
|
||||
*/
|
||||
public static function update_admin_settings_option( $key, $value, $network_override = false ) {
|
||||
// Update the site-wide option if we're in the network admin, and return the updated status.
|
||||
return $network_override && is_multisite() ? update_site_option( $key, $value ) : update_option( $key, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an option from the database for.
|
||||
*
|
||||
* @param string $key The option key.
|
||||
* @param boolean $network_override Whether to allow the network admin setting to be overridden on subsites.
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public static function delete_admin_settings_option( $key, $network_override = false ) {
|
||||
// Delete the site-wide option if we're in the network admin.
|
||||
if ( $network_override && is_multisite() ) {
|
||||
delete_site_option( $key );
|
||||
} else {
|
||||
delete_option( $key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Zip AI is authorized.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return boolean True if Zip AI is authorized, false otherwise.
|
||||
*/
|
||||
public static function is_authorized() {
|
||||
// Get the Zip AI settings.
|
||||
$existing_settings = self::get_admin_settings_option( 'zip_ai_settings' );
|
||||
|
||||
// If the Zip AI settings are empty, return false.
|
||||
if ( empty( $existing_settings ) || ! is_array( $existing_settings ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if the auth token is set and is a string.
|
||||
return (
|
||||
! empty( $existing_settings['auth_token'] )
|
||||
&& is_string( $existing_settings['auth_token'] )
|
||||
&& ! empty( trim( $existing_settings['auth_token'] ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Zip AI Settings.
|
||||
*
|
||||
* If used with a key, it will return that specific setting.
|
||||
* If used without a key, it will return the entire settings array.
|
||||
*
|
||||
* @param string $key The setting key.
|
||||
* @param mixed $default The default value to return if the setting is not found.
|
||||
* @since 1.0.0
|
||||
* @return mixed|array The setting value, or the default.
|
||||
*/
|
||||
public static function get_setting( $key = '', $default = array() ) {
|
||||
|
||||
// Get the Zip AI settings.
|
||||
$existing_settings = self::get_admin_settings_option( 'zip_ai_settings' );
|
||||
|
||||
// If the Zip AI settings are empty, return the fallback.
|
||||
if ( empty( $existing_settings ) || ! is_array( $existing_settings ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
// If the key is empty, return the entire settings array - otherwise return the specific setting or the fallback.
|
||||
if ( empty( $key ) ) {
|
||||
return $existing_settings;
|
||||
} else {
|
||||
return isset( $existing_settings[ $key ] ) ? $existing_settings[ $key ] : $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Token Count for a given message.
|
||||
*
|
||||
* @param string $message The message to get the token count for.
|
||||
* @since 1.0.0
|
||||
* @return int The token count.
|
||||
*/
|
||||
public static function get_token_count( $message ) {
|
||||
// Get the formatted token array.
|
||||
$token_array = Token_Calculator::gpt_encode( $message );
|
||||
|
||||
// If the token array is empty, return 0, else return the count of the token array.
|
||||
return ( empty( $token_array ) || ! is_array( $token_array ) ) ? 0 : count( $token_array );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Zip AI Response from the Zip Credit Server.
|
||||
*
|
||||
* @param string $endpoint The endpoint to get the response from.
|
||||
* @param array $body The data to be passed as the request body, if any.
|
||||
* @param array $extra_args Extra arguments to be passed to the request, if any.
|
||||
* @since 1.0.0
|
||||
* @return array The Zip AI Response.
|
||||
*/
|
||||
public static function get_credit_server_response( $endpoint, $body = [], $extra_args = [] ) {
|
||||
// If the endpoint is not a string, then abandon ship.
|
||||
if ( ! is_string( $endpoint ) ) {
|
||||
return array(
|
||||
'error' => __( 'The Zip AI Endpoint was not declared', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Get the Auth Token from the Zip AI Settings.
|
||||
$auth_token = self::get_decrypted_auth_token();
|
||||
|
||||
// If the Zip Auth Token is not set, then abandon ship.
|
||||
if ( empty( $auth_token ) || ! is_string( $auth_token ) ) {
|
||||
return array(
|
||||
'error' => __( 'The Zip AI Auth Token is not set.', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Set the API URL.
|
||||
$api_url = ZIP_AI_CREDIT_SERVER_API . $endpoint;
|
||||
$api_args = array(
|
||||
'headers' => array(
|
||||
'Authorization' => 'Bearer ' . $auth_token,
|
||||
),
|
||||
'timeout' => 30, // phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout -- 30 seconds is required sometime for open ai responses
|
||||
);
|
||||
|
||||
// If the data array was passed, add it to the args.
|
||||
if ( ! empty( $body ) && is_array( $body ) ) {
|
||||
$api_args['body'] = $body;
|
||||
}
|
||||
|
||||
// If there are any extra arguments, then we can overwrite the required arguments.
|
||||
if ( ! empty( $extra_args ) && is_array( $extra_args ) ) {
|
||||
$api_args = array_merge(
|
||||
$api_args,
|
||||
$extra_args
|
||||
);
|
||||
}
|
||||
|
||||
// Get the response from the endpoint.
|
||||
$response = wp_remote_post(
|
||||
$api_url,
|
||||
$api_args
|
||||
);
|
||||
|
||||
// If the response was an error, or not a 200 status code, then abandon ship.
|
||||
if ( is_wp_error( $response ) || empty( $response['response'] ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return array(
|
||||
'error' => __( 'The Zip AI Middleware is not responding.', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Get the response body.
|
||||
$response_body = wp_remote_retrieve_body( $response );
|
||||
|
||||
// If the response body is not a JSON, then abandon ship.
|
||||
if ( empty( $response_body ) || ! json_decode( $response_body ) ) {
|
||||
return array(
|
||||
'error' => __( 'The Zip AI Middleware encountered an error.', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Return the response body.
|
||||
return json_decode( $response_body, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a response from the ZipWP API server.
|
||||
*
|
||||
* @param string $endpoint The endpoint to get the response from.
|
||||
* @since 1.1.2
|
||||
* @return array The ZipWP API Response.
|
||||
*/
|
||||
public static function get_zipwp_api_response( $endpoint ) {
|
||||
// If the endpoint is not a string, then abandon ship.
|
||||
if ( ! is_string( $endpoint ) ) {
|
||||
return array(
|
||||
'error' => __( 'The ZipWP Endpoint was not declared', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Get the ZipWP Token from the Zip AI Settings.
|
||||
$zipwp_token = self::get_decrypted_zipwp_token();
|
||||
|
||||
// If the ZipWP Token is not set, then abandon ship.
|
||||
if ( empty( $zipwp_token ) || ! is_string( $zipwp_token ) ) {
|
||||
return array(
|
||||
'error' => __( 'The ZipWP Token is not set.', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Set the API URL.
|
||||
$api_url = ZIP_AI_ZIPWP_API . $endpoint;
|
||||
|
||||
// Get the response from the endpoint.
|
||||
$response = wp_remote_get(
|
||||
$api_url,
|
||||
array(
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . $zipwp_token,
|
||||
),
|
||||
'sslverify' => false,
|
||||
'timeout' => 30, // phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout -- 30 seconds is required sometime for the ZipWP API response
|
||||
)
|
||||
);
|
||||
|
||||
// If the response was an error, or not a 200 status code, then abandon ship.
|
||||
if ( is_wp_error( $response ) || empty( $response['response'] ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return array(
|
||||
'error' => __( 'The ZipWP API server is not responding.', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Get the response body.
|
||||
$response_body = wp_remote_retrieve_body( $response );
|
||||
|
||||
// If the response body is not a JSON, then abandon ship.
|
||||
if ( empty( $response_body ) || ! json_decode( $response_body ) ) {
|
||||
return array(
|
||||
'error' => __( 'The ZipWP API server encountered an error.', 'astra-sites' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Return the response body.
|
||||
return json_decode( $response_body, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decrypted token from the Zip AI Settings.
|
||||
*
|
||||
* @param string $token_name The name of the token.
|
||||
* @since 1.1.2
|
||||
* @return string The decrypted token.
|
||||
*/
|
||||
private static function get_decrypted_token( $token_name ) {
|
||||
// Get the Zip AI Settings.
|
||||
$zip_ai_token = self::get_setting( $token_name );
|
||||
|
||||
// Return early if the ZipWP token is not set.
|
||||
if ( empty( $zip_ai_token ) || ! is_string( $zip_ai_token ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Return the decrypted ZipWP token.
|
||||
return ! empty( trim( $zip_ai_token ) ) ? Utils::decrypt( $zip_ai_token ) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decrypted auth token.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return string The decrypted auth token.
|
||||
*/
|
||||
public static function get_decrypted_auth_token() {
|
||||
return self::get_decrypted_token( 'auth_token' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decrypted ZipWP token.
|
||||
*
|
||||
* @since 1.1.2
|
||||
* @return string The decrypted ZipWP token.
|
||||
*/
|
||||
public static function get_decrypted_zipwp_token() {
|
||||
return self::get_decrypted_token( 'zip_token' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This helper function returns credit details.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return array
|
||||
*/
|
||||
public static function get_credit_details() {
|
||||
// Set the default credit details.
|
||||
$credit_details = array(
|
||||
'used' => 0,
|
||||
'total' => 0,
|
||||
'threshold' => array(
|
||||
'medium' => ZIP_AI_CREDIT_THRESHOLD_MEDIUM,
|
||||
'high' => ZIP_AI_CREDIT_THRESHOLD_HIGH,
|
||||
),
|
||||
'percentage' => 0,
|
||||
'status' => 'success',
|
||||
);
|
||||
|
||||
// Get the response from the endpoint.
|
||||
$response = self::get_credit_server_response( 'usage' );
|
||||
|
||||
// If the response is not an error, then update the credit details.
|
||||
if (
|
||||
empty( $response['error'] )
|
||||
&& ! empty( $response['total_credits'] )
|
||||
) {
|
||||
$credit_details['used'] = ! empty( $response['total_used_credits'] ) ? $response['total_used_credits'] : 0;
|
||||
$credit_details['total'] = $response['total_credits'];
|
||||
$credit_details['percentage'] = intval( ( $credit_details['used'] / $credit_details['total'] ) * 100 );
|
||||
} else {
|
||||
$credit_details['status'] = 'error';
|
||||
}
|
||||
|
||||
return $credit_details;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper function returns the current plan details.
|
||||
*
|
||||
* @since 1.1.2
|
||||
* @return array
|
||||
*/
|
||||
public static function get_current_plan_details() {
|
||||
$current_plan_details = [];
|
||||
|
||||
// Get the response from the endpoint.
|
||||
$response = self::get_zipwp_api_response( 'plan/current-plan' );
|
||||
|
||||
// If the response is not an error, then use it - else create an error response array.
|
||||
if ( empty( $response['error'] ) && is_array( $response ) ) {
|
||||
$current_plan_details = $response;
|
||||
if ( empty( $current_plan_details['status'] ) ) {
|
||||
$current_plan_details['status'] = 'ok';
|
||||
}
|
||||
} else {
|
||||
$current_plan_details['status'] = 'error';
|
||||
if ( ! empty( $response['error'] ) ) {
|
||||
$current_plan_details['error'] = $response['error'];
|
||||
}
|
||||
}
|
||||
|
||||
return $current_plan_details;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authorization middleware url.
|
||||
*
|
||||
* @param array $params An array of parameters to add to the middleware URL.
|
||||
* @since 1.0.0
|
||||
* @return string The authorization middleware url.
|
||||
*/
|
||||
public static function get_auth_middleware_url( $params = [] ) {
|
||||
|
||||
// Create the Redirect URL.
|
||||
$redirect_url = add_query_arg(
|
||||
array(
|
||||
'nonce' => wp_create_nonce( 'zip_ai_auth_nonce' ),
|
||||
'scs-authorize' => 'true',
|
||||
),
|
||||
admin_url()
|
||||
);
|
||||
|
||||
// Create the Authentication URL.
|
||||
$auth_url = add_query_arg(
|
||||
apply_filters(
|
||||
'zip_ai_auth_middleware_args',
|
||||
array(
|
||||
'type' => 'token',
|
||||
'redirect_url' => rawurlencode( $redirect_url ),
|
||||
)
|
||||
),
|
||||
ZIP_AI_MIDDLEWARE
|
||||
);
|
||||
|
||||
// Add the plugin param if passed.
|
||||
if ( ! empty( $params['plugin'] ) && is_string( $params['plugin'] ) ) {
|
||||
$auth_url = add_query_arg(
|
||||
'plugin',
|
||||
sanitize_text_field( $params['plugin'] ),
|
||||
$auth_url
|
||||
);
|
||||
}
|
||||
|
||||
// Add the source param if passed.
|
||||
if ( ! empty( $params['source'] ) && is_string( $params['source'] ) ) {
|
||||
$auth_url = add_query_arg(
|
||||
'source',
|
||||
sanitize_text_field( $params['source'] ),
|
||||
$auth_url
|
||||
);
|
||||
}
|
||||
|
||||
// Add the affiliate param if passed.
|
||||
$affiliate = get_option( 'zipwp_partner_url_param', '' );
|
||||
$affiliate = is_string( $affiliate ) ? sanitize_text_field( $affiliate ) : '';
|
||||
|
||||
if ( ! empty( $affiliate ) ) {
|
||||
$auth_url = add_query_arg(
|
||||
'aff',
|
||||
$affiliate,
|
||||
$auth_url
|
||||
);
|
||||
}
|
||||
|
||||
return $auth_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the revoke url for the auth token.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return string The authorization revoke url.
|
||||
*/
|
||||
public static function get_auth_revoke_url() {
|
||||
$revoke_url = add_query_arg(
|
||||
apply_filters(
|
||||
'zip_ai_auth_revoke_args',
|
||||
array(
|
||||
array(
|
||||
'nonce' => wp_create_nonce( 'zip_ai_auth_nonce' ),
|
||||
'revoke_zip_ai_authorization_token' => 'definitely',
|
||||
),
|
||||
admin_url(),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return $revoke_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
/**
|
||||
* Zip AI - Module.
|
||||
*
|
||||
* This file is used to register and manage the Zip AI Modules.
|
||||
*
|
||||
* @package zip-ai
|
||||
*/
|
||||
|
||||
namespace ZipAI\Classes;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Classes to be used, in alphabetical order.
|
||||
use ZipAI\Classes\Helper;
|
||||
|
||||
/**
|
||||
* The Module Class.
|
||||
*/
|
||||
class Module {
|
||||
/**
|
||||
* Private Variable of all the valid Zip AI Modules.
|
||||
*
|
||||
* @since 1.0.5
|
||||
* @var array $valid_modules Array of all the available Zip AI Modules.
|
||||
*/
|
||||
private static $valid_modules = [
|
||||
'ai_assistant',
|
||||
'ai_design_copilot',
|
||||
];
|
||||
|
||||
/**
|
||||
* Update the status of Zip AI Module(s).
|
||||
*
|
||||
* @param string|array $module_name Name of the module or an array of module names.
|
||||
* @param string $status Status of the module(s) to be updated.
|
||||
* @since 1.0.5
|
||||
* @return boolean True if Zip AI Module(s) status has been updated, false otherwise.
|
||||
*/
|
||||
private static function update_status( $module_name, $status ) {
|
||||
// If the status is not a valid status, return.
|
||||
if ( ! in_array( $status, [ 'enabled', 'disabled' ], true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the module name is a string, format it into an array.
|
||||
if ( is_string( $module_name ) && ! empty( trim( $module_name ) ) ) {
|
||||
$module_name = [ $module_name ];
|
||||
} elseif ( ! is_array( $module_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all the modules.
|
||||
$all_modules = self::get_all_modules();
|
||||
|
||||
// Ensure that the modules that are to be updated are valid.
|
||||
$module_name = array_intersect( array_keys( $all_modules ), $module_name );
|
||||
|
||||
// Modules from DB is an array of arrays, where the keys are the module names, and the values are an array of module data.
|
||||
// We need to update all the modules that are passed in the $module_name array, making their status as $status.
|
||||
array_walk(
|
||||
$all_modules,
|
||||
function( &$module, $module_key ) use ( $module_name, $status ) {
|
||||
// If the module is not in the module name array, return it as it is.
|
||||
if ( ! is_array( $module ) || ! in_array( $module_key, $module_name, true ) ) {
|
||||
return $module;
|
||||
}
|
||||
|
||||
// If the module is in the module name array, update the status.
|
||||
$module['status'] = $status;
|
||||
|
||||
// Return the updated module.
|
||||
return $module;
|
||||
}
|
||||
);
|
||||
|
||||
// Update the modules array.
|
||||
return Helper::update_admin_settings_option( 'zip_ai_modules', $all_modules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to migrate older Zip AI settings into the new modular format.
|
||||
*
|
||||
* @since 1.0.5
|
||||
* @return void
|
||||
*/
|
||||
public static function migrate_options() {
|
||||
// Get the existing Zip AI settings option.
|
||||
$existing_settings = Helper::get_admin_settings_option( 'zip_ai_settings', [] );
|
||||
|
||||
// If the chat enabled option is set, migrate it.
|
||||
if ( isset( $existing_settings['chat_enabled'] ) ) {
|
||||
// Set the new option value based on the chat enabled value.
|
||||
$ai_assistant_status = false === $existing_settings['chat_enabled'] ? 'disabled' : 'enabled';
|
||||
|
||||
// Update the AI assistant module status.
|
||||
$ai_assistant_migrated = self::update_status( 'ai_assistant', $ai_assistant_status );
|
||||
|
||||
// If the migration was successful, unset the chat enabled value and update the settings.
|
||||
if ( $ai_assistant_migrated ) {
|
||||
unset( $existing_settings['chat_enabled'] );
|
||||
Helper::update_admin_settings_option( 'zip_ai_settings', $existing_settings );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get all the availabe Zip AI Modules, after applying the filter.
|
||||
*
|
||||
* First all the filtered modules and the modules from the database will be fetched.
|
||||
* Then the database modules will be cross-checked against the valid filtered modules.
|
||||
* This is done so that even if a value exists in the database, if the product that is adding the filter is disabled, the feature will be considered as non-existent.
|
||||
* Finally the required data from the database will overwrite the filtered defaults, and only the valid modules will be returned for use.
|
||||
*
|
||||
* @since 1.0.5
|
||||
* @return array Array of all the available Zip AI Modules and their details.
|
||||
*/
|
||||
public static function get_all_modules() {
|
||||
$filtered_modules = apply_filters( 'zip_ai_modules', [] );
|
||||
|
||||
// Ensure that the modules are in the correct format.
|
||||
$filtered_modules = is_array( $filtered_modules ) ? $filtered_modules : [];
|
||||
|
||||
// Get the existing Zip AI modules from the DB.
|
||||
$modules_from_db = Helper::get_admin_settings_option( 'zip_ai_modules', [] );
|
||||
|
||||
// Ensure that the modules are in the correct format.
|
||||
$modules_from_db = is_array( $modules_from_db ) ? $modules_from_db : [];
|
||||
|
||||
// Only load the modules from the database that have the same keys as the filtered modules.
|
||||
$modules_from_db = array_intersect_key( $modules_from_db, $filtered_modules );
|
||||
|
||||
// Set the final modules array, where the database values override the filtered values.
|
||||
$filtered_modules = array_merge( $filtered_modules, $modules_from_db );
|
||||
|
||||
// Ensure that only the valid modules are returned.
|
||||
return array_intersect_key( $filtered_modules, array_flip( self::$valid_modules ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Zip AI Module(s).
|
||||
*
|
||||
* If a string is passed, that module will be enabled if valid.
|
||||
* If an array is passed, all valid modules will be enabled.
|
||||
*
|
||||
* @param string|array $module_name Name of the module or an array of module names.
|
||||
* @since 1.0.5
|
||||
* @return boolean True if Zip AI module(s) has been enabled, false otherwise.
|
||||
*/
|
||||
public static function enable( $module_name ) {
|
||||
return self::update_status( $module_name, 'enabled' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to disable Zip AI Module(s).
|
||||
*
|
||||
* If a string is passed, that module will be disabled if valid.
|
||||
* If an array is passed, all valid modules will be disabled.
|
||||
*
|
||||
* @param string|array $module_name Name of the module or an array of module names.
|
||||
* @since 1.0.5
|
||||
* @return boolean True if Zip AI module(s) has been enabled, false otherwise.
|
||||
*/
|
||||
public static function disable( $module_name ) {
|
||||
return self::update_status( $module_name, 'disabled' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check if Zip AI Module is enabled.
|
||||
*
|
||||
* @param string $module_name Name of the module.
|
||||
* @since 1.0.5
|
||||
* @return boolean True if Zip AI is enabled, false otherwise.
|
||||
*/
|
||||
public static function is_enabled( $module_name ) {
|
||||
// If the module name is not a string, abandon ship.
|
||||
if ( ! is_string( $module_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all the modules.
|
||||
$all_modules = self::get_all_modules();
|
||||
|
||||
// If the given module name is not a valid module or if the module does not have a status, abandon ship.
|
||||
if ( ! array_key_exists( $module_name, $all_modules ) || empty( $all_modules[ $module_name ]['status'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return based on whether Zip AI is enabled or not.
|
||||
return 'enabled' === $all_modules[ $module_name ]['status'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the given Zip AI module if it exists, else create and enable it.
|
||||
*
|
||||
* @param array $modules The reference to the modules array that will be modified.
|
||||
* @param string $module_name The module name.
|
||||
* @since 1.1.0
|
||||
* @return void
|
||||
*/
|
||||
public static function force_enabled( &$modules, $module_name ) {
|
||||
if ( empty( $modules[ $module_name ] ) || ! is_array( $modules[ $module_name ] ) ) {
|
||||
$modules[ $module_name ] = array( 'status' => 'enabled' );
|
||||
} else {
|
||||
$modules[ $module_name ]['status'] = 'enabled';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,756 @@
|
||||
<?php
|
||||
/**
|
||||
* Zip AI - Admin Configurations.
|
||||
*
|
||||
* @package zip-ai
|
||||
*/
|
||||
|
||||
namespace ZipAI\Classes;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Classes to be used, in alphabetical order.
|
||||
use ZipAI\Classes\Helper;
|
||||
use ZipAI\Classes\Module;
|
||||
|
||||
/**
|
||||
* The Sidebar_Configurations Class.
|
||||
*/
|
||||
class Sidebar_Configurations {
|
||||
|
||||
/**
|
||||
* The namespace for the Rest Routes.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
private $namespace = 'zip_ai';
|
||||
|
||||
/**
|
||||
* Instance of this class.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var object Class object.
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* Initiator of this class.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return object initialized object of this class.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor of this class.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( ! current_user_can( 'manage_zip_ai_assistant' ) ) {
|
||||
return;
|
||||
}
|
||||
global $wp_version;
|
||||
// Set the priority for loading ZIP AI Adminbar trigger.
|
||||
$admin_trigger_priority = version_compare( $wp_version, '6.6', '<' ) ? 999 : 6;
|
||||
// Setup the Sidebar Rest Routes.
|
||||
add_action( 'rest_api_init', array( $this, 'register_route' ) );
|
||||
add_action( 'admin_bar_menu', array( $this, 'add_admin_trigger' ), $admin_trigger_priority );
|
||||
// Setup the Sidebar Auth Ajax.
|
||||
add_action( 'wp_ajax_verify_zip_ai_authenticity', array( $this, 'verify_authenticity' ) );
|
||||
// Setup the Sidebar Credit Details Ajax.
|
||||
add_action( 'wp_ajax_get_latest_credit_details', array( $this, 'get_latest_credit_details' ) );
|
||||
|
||||
// Render the Sidebar React App in the Footer in the Gutenberg Editor, Admin, and the Front-end.
|
||||
add_action( 'admin_footer', array( $this, 'render_sidebar_markup' ) );
|
||||
add_action( 'wp_footer', array( $this, 'render_sidebar_markup' ) );
|
||||
|
||||
// Add the Sidebar to the Gutenberg Editor, Admin, and the Front-end.
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'load_sidebar_assets' ) );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'load_sidebar_assets' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register All Routes.
|
||||
*
|
||||
* @hooked - rest_api_init
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function register_route() {
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/generate',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'generate_ai_content' ),
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_zip_ai_assistant' );
|
||||
},
|
||||
'args' => array(
|
||||
'use_system_message' => array(
|
||||
'sanitize_callback' => array( $this, 'sanitize_boolean_field' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the value is boolean or not.
|
||||
*
|
||||
* @param mixed $value value to be checked.
|
||||
* @since 1.0.0
|
||||
* @return boolean
|
||||
*/
|
||||
public function sanitize_boolean_field( $value ) {
|
||||
return filter_var( $value, FILTER_VALIDATE_BOOLEAN );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ZIP AI Assistant options.
|
||||
*
|
||||
* @param array $params Parameters for updating options.
|
||||
* @since 1.1.6
|
||||
* @return void
|
||||
*/
|
||||
public function update_zip_ai_assistant_options( $params ) {
|
||||
|
||||
$last_message_tone = '';
|
||||
$last_index = count( $params['message_array'] ) - 1;
|
||||
|
||||
// Find the last match if it exist.
|
||||
for ( $i = $last_index; $i >= 0; $i-- ) {
|
||||
$content = $params['message_array'][ $i ]['content'];
|
||||
|
||||
preg_match( '/Rewrite in a (\w+) tone/', $content, $matches_tone );
|
||||
if ( ! empty( $matches_tone ) && empty( $last_message_tone ) ) {
|
||||
$last_message_tone = $matches_tone[1];
|
||||
}
|
||||
|
||||
// If both language and message tone are found, break the loop.
|
||||
if ( ! empty( $last_message_tone ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$option_name = 'zip_ai_assistant_option';
|
||||
$current_options = array();
|
||||
|
||||
// If options exist, fetch them.
|
||||
if ( get_option( $option_name ) ) {
|
||||
$current_options = get_option( $option_name );
|
||||
}
|
||||
|
||||
if ( ! empty( $last_message_tone ) ) {
|
||||
$current_options['last_used']['changeTone'] = [
|
||||
'value' => $last_message_tone,
|
||||
'label' => __( ucfirst( $last_message_tone ), 'astra-sites' ), //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
|
||||
];
|
||||
}
|
||||
|
||||
// Update options in the database.
|
||||
Helper::update_admin_settings_option( $option_name, $current_options );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches ai data from the middleware server.
|
||||
*
|
||||
* @param \WP_REST_Request $request request object.
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function generate_ai_content( $request ) {
|
||||
|
||||
// Get the params.
|
||||
$params = $request->get_params();
|
||||
|
||||
// Update the ZIP AI Assistant options for last used language and tone.
|
||||
$this->update_zip_ai_assistant_options( $params );
|
||||
|
||||
// If the nessage array doesn't exist, abandon ship.
|
||||
if ( empty( $params['message_array'] ) || ! is_array( $params['message_array'] ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'The message array was not supplied', 'astra-sites' ) ) );
|
||||
}
|
||||
|
||||
// Set the token count to 0, and create messages array.
|
||||
$token_count = 0;
|
||||
$messages = array();
|
||||
|
||||
// Start with the last message - going upwards until the token count hits 2000.
|
||||
foreach ( array_reverse( $params['message_array'] ) as $current_message ) {
|
||||
// If the message content doesn't exist, skip it.
|
||||
if ( empty( $current_message['content'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the token count, and if it's greater than 2000, break out of the loop.
|
||||
$token_count += Helper::get_token_count( $current_message['content'] );
|
||||
if ( $token_count >= 1000 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the message to the start of the messages to send to the SCS Middleware.
|
||||
array_unshift( $messages, $current_message );
|
||||
}
|
||||
|
||||
// Finally add the system message to the start of the array.
|
||||
if ( ! empty( $params['use_system_message'] ) ) {
|
||||
|
||||
// Get the AI training message according to the location of the current page.
|
||||
$initial_messages = self::assign_ai_assistant_purpose( $params );
|
||||
|
||||
foreach ( array_reverse( $initial_messages ) as $initial_message ) {
|
||||
array_unshift(
|
||||
$messages,
|
||||
$initial_message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the required values to send to the middleware server.
|
||||
$endpoint = 'chat/completions';
|
||||
$data = array(
|
||||
'temperature' => 0.7,
|
||||
'top_p' => 1,
|
||||
'frequency_penalty' => 0.8,
|
||||
'presence_penalty' => 1,
|
||||
'messages' => $messages,
|
||||
);
|
||||
|
||||
// Get the response from the endpoint.
|
||||
$response = Helper::get_credit_server_response( $endpoint, $data );
|
||||
|
||||
if ( ! empty( $response['error'] ) ) {
|
||||
// If the response has an error, handle it and report it back.
|
||||
$message = '';
|
||||
if ( ! empty( $response['error']['message'] ) ) { // If any error message received from OpenAI.
|
||||
$message = $response['error']['message'];
|
||||
} elseif ( is_string( $response['error'] ) ) { // If any error message received from server.
|
||||
if ( ! empty( $response['code'] && is_string( $response['code'] ) ) ) {
|
||||
$message = $this->custom_message( $response['code'] );
|
||||
}
|
||||
$message = ! empty( $message ) ? $message : $response['error'];
|
||||
}
|
||||
wp_send_json_error( array( 'message' => $message ) );
|
||||
} elseif ( is_array( $response['choices'] ) && ! empty( $response['choices'][0]['message']['content'] ) ) {
|
||||
// If the message was sent successfully, send it successfully.
|
||||
wp_send_json_success( array( 'message' => $response['choices'][0]['message']['content'] ) );
|
||||
} else {
|
||||
// If you've reached here, then something has definitely gone amuck. Abandon ship.
|
||||
wp_send_json_error( array( 'message' => __( 'Something went wrong', 'astra-sites' ) ) );
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* This function converts the code recieved from scs to a readable error message.
|
||||
* Useful to provide better language for error codes.
|
||||
*
|
||||
* @param string $code error code received from SCS ( Credits server ).
|
||||
* @since 1.0.0
|
||||
* @return string
|
||||
*/
|
||||
private function custom_message( $code ) {
|
||||
$message_array = array(
|
||||
'no_auth' => __( 'Invalid auth token.', 'astra-sites' ),
|
||||
'insufficient_credits' => __( 'You have no credits left.', 'astra-sites' ),
|
||||
);
|
||||
|
||||
return isset( $message_array[ $code ] ) ? $message_array[ $code ] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax handeler to verify the Zip AI authorization.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function verify_authenticity() {
|
||||
|
||||
// Check the nonce.
|
||||
check_ajax_referer( 'zip_ai_ajax_nonce', 'nonce' );
|
||||
|
||||
// Set an array of data to be sent.
|
||||
$required_details = [
|
||||
'is_authorized' => Helper::is_authorized(),
|
||||
];
|
||||
|
||||
// If the user is authorized, get the credit details.
|
||||
if ( $required_details['is_authorized'] ) {
|
||||
$required_details['credit_details'] = Helper::get_credit_details();
|
||||
}
|
||||
|
||||
// Get the current plan details that need to be localized.
|
||||
$response_zipwp_plan = Helper::get_current_plan_details();
|
||||
|
||||
// If the response is not an error, then proceed to localize the required details.
|
||||
if ( is_array( $response_zipwp_plan ) && 'error' !== $response_zipwp_plan['status'] ) {
|
||||
|
||||
// Add the team name if it exists.
|
||||
if ( ! empty( $response_zipwp_plan['team']['name'] ) ) {
|
||||
$required_details['team_name'] = $response_zipwp_plan['team']['name'];
|
||||
}
|
||||
}
|
||||
|
||||
// Send a boolean based on whether the auth token has been added.
|
||||
wp_send_json_success( $required_details );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the AI Asssitant Sidebar assets.
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function load_sidebar_assets() {
|
||||
|
||||
if ( class_exists( '\UAGB_Admin_Helper' ) && method_exists( '\UAGB_Admin_Helper', 'should_exclude_assets_for_cpt' ) ) {
|
||||
if ( \UAGB_Admin_Helper::should_exclude_assets_for_cpt() ) {
|
||||
return; // Early return to prevent loading assets.
|
||||
}
|
||||
}
|
||||
// If the admin bar is not visible, we don't want to load the sidebar assets.
|
||||
if ( ! is_admin_bar_showing() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the required variables.
|
||||
$handle = 'zip-ai-sidebar';
|
||||
$build_path = ZIP_AI_DIR . 'sidebar/build/';
|
||||
$build_url = ZIP_AI_URL . 'sidebar/build/';
|
||||
$script_asset_path = $build_path . 'sidebar-app.asset.php';
|
||||
$script_info = file_exists( $script_asset_path )
|
||||
? include $script_asset_path
|
||||
: array(
|
||||
'dependencies' => array(),
|
||||
'version' => ZIP_AI_VERSION,
|
||||
);
|
||||
|
||||
// If this is in the front-end, remove any editor-specific dependencies.
|
||||
// This will work as intended because the React components for the editor have checks to render the same, leaving no errors.
|
||||
$script_dep = ! is_admin() ? array_diff(
|
||||
$script_info['dependencies'],
|
||||
[
|
||||
'wp-block-editor',
|
||||
'wp-edit-post',
|
||||
'wp-rich-text',
|
||||
]
|
||||
) : $script_info['dependencies'];
|
||||
|
||||
// Resolving conflict with wigdget page query monitor warning.
|
||||
global $pagenow;
|
||||
if ( 'widgets.php' === $pagenow ) {
|
||||
$script_dep = array_diff( $script_info['dependencies'], [ 'wp-edit-post' ] );
|
||||
}
|
||||
// Note that the current screen function is loaded after admin_init, so if it doesn't exist set screen to null.
|
||||
$screen = ( is_admin() && function_exists( 'get_current_screen' ) ) ? get_current_screen() : null;
|
||||
|
||||
// Register the sidebar scripts.
|
||||
wp_register_script(
|
||||
$handle,
|
||||
$build_url . 'sidebar-app.js',
|
||||
$script_dep,
|
||||
$script_info['version'],
|
||||
true
|
||||
);
|
||||
|
||||
// Register the sidebar styles.
|
||||
wp_register_style(
|
||||
$handle,
|
||||
$build_url . 'sidebar-app.css',
|
||||
array(),
|
||||
ZIP_AI_VERSION
|
||||
);
|
||||
|
||||
// Enqueue the sidebar scripts.
|
||||
wp_enqueue_script( $handle );
|
||||
// Set the script translations.
|
||||
wp_set_script_translations( $handle, apply_filters( 'zip_ai_library_textdomain', 'zip-ai' ) );
|
||||
// Enqueue the sidebar styles.
|
||||
wp_enqueue_style( $handle );
|
||||
|
||||
// Create the middleware parameters array and the credit topup URL.
|
||||
$middleware_params = [];
|
||||
$credit_topup_url = esc_url( ZIP_AI_CREDIT_TOPUP_URL );
|
||||
|
||||
// Get the collab product details, and extract the slug from there if it exists.
|
||||
$collab_product_details = apply_filters( 'zip_ai_collab_product_details', null );
|
||||
|
||||
// If the collab details is an array and has the plugin slug, add it to the middleware params.
|
||||
if ( is_array( $collab_product_details )
|
||||
&& ! empty( $collab_product_details['product_slug'] )
|
||||
&& is_string( $collab_product_details['product_slug'] )
|
||||
) {
|
||||
$middleware_params['plugin'] = sanitize_text_field( $collab_product_details['product_slug'] );
|
||||
|
||||
// Also update the plugin as the source param for the Get Credits URL.
|
||||
$credit_topup_url = esc_url( add_query_arg( 'source', $collab_product_details['product_slug'], ZIP_AI_CREDIT_TOPUP_URL ) );
|
||||
}
|
||||
|
||||
// Get the current plan details that need to be localized.
|
||||
$response_zipwp_plan = Helper::get_current_plan_details();
|
||||
$current_zipwp_plan = array();
|
||||
|
||||
// If the response is not an error, then proceed to localize the required details.
|
||||
if ( is_array( $response_zipwp_plan ) && 'error' !== $response_zipwp_plan['status'] ) {
|
||||
|
||||
// Add the team name if it exists.
|
||||
if ( ! empty( $response_zipwp_plan['team']['name'] ) ) {
|
||||
$current_zipwp_plan['team_name'] = $response_zipwp_plan['team']['name'];
|
||||
}
|
||||
}
|
||||
|
||||
// Get the ID based on the current URL - this will avoid incorrectly getting popups as the page.
|
||||
$current_url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$post_id = url_to_postid( set_url_scheme( $current_url ) );
|
||||
// If this is an editor page, this won't work - so if it doesn't, try getting the ID.
|
||||
if ( empty( $post_id ) ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
// Identify the special page if required.
|
||||
$special_page;
|
||||
switch ( true ) {
|
||||
case ( function_exists( 'is_shop' ) && is_shop() ):
|
||||
$special_page = 'shop';
|
||||
break;
|
||||
case ( function_exists( 'is_cart' ) && is_cart() ):
|
||||
$special_page = 'cart';
|
||||
break;
|
||||
case ( function_exists( 'is_checkout' ) && is_checkout() ):
|
||||
$special_page = 'checkout';
|
||||
break;
|
||||
default:
|
||||
$special_page = null;
|
||||
}
|
||||
|
||||
// Set the current view - this will determine what the initial prompts should be.
|
||||
$current_view = 'default';
|
||||
|
||||
// If you can get the current screen ( alluding to the fact that you're in the admin pages ), then proceed.
|
||||
if ( function_exists( 'get_current_screen' ) ) {
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
// Check if this a WooCommerce product edit page.
|
||||
if (
|
||||
isset( $current_screen->base )
|
||||
&& isset( $current_screen->id )
|
||||
&& 'post' === $current_screen->base
|
||||
&& 'product' === $current_screen->id
|
||||
) {
|
||||
$current_view = 'editing_product';
|
||||
}
|
||||
}
|
||||
// Localize the script required for the Zip AI Sidebar.
|
||||
wp_localize_script(
|
||||
$handle,
|
||||
'zip_ai_react',
|
||||
array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'ajax_nonce' => wp_create_nonce( 'zip_ai_ajax_nonce' ),
|
||||
'admin_nonce' => wp_create_nonce( 'zip_ai_admin_nonce' ),
|
||||
'site_url' => get_site_url(),
|
||||
'current_post_id' => $post_id,
|
||||
'special_page' => $special_page,
|
||||
'is_admin' => is_admin(),
|
||||
'auth_middleware' => Helper::get_auth_middleware_url( $middleware_params ),
|
||||
'is_authorized' => Helper::is_authorized(),
|
||||
'is_ai_assistant_enabled' => Module::is_enabled( 'ai_assistant' ),
|
||||
'is_customize_preview' => is_customize_preview(),
|
||||
'collab_product_details' => $collab_product_details,
|
||||
'zip_ai_assistant_options' => get_option( 'zip_ai_assistant_option' ),
|
||||
'is_widgets_page' => $screen->id ?? null,
|
||||
'current_status' => Helper::get_setting( 'status' ),
|
||||
'current_plan_details' => $current_zipwp_plan,
|
||||
'current_view' => $current_view,
|
||||
'credit_details' => Helper::get_credit_details(),
|
||||
'credit_topup_url' => $credit_topup_url,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Zip AI Assistant Sidebar to the admin bar.
|
||||
*
|
||||
* @param object $admin_bar The admin bar object.
|
||||
* @since 1.1.0
|
||||
* @return void
|
||||
*/
|
||||
public function add_admin_trigger( $admin_bar ) {
|
||||
if ( class_exists( '\UAGB_Admin_Helper' ) && method_exists( '\UAGB_Admin_Helper', 'should_exclude_assets_for_cpt' ) ) {
|
||||
if ( \UAGB_Admin_Helper::should_exclude_assets_for_cpt() ) {
|
||||
return; // Early return to prevent loading assets.
|
||||
}
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'id' => 'zip-ai-assistant',
|
||||
'title' => '<span class="ab-icon" aria-hidden="true" style="margin: 0">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M9.8132 15.9038L9 18.75L8.1868 15.9038C7.75968 14.4089 6.59112 13.2403 5.09619 12.8132L2.25 12L5.09619 11.1868C6.59113 10.7597 7.75968 9.59112 8.1868 8.09619L9 5.25L9.8132 8.09619C10.2403 9.59113 11.4089 10.7597 12.9038 11.1868L15.75 12L12.9038 12.8132C11.4089 13.2403 10.2403 14.4089 9.8132 15.9038Z" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"></path><path d="M16.8942 20.5673L16.5 21.75L16.1058 20.5673C15.8818 19.8954 15.3546 19.3682 14.6827 19.1442L13.5 18.75L14.6827 18.3558C15.3546 18.1318 15.8818 17.6046 16.1058 16.9327L16.5 15.75L16.8942 16.9327C17.1182 17.6046 17.6454 18.1318 18.3173 18.3558L19.5 18.75L18.3173 19.1442C17.6454 19.3682 17.1182 19.8954 16.8942 20.5673Z" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"></path><path d="M18.2589 8.71454L18 9.75L17.7411 8.71454C17.4388 7.50533 16.4947 6.56117 15.2855 6.25887L14.25 6L15.2855 5.74113C16.4947 5.43883 17.4388 4.49467 17.7411 3.28546L18 2.25L18.2589 3.28546C18.5612 4.49467 19.5053 5.43883 20.7145 5.74113L21.75 6L20.7145 6.25887C19.5053 6.56117 18.5612 7.50532 18.2589 8.71454Z" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
||||
</span>',
|
||||
'href' => 'javascript:void(0);',
|
||||
'parent' => 'top-secondary',
|
||||
);
|
||||
$admin_bar->add_node( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the AI Assistant Sidebar markup.
|
||||
*
|
||||
* @since 1.1.0
|
||||
* @return void
|
||||
*/
|
||||
public static function render_sidebar_markup() {
|
||||
|
||||
if ( class_exists( '\UAGB_Admin_Helper' ) && method_exists( '\UAGB_Admin_Helper', 'should_exclude_assets_for_cpt' ) ) {
|
||||
if ( \UAGB_Admin_Helper::should_exclude_assets_for_cpt() ) {
|
||||
return; // Early return to prevent loading assets.
|
||||
}
|
||||
}
|
||||
|
||||
// If the adminbar is visible on this screen, render the admin trigger.
|
||||
if ( is_admin_bar_showing() ) {
|
||||
?>
|
||||
<div id="zip-ai-sidebar-admin-trigger"></div>
|
||||
<?php
|
||||
}
|
||||
// Render the sidebar div.
|
||||
?>
|
||||
<div id="zip-ai-sidebar"></div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the purpose of the AI Assistant given the current page.
|
||||
*
|
||||
* @param array<mixed> $params An array of all the parameters.
|
||||
* @since 2.0.0
|
||||
* @return array<array<string,string>> An array all the required system messages.
|
||||
*/
|
||||
public static function assign_ai_assistant_purpose( $params ) {
|
||||
// Get the site details.
|
||||
$site_details = [];
|
||||
|
||||
if ( ! empty( trim( get_bloginfo( 'name' ) ) ) ) {
|
||||
$site_details['name'] = esc_html( get_bloginfo( 'name' ) );
|
||||
}
|
||||
if ( ! empty( trim( get_bloginfo( 'description' ) ) ) ) {
|
||||
$site_details['description'] = esc_html( get_bloginfo( 'description' ) );
|
||||
}
|
||||
|
||||
// If there are ZipWP details, overwrite the default details with the improved ones.
|
||||
$zipwp_details = get_option( 'zipwp_user_business_details', '' );
|
||||
if ( is_array( $zipwp_details ) ) {
|
||||
if ( ! empty( $zipwp_details['business_name'] ) && is_string( $zipwp_details['business_name'] ) && ! empty( trim( $zipwp_details['business_name'] ) ) ) {
|
||||
$site_details['name'] = esc_html( $zipwp_details['business_name'] );
|
||||
}
|
||||
if ( ! empty( $zipwp_details['business_description'] ) && is_string( $zipwp_details['business_description'] ) && ! empty( trim( $zipwp_details['business_description'] ) ) ) {
|
||||
$site_details['description'] = esc_html( $zipwp_details['business_description'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Create the site detail message based on whether the name, description, both, or none are set.
|
||||
$site_detail_message = '';
|
||||
if ( ! empty( $site_details['name'] ) && ! empty( $site_details['description'] ) ) {
|
||||
$site_detail_message = 'The name of my site is "' . $site_details['name'] . '" and the tagline/description of my site is "' . $site_details['description'] . '".';
|
||||
} elseif ( ! empty( $site_details['name'] ) ) {
|
||||
$site_detail_message = 'The name of my site is "' . $site_details['name'] . '".';
|
||||
} elseif ( ! empty( $site_details['description'] ) ) {
|
||||
$site_detail_message = 'The tagline/description of my site is "' . $site_details['description'] . '".';
|
||||
}
|
||||
|
||||
// Create the default website-containing message so that links can be created.
|
||||
$website_detail_message = 'When helping me with something that needs me to log in to my WordPress dashboard, generate the exact URL of the page I need to go to at the end of the message. My website is \'example.com\'. Make sure all URLs contain the link text in square brackets, and the URL in round brackets.';
|
||||
|
||||
// Set the common content that will be used for all cases.
|
||||
$appended_common_rule = '\n\n\nYou can help me with everything I need even if it is not related to my site. You will only generate content for what you are asked.';
|
||||
|
||||
// All the role setting messages.
|
||||
$role_settings_content = [
|
||||
'default' => 'You are my AI Assistant. You are a content writer that writes content for my website.' . $appended_common_rule,
|
||||
'wordpress_assistant' => 'You are my WordPress Assistant. You know everything about improving and optimizing my WordPress website for my visitors.' . $appended_common_rule,
|
||||
'e_commerce_expert' => 'You are my WordPress E-commerce Expert. You know everything about improving and optimizing my E-Commerce website for my customers.' . $appended_common_rule,
|
||||
];
|
||||
|
||||
// Create an array for all the system messages.
|
||||
$page_based_system_messages = [];
|
||||
|
||||
// First determine if you're on any post.
|
||||
if ( ! empty( $params['current_post_id'] ) && is_numeric( $params['current_post_id'] ) ) {
|
||||
// Get the required details based on the ID.
|
||||
$page_details = self::get_page_details( $params['current_post_id'] );
|
||||
$page_post_type = get_post_type( $params['current_post_id'] );
|
||||
|
||||
// Check if the current page is a WooCommerce product.
|
||||
$this_is_a_product_page = 'product' === $page_post_type;
|
||||
|
||||
// Set the role based on the page type.
|
||||
if ( $this_is_a_product_page ) {
|
||||
// Set the role of an E-commerce expert.
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $role_settings_content['e_commerce_expert'] ) );
|
||||
if ( ! empty( $site_detail_message ) ) {
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $site_detail_message ) );
|
||||
}
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( 'This is a product page.' ) );
|
||||
} else {
|
||||
// Set the role of a WordPress expert.
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $role_settings_content['wordpress_assistant'] ) );
|
||||
if ( ! empty( $site_detail_message ) ) {
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $site_detail_message ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Add the page details.
|
||||
$page_detail_message = 'These are the details of the current page that you and I are on, in case you are asked something about it\n\n\nPage ID: `' . $params['current_post_id'] . '`\nTitle: `' . $page_details['title'] . '`\nContent:`' . $page_details['content'] . '`';
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $page_detail_message ) );
|
||||
|
||||
// Add the website based message.
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $website_detail_message ) );
|
||||
|
||||
return $page_based_system_messages;
|
||||
} elseif ( ! empty( $params['special_page'] ) && is_string( $params['special_page'] ) ) {
|
||||
// Set the role of an E-commerce expert.
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $role_settings_content['e_commerce_expert'] ) );
|
||||
if ( ! empty( $site_detail_message ) ) {
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $site_detail_message ) );
|
||||
}
|
||||
|
||||
$special_page_id;
|
||||
switch ( $params['special_page'] ) {
|
||||
case 'shop':
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( 'This is my shop page.' ) );
|
||||
$special_page_id = get_option( 'woocommerce_shop_page_id' );
|
||||
break;
|
||||
case 'cart':
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( 'This is the cart page.' ) );
|
||||
$special_page_id = get_option( 'woocommerce_cart_page_id' );
|
||||
break;
|
||||
case 'checkout':
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( 'This is the checkout page.' ) );
|
||||
$special_page_id = get_option( 'woocommerce_checkout_page_id' );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! empty( $special_page_id ) && is_numeric( $special_page_id ) ) {
|
||||
$page_details = self::get_page_details( $special_page_id );
|
||||
$page_detail_message = 'These are the details of the current page that you and I are on, in case you are asked something about it\n\n\nPage ID: `' . $special_page_id . '`\nTitle: `' . $page_details['title'] . '`\nContent:`' . $page_details['content'] . '`';
|
||||
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $page_detail_message ) );
|
||||
}
|
||||
|
||||
// Add the website based message.
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $website_detail_message ) );
|
||||
|
||||
return $page_based_system_messages;
|
||||
|
||||
}
|
||||
|
||||
// If you're not on a post, then the assistant is a WordPress based expert.
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $role_settings_content['wordpress_assistant'] ) );
|
||||
// Add the site details message if required.
|
||||
if ( ! empty( $site_detail_message ) ) {
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $site_detail_message ) );
|
||||
}
|
||||
// Add the website based message.
|
||||
array_push( $page_based_system_messages, self::get_formatted_system_role( $website_detail_message ) );
|
||||
|
||||
return $page_based_system_messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the required page details for AI from the given post ID.
|
||||
*
|
||||
* @param int $current_post_id The current post ID.
|
||||
* @since 2.0.0
|
||||
* @return array<string,mixed> An array of all the required Post details.
|
||||
*/
|
||||
public static function get_page_details( $current_post_id ) {
|
||||
// Regular expression to match opening or closing tags.
|
||||
$tag_regex = '/(<\/?[a-zA-Z]+[^>]*>|<\/?[a-zA-Z]+[^>]*>)/';
|
||||
|
||||
// Get all the required details of the current post.
|
||||
$page_title = get_post_field( 'post_title', $current_post_id );
|
||||
$page_content = get_post_field( 'post_content', $current_post_id );
|
||||
$page_url = get_permalink( $current_post_id );
|
||||
|
||||
// Replace the Page URL with the dummy.
|
||||
$page_url = str_replace( preg_replace( '#^https?://#', '', get_site_url() ), 'example.com', $page_url );
|
||||
|
||||
// Split the post content based to put all tags and content on new lines.
|
||||
$content_parts = preg_split( $tag_regex, $page_content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
|
||||
|
||||
// If any part is a tag, delete it.
|
||||
$content_parts = array_filter(
|
||||
$content_parts,
|
||||
function ( $content_part ) {
|
||||
// Only return true for elements that are not tags, or elements that aren't just neewline characters.
|
||||
return (
|
||||
( false === str_starts_with( $content_part, '<' ) )
|
||||
&& ( false === str_starts_with( $content_part, "\n" ) )
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Combine all the parts into a single string with line breaks.
|
||||
$page_content = implode( "\n", $content_parts );
|
||||
$page_content = preg_replace( '/\n{2,}/', "\n", $page_content );
|
||||
|
||||
// Return the required details.
|
||||
return [
|
||||
'title' => $page_title,
|
||||
'content' => $page_content,
|
||||
'url' => $page_url,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* A small private function to take in any given content, and return a formatted array for OpenAI as a system message.
|
||||
*
|
||||
* @param string $content The content to be put as the message.
|
||||
* @param string $role The role of the message, as per OpenAI standards.
|
||||
* @since 2.0.0
|
||||
* @return array<string,mixed> An array containing the role and content of the message.
|
||||
*/
|
||||
private static function get_formatted_system_role( $content, $role = 'system' ) {
|
||||
return [
|
||||
'role' => $role,
|
||||
'content' => $content,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax handeler to get the latest Zip AI credit details.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function get_latest_credit_details() {
|
||||
// Check the nonce.
|
||||
check_ajax_referer( 'zip_ai_ajax_nonce', 'nonce' );
|
||||
|
||||
// Set an array of data to be sent.
|
||||
$latest_credit_details = Helper::get_credit_details();
|
||||
|
||||
// If an error was encountered, send the error details.
|
||||
if ( isset( $latest_credit_details['status'] ) && 'error' === $latest_credit_details['status'] ) {
|
||||
wp_send_json_error( $latest_credit_details );
|
||||
}
|
||||
|
||||
// Send the latest credit details.
|
||||
wp_send_json_success( $latest_credit_details );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
<?php
|
||||
/**
|
||||
* Zip AI - Token Calculator
|
||||
*
|
||||
* @package zip-ai
|
||||
*/
|
||||
|
||||
namespace ZipAI\Classes;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Token_Calculator Class.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Token_Calculator {
|
||||
/**
|
||||
* Get the GPT encoded tokens.
|
||||
*
|
||||
* @param string $text The text to encode.
|
||||
* @since 1.0.0
|
||||
* @return array The encoded tokens.
|
||||
*/
|
||||
public static function gpt_encode( $text ) {
|
||||
$bpe_tokens = [];
|
||||
// If the text is empty, then abandon ship.
|
||||
if ( empty( $text ) ) {
|
||||
return $bpe_tokens;
|
||||
}
|
||||
// Load the characters.
|
||||
$raw_chars = file_get_contents( ZIP_AI_DIR . 'assets/open-ai/json/characters.json' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
|
||||
$byte_encoder = json_decode( $raw_chars, true );
|
||||
// If the characters are empty, then abandon ship.
|
||||
if ( empty( $byte_encoder ) ) {
|
||||
return $bpe_tokens;
|
||||
}
|
||||
// Load the encoder.
|
||||
$rencoder = file_get_contents( ZIP_AI_DIR . 'assets/open-ai/json/encoder.json' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
|
||||
$encoder = json_decode( $rencoder, true );
|
||||
// If the encoder is empty, then abandon ship.
|
||||
if ( empty( $encoder ) ) {
|
||||
return $bpe_tokens;
|
||||
}
|
||||
// Load the vocabulary.
|
||||
$bpe_file = file_get_contents( ZIP_AI_DIR . 'assets/open-ai/json/vocab.bpe' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
|
||||
// If the vocabulary is empty, then abandon ship.
|
||||
if ( empty( $bpe_file ) ) {
|
||||
return $bpe_tokens;
|
||||
}
|
||||
// Match the text with the regex.
|
||||
preg_match_all( "#'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+#u", $text, $matches );
|
||||
// If the matches are empty, then abandon ship.
|
||||
if ( ! isset( $matches[0] ) || 0 === count( $matches[0] ) ) {
|
||||
return $bpe_tokens;
|
||||
}
|
||||
// Load the BPE merges.
|
||||
$lines = preg_split( '/\r\n|\r|\n/', $bpe_file );
|
||||
$bpe_merges = [];
|
||||
$bpe_merges_temp = array_slice( $lines, 1, count( $lines ), true );
|
||||
foreach ( $bpe_merges_temp as $bmt ) {
|
||||
$split_bmt = preg_split( '#(\s+)#', $bmt );
|
||||
$split_bmt = array_filter( $split_bmt, [ 'ZipAI\Classes\Token_Calculator', 'gpt_filter' ] );
|
||||
if ( count( $split_bmt ) > 0 ) {
|
||||
$bpe_merges[] = $split_bmt;
|
||||
}
|
||||
}
|
||||
// Load the BPE ranks.
|
||||
$bpe_ranks = self::gpt_dict_zip( $bpe_merges, range( 0, count( $bpe_merges ) - 1 ) );
|
||||
$cache = [];
|
||||
// Loop through the matches.
|
||||
foreach ( $matches[0] as $token ) {
|
||||
$new_tokens = [];
|
||||
$chars = [];
|
||||
$token = self::gpt_utf8_encode( $token );
|
||||
// Either use mb_strlen to get the length of the token in UTF-8 or use str_split.
|
||||
// This is for backwards compatibility.
|
||||
if ( function_exists( 'mb_strlen' ) ) {
|
||||
$len = mb_strlen( $token, 'UTF-8' );
|
||||
for ( $i = 0; $i < $len; $i++ ) {
|
||||
$chars[] = mb_substr( $token, $i, 1, 'UTF-8' );
|
||||
}
|
||||
} else {
|
||||
$chars = str_split( $token );
|
||||
}
|
||||
$result_word = '';
|
||||
// Loop through the characters and encode them.
|
||||
foreach ( $chars as $char ) {
|
||||
if ( isset( $byte_encoder[ self::gpt_unichr( $char ) ] ) ) {
|
||||
$result_word .= $byte_encoder[ self::gpt_unichr( $char ) ];
|
||||
}
|
||||
}
|
||||
// Encode the BPE.
|
||||
$new_tokens_bpe = self::gpt_bpe( $result_word, $bpe_ranks, $cache );
|
||||
$new_tokens_bpe = explode( ' ', $new_tokens_bpe );
|
||||
// Loop through the BPE tokens and encode them.
|
||||
foreach ( $new_tokens_bpe as $x ) {
|
||||
if ( isset( $encoder[ $x ] ) ) {
|
||||
if ( isset( $new_tokens[ $x ] ) ) {
|
||||
$new_tokens[ wp_rand() . '---' . $x ] = $encoder[ $x ];
|
||||
} else {
|
||||
$new_tokens[ $x ] = $encoder[ $x ];
|
||||
}
|
||||
} else {
|
||||
if ( isset( $new_tokens[ $x ] ) ) {
|
||||
$new_tokens[ wp_rand() . '---' . $x ] = $x;
|
||||
} else {
|
||||
$new_tokens[ $x ] = $x;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Loop through the new tokens and add them to the BPE tokens.
|
||||
foreach ( $new_tokens as $ninx => $nval ) {
|
||||
if ( isset( $bpe_tokens[ $ninx ] ) ) {
|
||||
$bpe_tokens[ wp_rand() . '---' . $ninx ] = $nval;
|
||||
} else {
|
||||
$bpe_tokens[ $ninx ] = $nval;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the encoded BPE tokens.
|
||||
return $bpe_tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ranks of the BPE merges.
|
||||
*
|
||||
* @param array $x The BPE merges.
|
||||
* @param array $y The range.
|
||||
* @since 1.0.0
|
||||
* @return array The ranks.
|
||||
*/
|
||||
public static function gpt_dict_zip( $x, $y ) {
|
||||
$result = [];
|
||||
$cnt = 0;
|
||||
foreach ( $x as $i ) {
|
||||
if ( isset( $i[1] ) && isset( $i[0] ) ) {
|
||||
$result[ $i[0] . ',' . $i[1] ] = $cnt;
|
||||
$cnt++;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UTF-8 character of the given string/token.
|
||||
*
|
||||
* @param string $str The string/token.
|
||||
* @since 1.0.0
|
||||
* @return string The UTF-8 character.
|
||||
*/
|
||||
public static function gpt_utf8_encode( $str ) {
|
||||
$str .= $str;
|
||||
$len = strlen( $str );
|
||||
for ( $i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j ) {
|
||||
switch ( true ) {
|
||||
case $str[ $i ] < "\x80":
|
||||
$str[ $j ] = $str[ $i ];
|
||||
break;
|
||||
case $str[ $i ] < "\xC0":
|
||||
$str[ $j ] = "\xC2";
|
||||
$str[ ++$j ] = $str[ $i ];
|
||||
break;
|
||||
default:
|
||||
$str[ $j ] = "\xC3";
|
||||
$str[ ++$j ] = chr( ord( $str[ $i ] ) - 64 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return substr( $str, 0, $j );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the byte size of the given character.
|
||||
*
|
||||
* @param string $c The character.
|
||||
* @since 1.0.0
|
||||
* @return int The byte size.
|
||||
*/
|
||||
public static function gpt_unichr( $c ) {
|
||||
if ( ord( $c[0] ) >= 0 && ord( $c[0] ) <= 127 ) {
|
||||
return ord( $c[0] );
|
||||
}
|
||||
if ( ord( $c[0] ) >= 192 && ord( $c[0] ) <= 223 ) {
|
||||
return ( ord( $c[0] ) - 192 ) * 64 + ( ord( $c[1] ) - 128 );
|
||||
}
|
||||
if ( ord( $c[0] ) >= 224 && ord( $c[0] ) <= 239 ) {
|
||||
return ( ord( $c[0] ) - 224 ) * 4096 + ( ord( $c[1] ) - 128 ) * 64 + ( ord( $c[2] ) - 128 );
|
||||
}
|
||||
if ( ord( $c[0] ) >= 240 && ord( $c[0] ) <= 247 ) {
|
||||
return ( ord( $c[0] ) - 240 ) * 262144 + ( ord( $c[1] ) - 128 ) * 4096 + ( ord( $c[2] ) - 128 ) * 64 + ( ord( $c[3] ) - 128 );
|
||||
}
|
||||
if ( ord( $c[0] ) >= 248 && ord( $c[0] ) <= 251 ) {
|
||||
return ( ord( $c[0] ) - 248 ) * 16777216 + ( ord( $c[1] ) - 128 ) * 262144 + ( ord( $c[2] ) - 128 ) * 4096 + ( ord( $c[3] ) - 128 ) * 64 + ( ord( $c[4] ) - 128 );
|
||||
}
|
||||
if ( ord( $c[0] ) >= 252 && ord( $c[0] ) <= 253 ) {
|
||||
return ( ord( $c[0] ) - 252 ) * 1073741824 + ( ord( $c[1] ) - 128 ) * 16777216 + ( ord( $c[2] ) - 128 ) * 262144 + ( ord( $c[3] ) - 128 ) * 4096 + ( ord( $c[4] ) - 128 ) * 64 + ( ord( $c[5] ) - 128 );
|
||||
}
|
||||
if ( ord( $c[0] ) >= 254 && ord( $c[0] ) <= 255 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encoded BPE tokens.
|
||||
*
|
||||
* @param string $token The token.
|
||||
* @param array $bpe_ranks The BPE ranks.
|
||||
* @param array $cache The cache.
|
||||
*/
|
||||
public static function gpt_bpe( $token, $bpe_ranks, &$cache ) {
|
||||
// Check if the token is in the cache.
|
||||
if ( array_key_exists( $token, $cache ) ) {
|
||||
return $cache[ $token ];
|
||||
}
|
||||
// Split the token into UTF-8 characters.
|
||||
$word = self::gpt_split( $token );
|
||||
$init_len = count( $word );
|
||||
$pairs = self::gpt_get_pairs( $word );
|
||||
// If there are no pairs, return the token.
|
||||
if ( ! $pairs ) {
|
||||
return $token;
|
||||
}
|
||||
// Loop through the pairs.
|
||||
while ( true ) {
|
||||
$min_pairs = [];
|
||||
// Get the minimum pair.
|
||||
foreach ( $pairs as $pair ) {
|
||||
if ( array_key_exists( $pair[0] . ',' . $pair[1], $bpe_ranks ) ) {
|
||||
$rank = $bpe_ranks[ $pair[0] . ',' . $pair[1] ];
|
||||
$min_pairs[ $rank ] = $pair;
|
||||
} else {
|
||||
$min_pairs[ 10e10 ] = $pair;
|
||||
}
|
||||
}
|
||||
// Sort the minimum pairs.
|
||||
ksort( $min_pairs );
|
||||
$min_key = array_key_first( $min_pairs );
|
||||
// Loop through the minimum pairs.
|
||||
foreach ( $min_pairs as $mpi => $mp ) {
|
||||
if ( $mpi < $min_key ) {
|
||||
$min_key = $mpi;
|
||||
}
|
||||
}
|
||||
$bigram = $min_pairs[ $min_key ];
|
||||
// If the bigram is not in the BPE ranks, break.
|
||||
if ( ! array_key_exists( $bigram[0] . ',' . $bigram[1], $bpe_ranks ) ) {
|
||||
break;
|
||||
}
|
||||
$first = $bigram[0];
|
||||
$second = $bigram[1];
|
||||
$new_word = [];
|
||||
$i = 0;
|
||||
$word_length = count( $word );
|
||||
// Loop through the word.
|
||||
while ( $i < $word_length ) {
|
||||
// Get the index of the first bigram.
|
||||
$j = self::gpt_index_of( $word, $first, $i );
|
||||
// If the index is -1, add the rest of the word to the new word and break.
|
||||
if ( -1 === $j ) {
|
||||
$new_word = array_merge( $new_word, array_slice( $word, $i, null, true ) );
|
||||
break;
|
||||
}
|
||||
// If the index is not 0, add the rest of the word to the new word.
|
||||
if ( $i > $j ) {
|
||||
$slicer = [];
|
||||
} elseif ( 0 === $j ) {
|
||||
$slicer = [];
|
||||
} else {
|
||||
$slicer = array_slice( $word, $i, $j - $i, true );
|
||||
}
|
||||
$new_word = array_merge( $new_word, $slicer );
|
||||
// If the length of the new word is greater than the initial length, break.
|
||||
if ( count( $new_word ) > $init_len ) {
|
||||
break;
|
||||
}
|
||||
$i = $j;
|
||||
// If the next character is the second bigram, add the bigram to the new word - otherwise, add the character to the new word.
|
||||
if ( $word[ $i ] === $first && $i < count( $word ) - 1 && $word[ $i + 1 ] === $second ) {
|
||||
array_push( $new_word, $first . $second );
|
||||
$i = $i + 2;
|
||||
} else {
|
||||
array_push( $new_word, $word[ $i ] );
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
// If the new word is the same as the old word, break.
|
||||
if ( $word === $new_word ) {
|
||||
break;
|
||||
}
|
||||
$word = $new_word;
|
||||
$word_length = count( $word );
|
||||
// If the length of the word is 1, break - otherwise, get the pairs.
|
||||
if ( 1 === $word_length ) {
|
||||
break;
|
||||
} else {
|
||||
$pairs = self::gpt_get_pairs( $word );
|
||||
}
|
||||
}
|
||||
$word = implode( ' ', $word );
|
||||
$cache[ $token ] = $word;
|
||||
|
||||
// Return the word.
|
||||
return $word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a string into UTF-8 characters.
|
||||
*
|
||||
* @param string $str The string.
|
||||
* @param int $len The length - default 1.
|
||||
* @since 1.0.0
|
||||
* @return array The UTF-8 characters.
|
||||
*/
|
||||
public static function gpt_split( $str, $len = 1 ) {
|
||||
$arr = [];
|
||||
// Handle backwards compatibility.
|
||||
if ( function_exists( 'mb_strlen' ) ) {
|
||||
$length = mb_strlen( $str, 'UTF-8' );
|
||||
} else {
|
||||
$length = strlen( $str );
|
||||
}
|
||||
|
||||
// Loop through the string characters, forming an array of UTF-8 characters.
|
||||
for ( $i = 0; $i < $length; $i += $len ) {
|
||||
if ( function_exists( 'mb_substr' ) ) {
|
||||
$arr[] = mb_substr( $str, $i, $len, 'UTF-8' );
|
||||
} else {
|
||||
$arr[] = substr( $str, $i, $len );
|
||||
}
|
||||
}
|
||||
|
||||
return $arr;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pairs of a word.
|
||||
*
|
||||
* @param string $word The word.
|
||||
* @since 1.0.0
|
||||
* @return array The pairs.
|
||||
*/
|
||||
public static function gpt_get_pairs( $word ) {
|
||||
$pairs = [];
|
||||
$prev_char = $word[0];
|
||||
$word_length = count( $word );
|
||||
for ( $i = 1; $i < $word_length; $i++ ) {
|
||||
$char = $word[ $i ];
|
||||
$pairs[] = [ $prev_char, $char ];
|
||||
$prev_char = $char;
|
||||
}
|
||||
|
||||
return $pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of a value in an array.
|
||||
*
|
||||
* @param array $arrax The array.
|
||||
* @param string $search_element The value to search for.
|
||||
* @param int $from_index The index to start searching from.
|
||||
* @since 1.0.0
|
||||
* @return int The index.
|
||||
*/
|
||||
public static function gpt_index_of( $arrax, $search_element, $from_index ) {
|
||||
$index = 0;
|
||||
foreach ( $arrax as $index => $value ) {
|
||||
if ( $index < $from_index ) {
|
||||
$index++;
|
||||
|
||||
continue;
|
||||
}
|
||||
if ( $value === $search_element ) {
|
||||
return $index;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a variable.
|
||||
*
|
||||
* @param mixed $var The variable.
|
||||
* @since 1.0.0
|
||||
* @return bool Whether the variable is not null, false, or empty.
|
||||
*/
|
||||
public static function gpt_filter( $var ) {
|
||||
return ! in_array( $var, [ null, false, '' ], true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* Zip AI - Utils.
|
||||
*
|
||||
* This file contains all the utility functions of Zip AI.
|
||||
* Utilities manipulate data and perform actions that are not directly related to the library.
|
||||
*
|
||||
* @package zip-ai
|
||||
*/
|
||||
|
||||
namespace ZipAI\Classes;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Utils Class.
|
||||
*/
|
||||
class Utils {
|
||||
/**
|
||||
* Encrypt data using base64.
|
||||
*
|
||||
* @param string $input The input string which needs to be encrypted.
|
||||
* @since 1.0.0
|
||||
* @return string The encrypted string.
|
||||
*/
|
||||
public static function encrypt( $input ) {
|
||||
// If the input is empty or not a string, then abandon ship.
|
||||
if ( empty( $input ) || ! is_string( $input ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Encrypt the input and return it.
|
||||
$base_64 = base64_encode( $input ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
$encode = rtrim( $base_64, '=' );
|
||||
return $encode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data using base64.
|
||||
*
|
||||
* @param string $input The input string which needs to be decrypted.
|
||||
* @since 1.0.0
|
||||
* @return string The decrypted string.
|
||||
*/
|
||||
public static function decrypt( $input ) {
|
||||
// If the input is empty or not a string, then abandon ship.
|
||||
if ( empty( $input ) || ! is_string( $input ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Decrypt the input and return it.
|
||||
$base_64 = $input . str_repeat( '=', strlen( $input ) % 4 );
|
||||
$decode = base64_decode( $base_64 ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
return $decode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Loader.
|
||||
*
|
||||
* @package zip-ai
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
namespace ZipAI;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Classes to be used, in alphabetical order.
|
||||
use ZipAI\Classes\Admin_Configurations;
|
||||
use ZipAI\Classes\Module;
|
||||
use ZipAI\Classes\Sidebar_Configurations;
|
||||
|
||||
if ( ! class_exists( '\ZipAI\Loader' ) ) {
|
||||
/**
|
||||
* Plugin_Loader
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Loader {
|
||||
|
||||
/**
|
||||
* Instance
|
||||
*
|
||||
* @access private
|
||||
* @var object Class Instance.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* Initiator
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return object initialized object of class.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Autoload classes.
|
||||
*
|
||||
* @param string $class class name.
|
||||
*/
|
||||
public function autoload( $class ) {
|
||||
if ( 0 !== strpos( $class, __NAMESPACE__ ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class_to_load = $class;
|
||||
|
||||
$filename = strtolower(
|
||||
preg_replace(
|
||||
[ '/^' . __NAMESPACE__ . '\\\/', '/([a-z])([A-Z])/', '/_/', '/\\\/' ],
|
||||
[ '', '$1-$2', '-', DIRECTORY_SEPARATOR ],
|
||||
$class_to_load
|
||||
)
|
||||
);
|
||||
|
||||
$file = ZIP_AI_DIR . $filename . '.php';
|
||||
|
||||
// if the file redable, include it.
|
||||
if ( is_readable( $file ) ) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
spl_autoload_register( [ $this, 'autoload' ] );
|
||||
|
||||
add_action( 'plugins_loaded', [ $this, 'setup_classes' ], 20 );
|
||||
$this->define_constants();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the required constants.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function define_constants() {
|
||||
define( 'ZIP_AI_FILE', __FILE__ );
|
||||
define( 'ZIP_AI_DIR', plugin_dir_path( ZIP_AI_FILE ) );
|
||||
define( 'ZIP_AI_URL', plugins_url( '/', ZIP_AI_FILE ) );
|
||||
define( 'ZIP_AI_VERSION', '2.0.2' );
|
||||
define( 'ZIP_AI_MENU_SLUG', 'zip-ai' );
|
||||
define( 'ZIP_AI_MIDDLEWARE', 'https://app.zipwp.com/auth/' );
|
||||
define( 'ZIP_AI_ZIPWP_API', 'https://api.zipwp.com/api/' );
|
||||
define( 'ZIP_AI_CREDIT_SERVER_API', 'https://credits.startertemplates.com/api/' );
|
||||
define( 'ZIP_AI_CREDIT_TOPUP_URL', 'https://app.zipwp.com/credits-pricing' );
|
||||
define( 'ZIP_AI_CREDIT_THRESHOLD_MEDIUM', 65 );
|
||||
define( 'ZIP_AI_CREDIT_THRESHOLD_HIGH', 85 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the required classes.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function setup_classes() {
|
||||
// Migrate any older modules to the new format.
|
||||
Module::migrate_options();
|
||||
|
||||
// Enable the Zip AI Chat Sidebar if required - filter is for old users.
|
||||
if ( apply_filters( 'zip_ai_enable_chat_sidebar', true ) && Module::is_enabled( 'ai_assistant' ) ) {
|
||||
Sidebar_Configurations::get_instance();
|
||||
}
|
||||
|
||||
// Enable the Zip AI Admin Configurations if required.
|
||||
if ( is_admin() ) {
|
||||
Admin_Configurations::get_instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicking this off by calling 'get_instance()' method
|
||||
*/
|
||||
Loader::get_instance();
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-plugins', 'wp-rich-text'), 'version' => 'b3680a68e8218cfea8ff');
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"zip-ai": "2.0.2"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Zip AI Assistant
|
||||
* Description: Library which interacts with SCS and provide multiple useful modules.
|
||||
* Author: Brainstorm Force
|
||||
* Version: 2.0.2
|
||||
* License: GPL v2
|
||||
* Text Domain: zip-ai
|
||||
*
|
||||
* @package zip-ai
|
||||
*/
|
||||
|
||||
// Exit if Zip AI is already loaded.
|
||||
if ( defined( 'ZIP_AI_DIR' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the Zip AI Loader.
|
||||
if ( apply_filters( 'zip_ai_load_library', true ) ) {
|
||||
require_once 'loader.php';
|
||||
}
|
||||
Reference in New Issue
Block a user