<?php
/**
* Jetpack CRM Core
*
* @author Woody Hayday, Mike Stott
* @package automattic/jetpack-crm
* @since 2.27
*/
if ( ! defined( 'ABSPATH' ) ) {
exit( 0 ); // Exit if accessed directly.
}
/**
* Main ZeroBSCRM Class.
*
* @class ZeroBSCRM
* @version 2.27
*/
final class ZeroBSCRM {
/**
* Jetpack CRM version.
*
* @var string
*/
const VERSION = '6.7.2';
/**
* Jetpack CRM version (used in various extensions as of January 2025).
*
* @deprecated
* @var string
*/
public $version = '';
/**
* WordPress version tested with.
*
* @var string
*/
public $wp_tested = '6.8';
/**
* WordPress update API version.
*
* @var string
*/
public $api_ver = '1.0';
/**
* Jetpack CRM update API version.
*
* @var string
*/
public $update_api_version = '1.0';
/**
* ZeroBSCRM DB version.
*
* @var string
*/
public $db_version = '3.0';
/**
* Database details.
*
* @var array
*/
public $database_server_info = array();
/**
* ZeroBSCRM DAL version.
*
* @var string
*/
public $dal_version = '3.0';
/**
* ZeroBSCRM Extension Compatible versions
* Stores which extensions are viable to use with newly-migrated v3.0
*
* @var string
*/
public $compat_versions = array(
// v3.0 Migration needed a 'minimum version' for any extensions which might not work with v3.0 but were active premigration
// 15th Nov - as numbers it does not like the 1.4.1 type format so added as strings.
'v3extminimums' => array(
'advancedsegments' => '1.3',
'apiconnector' => '1.6',
'automations' => '1.4.1',
'aweber' => '1.2',
'awesomesupport' => '2.5',
'batchtag' => '2.3',
'passwordmanager' => '1.4.1',
'clientportalpro' => '1.7',
'contactform' => '2.5',
'convertkit' => '2.5',
'csvpro' => '2.0',
'envato' => '2.4.2',
'exitbee' => '1.1',
'funnels' => '1.2',
'googlecontact' => '2.6',
'gravity' => '2.6',
'groove' => '2.6',
'invpro' => '2.6',
'livestorm' => '1.1',
'mailcamp' => '2.0.4',
'mailchimp' => '2.6',
'membermouse' => '1.5',
'optinmonster' => '1.1',
'paypal' => '2.6.1',
'registrationmagic' => '1.1',
'salesdash' => '2.6',
'stripe' => '2.6.2',
'systememail' => '1.1',
'twilio' => '1.5',
'woosync' => '2.9',
'wordpressutilities' => '1.2',
'worldpay' => '2.4',
),
);
/**
* ZeroBSCRM DAL .
*
* @var object (DAL Class init) ;)
*/
public $DAL = false;
/**
* Dependency checker
*
* @var object JPCRM_DependencyChecker init
*/
public $dependency_checker = false;
/**
* Feature sniffer
*
* @var object JPCRM_FeatureSniffer init
*/
public $feature_sniffer = false;
/**
* WordPress User Integrations
*
* @var object Wordpress_User_Integration class
*/
public $wordpress_user_integration = false;
/**
* Zapier integration
*
* @var ?
*/
public $zapier = false;
/**
* Fonts
*
* @var object JPCRM_Fonts init
*/
public $fonts = false;
/**
* DB1 compatability support
*
* @var Bool - if true, basically $obj['meta'] is a clone of $obj itself (To be disabled once safely in DAL2 + updated extensions)
*/
public $db1CompatabilitySupport = false;
/**
* DB2 compatability support
*
* @var Bool - if true, basically $obj['meta'] is a clone of $obj itself (To be disabled once safely in DAL3 + updated extensions)
* This variant accounts for stray objs in quotes, trans, invs, etc.
*/
public $db2CompatabilitySupport = false;
/**
* ZeroBSCRM DB Version Switch.
*
* @var string
*/
public $DBVER = 1;
/**
* The single instance of the class.
*
* @var ZeroBSCRM
* @since 2.1
*/
protected static $_instance = null;
/**
* JP CRM Page Loaded (KEY - used for screenoptions) (equivilent of pagenow)
*
* @var string
*/
public $pageKey = 'root';
/**
* WordPress Admin notice stack
*
* @var array
*/
public $admin_notices = array();
/**
* Hide admin_notices for specified pages
*
* @var array
*/
public $hide_admin_pages = array(
// hidden due to #gh-1442
'manage-tasks',
'zerobscrm-csvimporterlite-app',
);
/**
* Template path, this is where we look in the theme directory for templates
*
* @var string
*/
public $template_path = 'jetpack-crm';
/**
* Extensions instances
*
* @var Jetpack CRM Extensions
*/
public $extensions = null;
/**
* External Sources
*
* @var Jetpack CRM External Sources
*/
public $external_sources = null;
/**
* Listview filters
*
* @var array Jetpack CRM External Sources
*/
public $listview_filters = array();
/**
* Settings Object
*
* @var Jetpack CRM Settings Object
*/
public $settings = null;
/**
* Internal Automator Block
*
* @var Bool - if true, IA will not fire anything :)
*/
public $internalAutomatorBlock = false;
/**
* Metaboxes Object
*
* @var Jetpack CRM Metaboxes Object
*/
public $metaboxes = null;
/**
* Menus Object
*
* @var Jetpack CRM Menus Array
* This ultimately adds any WP menus that need injecting
*/
private $menu = null;
/**
* Learn Menu Object
*
* @var Jetpack CRM Learn menu class instance
*/
public $learn_menu = null;
/**
* URLS Array
*
* @var Jetpack CRM URLS list
*/
public $urls;
/**
* Slugs Array
*
* @var Jetpack CRM Slugs list
*/
public $slugs;
/**
* Transient Array
*
* @var Jetpack CRM Transients list
*/
public $transients;
/**
* Houses all module classes
* e.g. $zbs->modules->woosync
*/
public $modules = null;
/**
* Package installer (Automattic\JetpackCRM\Package_Installer)
*/
public $package_installer = null;
/**
* OAuth handler
*/
public $oauth = null;
/**
* Endpoint Listener
*/
public $listener = null;
/**
* Encryption tooling
*/
public $encryption = null;
/**
* Included Array (means we cannot 'reinclude' stripe etc.)
*/
public $included = array(
'stripe' => false,
);
/**
* Libraries included (3.0.12+)
* Note: All paths need to be prepended by ZEROBSCRM_PATH before use
*/
private $libs = array();
/**
* Usage Tracking
*
* @var object Usage tracking class
*/
public $tracking = false;
/**
* Page Messages Array
* Experimental: stores msgs such as "Contact Updated"
*
* @var msg arr
*/
public $pageMessages;
/**
* Templating: placeholders
*
* @var object Placeholder Class
*/
public $templating_placeholders = false;
/**
* Acceptable mime types Array
*
* @var Jetpack CRM Acceptable mime types list
*/
public $acceptable_mime_types;
/**
* Acceptable fields to be included in the Total Value of contacts and companies
*
* @var Jetpack CRM Acceptable fields to be included in the Total Value
*/
public $acceptable_total_value_fields = array(
'transactions' => 'Transactions',
'invoices' => 'Invoices',
);
/**
* Acceptable html array
*
* @var Jetpack CRM Acceptable html types list
* Was previously: $zeroBSCRM_allowedHTML
*/
public $acceptable_html = array(
'h1' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'h2' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'h3' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'h4' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'h5' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'h6' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'a' => array(
'href' => array(),
'title' => array(),
'target' => array(),
'class' => array(),
),
'b' => array(),
'br' => array(),
'em' => array(),
'strong' => array(),
'ul' => array(),
'ol' => array(),
'li' => array(),
'p' => array(
'style' => true,
),
'div' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'span' => array(
'class' => array(),
'style' => array(),
'id' => array(),
),
'img' => array(
'class' => array(),
'style' => array(),
'src' => array(),
),
'i' => array(
'class' => array(),
),
'table' => array(
'tr' => array(
'th' => array(
'label' => array(),
),
'class' => array(),
'label' => array(),
'th' => array(),
),
'style' => array(),
'label' => array(),
),
'td' => array(),
'tr' => array(),
'blockquote' => array(),
'del' => array(),
'hr' => array(),
);
/**
* Acceptable (restricted) html array
*
* @var Jetpack CRM Acceptable (restricted) html types list
* (e.g. for use in contact logs)
*/
public $acceptable_restricted_html = array(
'a' => array(
'href' => array(),
'title' => array(),
'id' => array(),
'target' => array(),
),
'br' => array(),
'em' => array(),
'strong' => array(),
'blockquote' => array(),
);
/**
* Error Codes Array
* Experimental: loads + stores error codes, (only when needed/requested)
*
* @var error code arr
*/
private $errorCodes;
/**
* Main ZeroBSCRM Instance.
*
* Ensures only one instance of ZeroBSCRM is loaded or can be loaded.
*
* @since 2.27
* @static
* @return ZeroBSCRM - Main instance.
*/
public static function instance() {
if ( self::$_instance === null ) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Unserializing instances of this class is forbidden.
*
* @since 2.1
*/
public function __wakeup() {
zerobscrm_doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'zero-bs-crm' ), '2.1' );
}
/**
* Auto-load in-accessible properties on demand - What is this wizadrey?
*
* @param mixed $key Key name.
* @return mixed
*/
/*
See: http://php.net/manual/en/language.oop5.overloading.php#object.get
public function __get( $key ) {
if ( in_array( $key, array( 'payment_gateways', 'shipping', 'mailer', 'checkout' ), true ) ) {
return $this->$key();
}
}
*/
/**
* Jetpack CRM Constructor.
*/
public function __construct() {
// @phan-suppress-next-line PhanDeprecatedProperty - Define old property for backward compatibility.
$this->version = $this::VERSION;
// Simple global definitions without loading any core files...
// required for verify_minimum_requirements()
// define constants & globals
$this->define_constants();
// Verify we have minimum requirements (e.g. DAL3.0 and extension versions up to date)
if ( $this->verify_minimum_requirements() ) {
$this->debugMode();
// } Load includes
$this->includes();
// urls, slugs, (post inc.)
$this->setupUrlsSlugsEtc();
// } Initialisation
$this->init_hooks();
// } Post Init hook
do_action( 'zerobscrm_loaded' );
} else {
// used by some extensions to determine if current page is an admin page
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.AdminPages.Checks.php';
// extensions use the dependency checker functions
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-dependency-checker.php';
$this->dependency_checker = new JPCRM_DependencyChecker();
}
// display any wp admin notices in the stack
// needs to be outside of any above functionality as used for exposing failed verify_minimum_requirements()
add_action( 'admin_notices', array( $this, 'wp_admin_notices' ) );
}
/**
* Verify we have minimum requirements (e.g. DAL3.0)
*/
private function verify_minimum_requirements() {
// fresh installs get a pass so that migrations can run
// ... as soon as DB is installed, this'll be skipped
// gather database server info
$this->get_database_server_info();
if ( ! $this->is_database_installed() ) {
return true;
}
// v5.0+ JPCRM requires DAL3+
if ( ! $this->isDAL3() ) {
// we need urls
$this->setupUrlsSlugsEtc();
// build message
$message_html = '<p>' . sprintf( esc_html__( 'This version of CRM (%1$s) requires an upgraded database (3.0). Your database is using an older version than this (%2$s). To use CRM you will need to install version 4 of CRM and run the database upgrade.', 'zero-bs-crm' ), $this::VERSION, $this->dal_version ) . '</p>'; // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
##WLREMOVE
$message_html = '<p>' . sprintf( esc_html__( 'This version of Jetpack CRM (%1$s) requires an upgraded database (3.0). Your database is using an older version than this (%2$s). To use Jetpack CRM you will need to install version 4 of Jetpack CRM and run the database upgrade.', 'zero-bs-crm' ), $this::VERSION, $this->dal_version ) . '</p>'; // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
$message_html .= '<p><a href="' . esc_url( $this->urls['kb-pre-v5-migration-todo'] ) . '" target="_blank" class="button">' . __( 'Read the guide on migrating', 'zero-bs-crm' ) . '</a></p>';
##/WLREMOVE
$this->add_wp_admin_notice(
'',
array(
'class' => 'warning',
'html' => $message_html,
)
);
return false;
} elseif ( ! function_exists( 'openssl_get_cipher_methods' ) ) {
// build message
$message_html = '<p>' . sprintf( __( 'Jetpack CRM uses the OpenSSL extension for PHP to properly protect sensitive data. Most PHP environments have this installed by default, but it seems yours does not; we recommend contacting your host for further help.', 'zero-bs-crm' ), $this::VERSION, $this->dal_version ) . '</p>';
$message_html .= '<p><a href="' . esc_url( 'https://www.php.net/manual/en/book.openssl.php' ) . '" target="_blank" class="button">' . __( 'PHP docs on OpenSSL', 'zero-bs-crm' ) . '</a></p>';
$this->add_wp_admin_notice(
'',
array(
'class' => 'warning',
'html' => $message_html,
)
);
return false;
}
return true;
}
/**
* Verify our extensions meet minimum requirements (e.g. DAL3.0)
* Where extensions are found which do not meet requirements, these are deactivated and notices posted
* Note: This has to fire lower down the stack than `verify_minimum_requirements()`
* because it relies on extension linkages
*/
private function verify_extension_minimum_requirements() {
// v5.0+ JPCRM/DAL3 requires these extension versions
$installed_extensions = zeroBSCRM_installedProExt();
if ( is_array( $installed_extensions ) ) {
foreach ( $installed_extensions as $extension_name => $extension_info ) {
// get minimum version okay with v3
$minimum_version = 99.99;
if ( isset( $this->compat_versions['v3extminimums'][ $extension_info['key'] ] ) ) {
$minimum_version = $this->compat_versions['v3extminimums'][ $extension_info['key'] ];
}
// do we have an active outdated version?
if ( $extension_info['active'] == 1 && $minimum_version > 0 && ! ( version_compare( $extension_info['ver'], $minimum_version ) >= 0 ) ) {
// deactivate
jpcrm_extensions_deactivate_by_key( $extension_info['key'] );
// show warning notice
$message_html = '<p>' . sprintf( __( 'Your CRM extension %1$s (v%2$s) is not compatible with this version of CRM. You will need to run a database upgrade to use this extension. For now this extension has been deactivated.', 'zero-bs-crm' ), $extension_name, $extension_info['ver'] ) . '</p>';
##WLREMOVE
$message_html = '<p>' . sprintf( __( 'Your Jetpack CRM extension %1$s (v%2$s) is not compatible with this version of Jetpack CRM. You will need to run a database upgrade to be able to use this extension. For now this extension has been deactivated.', 'zero-bs-crm' ), $extension_name, $extension_info['ver'] ) . '</p>';
$message_html .= '<p><a href="' . esc_url( $this->urls['kb-pre-v5-migration-todo'] ) . '" target="_blank" class="button">' . __( 'Read the guide on migrating', 'zero-bs-crm' ) . '<a></p>';
##/WLREMOVE
$this->add_wp_admin_notice(
'',
array(
'class' => 'warning',
'html' => $message_html,
)
);
}
}
}
return false;
}
/**
* Add admin notice to the stack
*/
private function add_wp_admin_notice( $page, $notice ) {
// validate existing
if ( ! is_array( $this->admin_notices ) ) {
$this->admin_notices = array();
}
// add to stack if new page
if ( ! isset( $this->admin_notices[ $page ] ) ) {
$this->admin_notices[ $page ] = array();
}
// add notice to stack
$this->admin_notices[ $page ][] = $notice;
}
/**
* Output any admin notices in the stack
*/
public function wp_admin_notices() {
global $pagenow;
if ( is_array( $this->admin_notices ) ) {
foreach ( $this->admin_notices as $page => $notices ) {
// matching page or all pages (empty)
if ( $pagenow == $page || empty( $page ) ) {
foreach ( $notices as $notice ) {
wp_admin_notice(
wp_kses(
$notice['html'],
array(
'a' => array(
'href' => array(),
'target' => array(),
'class' => array(),
),
'p' => array(),
)
),
array(
'type' => esc_attr( $notice['class'] ),
'dismissible' => true,
'paragraph_wrap' => false,
)
);
}
}
}
}
}
/**
* Maintain a list of Jetpack CRM extension slugs here.
* (This was an MS initiative for updates/licensing, WH removed 27/11/18, doing via Keys = rebrandr friendly)
*/
/*
public $zeroBSCRM_extensionSlugs = array(
'ZeroBSCRM_BulkTagger.php',
);
*/
/**
* Define ZeroBSCRM Constants.
*/
private function define_constants() {
// Main paths etc.
$this->define( 'ZBS_ABSPATH', dirname( ZBS_ROOTFILE ) . '/' );
$this->define( 'ZEROBSCRM_PATH', plugin_dir_path( ZBS_ROOTFILE ) );
$this->define( 'ZEROBSCRM_URL', plugin_dir_url( ZBS_ROOTFILE ) );
// Template paths
$this->define( 'ZEROBSCRM_TEMPLATEPATH', ZEROBSCRM_PATH . 'templates/' );
$this->define( 'ZEROBSCRM_TEMPLATEURL', ZEROBSCRM_URL . 'templates/' );
// include/module paths
$this->define( 'ZEROBSCRM_INCLUDE_PATH', ZEROBSCRM_PATH . 'includes/' );
$this->define( 'JPCRM_MODULES_PATH', ZEROBSCRM_PATH . 'modules/' );
// } define that the CORE has been loaded - for backwards compatibility with other extensions
$this->define( 'ZBSCRMCORELOADED', true );
// } Menu types
$this->define( 'ZBS_MENU_FULL', 1 );
$this->define( 'ZBS_MENU_SLIM', 2 );
$this->define( 'ZBS_MENU_CRMONLY', 3 );
// } Debug
$this->define( 'ZBS_CRM_DEBUG', true );
}
private function debugMode() {
if ( defined( 'ZBS_CRM_DEBUG' ) ) {
/*
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
*/
}
}
// shorthand for lack of presence of any DB presence
public function is_database_installed() {
global $ZBSCRM_t, $wpdb;
// we need db
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Database.php';
// check
$tables = $wpdb->get_results( "SHOW TABLES LIKE '" . $ZBSCRM_t['contacts'] . "'" );
return ( count( $tables ) > 0 );
}
/**
* Retrieves MySQL/MariaDB/Percona database server info
*/
public function get_database_server_info() {
if ( empty( $this->database_server_info ) ) {
// Adapted from proposed SQLite integration for core
// https://github.com/WordPress/sqlite-database-integration/blob/4a687709bb16a569a7d1ecabfcce433c0e471de8/health-check.php
if ( defined( 'DB_ENGINE' ) && DB_ENGINE === 'sqlite' ) {
$db_engine = DB_ENGINE;
$db_engine_label = 'SQLite';
$raw_version = class_exists( 'SQLite3' ) ? SQLite3::version()['versionString'] : null;
$version = $raw_version;
} else {
global $wpdb;
$raw_version = $wpdb->get_var( 'SELECT VERSION()' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.DirectQuery
$version = preg_replace( '/[^0-9.].*/', '', $raw_version );
if ( stripos( $raw_version, 'mariadb' ) !== false ) {
$db_engine = 'mariadb';
$db_engine_label = 'MariaDB';
} else {
$db_engine = 'mysql';
$db_engine_label = 'MySQL';
}
}
$database_server_info = array(
'raw_version' => $raw_version,
'version' => $version,
'db_engine' => $db_engine,
'db_engine_label' => $db_engine_label,
);
$this->database_server_info = $database_server_info;
}
return $this->database_server_info;
}
// } Use this for shorthand checking new DAL additions
// this says "is At least DAL2"
public function isDAL2() {
// is DAL > 1.0
return ( version_compare( $this->dal_version, '1.0' ) > 0 );
}
// } Use this for shorthand checking new DAL additions
// this says "is At least DAL3"
public function isDAL3() {
// is DAL > 1.0
return ( version_compare( $this->dal_version, '2.53' ) > 0 );
}
// } Use this to output the number of plugins with "Jetpack CRM" in the name
public function extensionCount( $activatedOnly = false ) {
/*
Following func: zeroBSCRM_extensionsInstalledCount
... will get all active rebrandr extensions,
... and all active/inactive branded extensions
... and returns a count here */
return zeroBSCRM_extensionsInstalledCount( $activatedOnly );
}
private function setupUrlsSlugsEtc() {
// array check
if ( ! is_array( $this->urls ) ) {
$this->urls = array();
}
if ( ! is_array( $this->slugs ) ) {
$this->slugs = array();
}
if ( ! is_array( $this->transients ) ) {
$this->transients = array();
}
if ( ! is_array( $this->acceptable_mime_types ) ) {
$this->acceptable_mime_types = array();
}
if ( ! is_array( $this->pageMessages ) ) {
$this->pageMessages = array();
}
// Urls
$this->urls['home'] = 'https://jetpackcrm.com';
$this->urls['kb'] = 'https://kb.jetpackcrm.com';
$this->urls['support'] = 'https://kb.jetpackcrm.com/crm-support/';
$this->urls['feedback'] = 'https://kb.jetpackcrm.com/crm-support/';
$this->urls['pricing'] = 'https://jetpackcrm.com/pricing/';
$this->urls['usagetrackinginfo'] = 'https://jetpackcrm.com/usage-tracking/';
$this->urls['support-forum'] = 'https://wordpress.org/support/plugin/zero-bs-crm';
$this->urls['docs'] = 'https://kb.jetpackcrm.com/';
$this->urls['productsdatatools'] = 'https://jetpackcrm.com/data-tools/';
$this->urls['extimgrepo'] = 'https://jetpackcrm.com/_plugin_dependent_assets/_i/';
$this->urls['rateuswporg'] = 'https://wordpress.org/support/view/plugin-reviews/zero-bs-crm?filter=5#new-post';
$this->urls['extdlreporoot'] = 'https://jetpack-crm-cdn.s3.amazonaws.com/';
$this->urls['extdlrepo'] = $this->urls['extdlreporoot'] . 'ext/';
$this->urls['extdlfonts'] = $this->urls['extdlreporoot'] . 'fonts/';
$this->urls['extdlpackages'] = $this->urls['extdlreporoot'] . 'packages/';
$this->urls['apidocs'] = 'https://automattic.github.io/jetpack-crm-api-docs/';
$this->urls['oauthdocs'] = 'https://kb.jetpackcrm.com/knowledge-base/using-gmail-with-jetpack-crm-mail-delivery-system/#setting-up-gmail-oauth-connection-and-mail-delivery-method';
$this->urls['woosync'] = 'https://jetpackcrm.com/woocommerce/';
$this->urls['woomanagingorders'] = 'https://woocommerce.com/document/managing-orders/#order-statuses';
$this->urls['core-automations'] = 'https://jetpackcrm.com/features/automations';
// used for ext manager:
$this->urls['checkoutapi'] = 'https://jetpackcrm.com/wp-json/zbsextensions/v1/extensions/0';
$this->urls['howtoinstall'] = 'https://kb.jetpackcrm.com/knowledge-base/how-do-i-install-a-zero-bs-extension/';
$this->urls['apiconnectorsales'] = 'https://jetpackcrm.com/product/api-connector/';
$this->urls['autonumberhelp'] = 'https://kb.jetpackcrm.com/knowledge-base/custom-field-type-autonumber/';
$this->urls['akamode'] = 'https://jetpackcrm.com/feature/aka-mode/';
$this->urls['licensinginfo'] = 'https://kb.jetpackcrm.com/knowledge-base/yearly-subscriptions-refunds/';
$this->urls['easyaccessguide'] = 'https://kb.jetpackcrm.com/knowledge-base/easy-access-links-for-client-portal/';
// API v3.0 - licensing - 5/12/18
$this->urls['api'] = 'https://app.jetpackcrm.com/api/updates/updates';
$this->urls['apilocalcheck'] = 'https://app.jetpackcrm.com/api/updates/localcheck';
$this->urls['smm'] = 'https://app.jetpackcrm.com/api/welcome-wizard';
$this->urls['api-support'] = 'https://app.jetpackcrm.com/api/support';
// account
$this->urls['account'] = 'https://app.jetpackcrm.com/';
$this->urls['licensekeys'] = 'https://app.jetpackcrm.com/license-keys';
// } sales urls
$this->urls['products'] = 'https://jetpackcrm.com/extensions/';
$this->urls['extcsvimporterpro'] = 'https://jetpackcrm.com/product/csv-importer-pro/';
$this->urls['invpro'] = 'https://jetpackcrm.com/product/invoicing-pro/';
$this->urls['upgrade'] = 'https://jetpackcrm.com/checkout/?plan=entrepreneur&utm_source=plugin&utm_medium=plugin&utm_campaign=welcome_upgrade';
$this->urls['extcpp'] = 'https://jetpackcrm.com/product/client-portal-pro/';
$this->urls['extcal'] = 'https://jetpackcrm.com/product/calendar-pro/';
$this->urls['roadtov3'] = 'https://jetpackcrm.com/road-to-v3/';
$this->urls['advancedsegments'] = 'https://jetpackcrm.com/product/advanced-segments/';
$this->urls['bulktagger'] = 'https://jetpackcrm.com/product/bulk-tagger/';
$this->urls['salesdash'] = 'https://jetpackcrm.com/product/sales-dashboard/';
$this->urls['connect-multi-woo'] = 'https://jetpackcrm.com/feature/multiple-woocommerce-stores/';
$this->urls['woosync'] = 'https://jetpackcrm.com/woocommerce/';
$this->urls['mailpoet'] = 'https://jetpackcrm.com/feature/mailpoet-crm-sync/';
$this->urls['feedbackform'] = 'https://forms.gle/k94AdShUHZ3LWPvx8';
// social
$this->urls['twitter'] = 'https://twitter.com/jetpackcrm';
// assets
$this->urls['crm-logo'] = plugins_url( 'i/jpcrm-logo-stacked-black.png', ZBS_ROOTFILE );
// kb
$this->urls['kbdevmode'] = 'https://kb.jetpackcrm.com/knowledge-base/developer-mode/';
$this->urls['kbquoteplaceholders'] = 'https://kb.jetpackcrm.com/knowledge-base/placeholders-in-emails-quote-templates-invoices-etc/#quote-template-placeholders';
$this->urls['kblicensefaq'] = 'https://kb.jetpackcrm.com/knowledge-base/license-keys-faq/';
$this->urls['kbcronlimitations'] = 'https://kb.jetpackcrm.com/knowledge-base/wordpress-cron-limitations/';
$this->urls['kbfirstcontact'] = 'https://kb.jetpackcrm.com/knowledge-base/adding-your-first-customer/';
$this->urls['kbactivatecoreext'] = 'https://kb.jetpackcrm.com/knowledge-base/how-to-activate-deactivate-core-modules/';
$this->urls['kbinvoicebuilder'] = 'https://kb.jetpackcrm.com/knowledge-base/how-to-use-the-invoice-builder/';
$this->urls['kbteam'] = 'https://kb.jetpackcrm.com/knowledge-base/setting-up-your-team/';
$this->urls['kbupdateext'] = 'https://kb.jetpackcrm.com/knowledge-base/how-do-i-update-an-extension/';
$this->urls['kbclientportal'] = 'https://kb.jetpackcrm.com/knowledge-base/how-does-the-client-portal-work/';
$this->urls['kbtemplatefiles'] = 'https://kb.jetpackcrm.com/knowledge-base/templating-how-to-change-templates-pdfs-portal-emails/';
$this->urls['kbeasyaccess'] = 'https://kb.jetpackcrm.com/knowledge-base/easy-access-links-for-client-portal/';
$this->urls['kbdisablewelcome'] = 'https://kb.jetpackcrm.com/knowledge-base/automatically-create-wordpress-users-but-not-send-them-a-welcome-email/';
$this->urls['kbapi'] = 'https://kb.jetpackcrm.com/knowledge-base/using-the-api-connector/';
$this->urls['kbshowwpmenus'] = 'https://kb.jetpackcrm.com/knowledge-base/how-to-get-wordpress-menu-items-back/';
$this->urls['kbsmtpsetup'] = 'https://kb.jetpackcrm.com/knowledge-base/mail-delivery-method-setup-smtp/';
$this->urls['kbcrmdashboard'] = 'https://kb.jetpackcrm.com/knowledge-base/zero-bs-crm-dashboard/';
$this->urls['kbrevoverview'] = 'https://kb.jetpackcrm.com/knowledge-base/revenue-overview-chart/';
$this->urls['kbcsvformat'] = 'https://kb.jetpackcrm.com/knowledge-base/what-should-my-csv-be-formatted-like/';
$this->urls['kbcat_cal'] = 'https://kb.jetpackcrm.com/article-categories/calendar/';
$this->urls['kbsegment_issues'] = 'https://kb.jetpackcrm.com/knowledge-base/segment-issues-and-errors/';
$this->urls['kb-woosync-home'] = 'https://kb.jetpackcrm.com/knowledge-base/using-the-woocommerce-sync-hub/';
$this->urls['kb-pre-v5-migration-todo'] = 'https://kb.jetpackcrm.com/knowledge-base/upgrading-to-jetpack-crm-v5-0/';
$this->urls['kb-mailpoet'] = 'https://kb.jetpackcrm.com/knowledge-base/mailpoet-crm-sync/';
$this->urls['kb-automations'] = 'https://kb.jetpackcrm.com/knowledge-base/automations/';
$this->urls['kb-contact-fields'] = 'https://kb.jetpackcrm.com/knowledge-base/contact-field-list/';
$this->urls['kb-pdf-custom-fonts'] = 'https://kb.jetpackcrm.com/knowledge-base/using-custom-fonts-in-crm-pdfs-e-g-invoice-templates/';
// coming soon
$this->urls['soon'] = 'https://jetpackcrm.com/coming-soon/';
// v4 rebrand announcement
$this->urls['v4announce'] = 'https://jetpackcrm.com/rebrand-announcement';
$this->urls['v5announce'] = 'https://jetpackcrm.com/announcing-jetpack-crm-v5-woocommerce-crm/';
// } Usage Tracking
$this->urls['usage'] = 'https://app.jetpackcrm.com/api/usage';
$this->urls['usageinfo'] = 'https://jetpackcrm.com/usage-tracking';
// YouTubes!
$this->urls['youtube_channel'] = 'https://www.youtube.com/channel/UCyT-wMU7Gp6r1wN6W5YMAiQ';
$this->urls['youtube_intro_playlist'] = 'https://www.youtube.com/watch?v=tCC25uTFDTs&list=PLO9bxAENhBHhnc53Eq3OGBKLMSj0leAel';
$this->urls['youtube_intro_to_crm'] = 'https://www.youtube.com/watch?v=tCC25uTFDTs';
$this->urls['youtube_intro_to_tags'] = 'https://www.youtube.com/watch?v=KwGh-Br_exc';
$this->urls['youtube_intro_to_forms'] = 'https://www.youtube.com/watch?v=mBPjV1KUb-w';
$this->urls['youtube_intro_to_modules'] = 'https://www.youtube.com/watch?v=j9RsXPcgeIo';
// $this->urls['youtube_intro_to_woosync'] = 'https://www.youtube.com/watch?v=4G-FtmMhy-s';
// Page slugs
$this->slugs['home'] = 'zerobscrm-settings';
##WLREMOVE
$this->slugs['home'] = 'zerobscrm-plugin';
##/WLREMOVE
$this->slugs['dash'] = 'zerobscrm-dash';
$this->slugs['settings'] = 'zerobscrm-plugin-settings';
$this->slugs['logout'] = 'zerobscrm-logout';
$this->slugs['datatools'] = 'zerobscrm-datatools';
$this->slugs['welcome'] = 'zerobscrm-welcome';
$this->slugs['crmresources'] = 'jpcrm-resources';
$this->slugs['support'] = 'jpcrm-support';
$this->slugs['extensions'] = 'zerobscrm-extensions';
$this->slugs['modules'] = 'zerobscrm-modules';
$this->slugs['export'] = 'zerobscrm-export';
$this->slugs['systemstatus'] = 'zerobscrm-systemstatus';
$this->slugs['sync'] = 'zerobscrm-sync';
$this->slugs['core-automations'] = 'jpcrm-automations';
// CSV importer Lite
$this->slugs['csvlite'] = 'zerobscrm-csvimporterlite-app';
// } FOR NOW wl needs these:
$this->slugs['bulktagger'] = 'zerobscrm-batch-tagger';
$this->slugs['salesdash'] = 'sales-dash';
$this->slugs['stripesync'] = 'zerobscrm-stripesync-app';
$this->slugs['woosync'] = 'woo-sync-hub'; // previously 'woo-importer';
$this->slugs['paypalsync'] = 'zerobscrm-paypal-app';
$this->slugs['mailpoet'] = 'crm-mail-poet-hub'; // note can't use `*mailpoet*` as the plugin inteferes with styles
// } OTHER UI PAGES WHICH WEREN'T IN SLUG - MS CLASS ADDITION
// } WH: Not sure which we're using here, think first set cleaner:
// NOTE: DAL3 + these are referenced in DAL2.php so be aware :)
// (This helps for generically linking back to list obj etc.)
// USE zbsLink!
$this->slugs['managecontacts'] = 'manage-customers';
$this->slugs['managequotes'] = 'manage-quotes';
$this->slugs['manageinvoices'] = 'manage-invoices';
$this->slugs['managetransactions'] = 'manage-transactions';
$this->slugs['managecompanies'] = 'manage-companies';
$this->slugs['manageformscrm'] = 'manage-forms';
$this->slugs['segments'] = 'manage-segments';
$this->slugs['quote-templates'] = 'manage-quote-templates';
$this->slugs['manage-tasks'] = 'manage-tasks';
$this->slugs['manage-tasks-completed'] = 'manage-tasks-completed';
$this->slugs['manage-tasks-list'] = 'manage-tasks-list';
$this->slugs['managecontactsprev'] = 'manage-customers-crm';
$this->slugs['managequotesprev'] = 'manage-quotes-crm';
$this->slugs['managetransactionsprev'] = 'manage-transactions-crm';
$this->slugs['manageinvoicesprev'] = 'manage-invoices-crm';
$this->slugs['managecompaniesprev'] = 'manage-companies-crm';
$this->slugs['manageformscrmprev'] = 'manage-forms-crm';
// } NEW UI - ADD or EDIT, SEND EMAIL, NOTIFICATIONS
$this->slugs['addedit'] = 'zbs-add-edit';
$this->slugs['sendmail'] = 'zerobscrm-send-email';
$this->slugs['emails'] = 'zerobscrm-emails';
$this->slugs['notifications'] = 'zerobscrm-notifications';
// } TEAM - Manage the CRM team permissions
$this->slugs['team'] = 'zerobscrm-team';
// } Export tools
$this->slugs['export-tools'] = 'zbs-export-tools';
// } Your Profile (for Calendar Sync and Personalised Stuff (like your own task history))
$this->slugs['your-profile'] = 'your-crm-profile';
$this->slugs['reminders'] = 'zbs-reminders';
// } Adds a USER (i.e. puts our menu on user-new.php through ?page =)
$this->slugs['zbs-new-user'] = 'zbs-add-user';
$this->slugs['zbs-edit-user'] = 'zbs-edit-user'; // WH Added this, not sure what you're using for
// } Install helper
$this->slugs['zerobscrm-install-helper'] = 'zerobscrm-install-helper';
// emails
$this->slugs['email-templates'] = 'zbs-email-templates';
// tag manager
$this->slugs['tagmanager'] = 'tag-manager';
// no access
$this->slugs['zbs-noaccess'] = 'zbs-noaccess';
// } File Editor
$this->slugs['editfile'] = 'zerobscrm-edit-file';
$this->slugs['addnewfile'] = 'zerobscrm-add-file';
// } Extensions Deactivated error
$this->slugs['extensions-active'] = 'zbs-extensions-active';
// Activates a module and redirects to its 'hub' slug.
$this->slugs['module-activate-redirect'] = 'jpcrm-module-activate-redirect';
// Transients
// These are transients which CRM owns which can be set via jpcrm_set_jpcrm_transient() etc.
// Licensing prompts
$this->transients['jpcrm-license-modal'] = false;
// Mime types just use this func () - needs rethinking - includes/ZeroBSCRM.FileUploads.php
if ( function_exists( 'zeroBSCRM_returnMimeTypes' ) ) {
$this->acceptable_mime_types = zeroBSCRM_returnMimeTypes();
}
}
/**
* Include required core files used in admin and on the frontend. Note. In the main
* file it was included everything on front end too. Can move the relevant ones
* to if ( $this->is_request( 'admin' ) ) { } once initial tests complete.
*/
public function includes() {
// Admin messages (for any promos etc)
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.PluginAdminNotices.php';
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_startTimer( 'includes' );
}
// =================== / General Perf Testing =========================
// ====================================================================
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.GeneralFuncs.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Core.DateTime.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.AdminPages.Checks.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.ScriptsStyles.php';
// } Settings
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Config.Init.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'wh.config.lib.php';
// } WP REST API SUPPORT (better performant AJAX)
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.REST.php';
// } General store of Error Codes
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.ErrorCodes.php';
// Language modifiers (e.g. Company -> Organisation)
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-language.php';
// Segment conditions
require_once ZEROBSCRM_INCLUDE_PATH . 'class-segment-condition.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-segment-conditions.php';
// Generic CRM exceptions
require_once ZEROBSCRM_INCLUDE_PATH . 'class-crm-exception.php';
// WordPress user integrations
require_once ZEROBSCRM_INCLUDE_PATH . 'class-wordpress-user-integration.php';
// Endpoint Listener
require_once ZEROBSCRM_INCLUDE_PATH . 'class-endpoint-listener.php';
// OAuth Handler
require_once ZEROBSCRM_INCLUDE_PATH . 'class-oauth-handler.php';
// } DATA
// DAL3
// Here we include:
// - DAL 3 (base class)
// - DAL 3 Objects
// - DAL3.Helpers.php (our helper funcs)
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.php';
// 3.0 DAL objs:
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.ObjectLayer.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Contacts.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Companies.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Segments.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'class-segment-condition-exception.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'class-missing-settings-exception.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Quotes.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.QuoteTemplates.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Invoices.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Transactions.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Forms.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Events.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.EventReminders.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.Logs.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Obj.LineItems.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Export.php';
// helper funcs
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Helpers.php';
// drop-in-replacement for previous global fields (uses models from objs now.)
// NOTE: Rather than initially hard-typed, this now needs to WAIT until DAL3 initialised
// ... so field Globals available LATER in build queue in DAL3+
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL3.Fields.php';
// } Metaboxes v3.0
// Root classes
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBox.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Logs.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Tags.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.ExternalSources.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Contacts.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Companies.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.TagManager.php';
// } 3.0 + ALL are in our metaboxes
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Quotes.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.QuoteTemplates.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Invoices.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Ownership.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Tasks.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Transactions.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MetaBoxes3.Forms.php';
// NO CPTs! YAY!
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.ExternalSources.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DataIOValidation.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Database.php';
// } Split out DAL2:
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DAL2.Mail.php';
// } Admin Pages
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.AdminStyling.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.AdminPages.php';
require_once ZEROBSCRM_PATH . 'admin/tags/tag-manager.page.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.FormatHelpers.php';
// } Dashboard Boxes - WH Q why do we also need to define VARS for these, require once only requires once, right?
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.DashboardBoxes.php';
// } The kitchen sink
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Migrations.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Core.Localisation.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-localisation.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Core.Extensions.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Actions.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Core.Menus.WP.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Core.Menus.Top.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Core.License.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'class-learn-menu.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Permissions.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.ScreenOptions.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Inventory.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-rewrite-rules.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-mail-templating.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-templating.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-templating-placeholders.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.MailTracking.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.InternalAutomator.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.CRON.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Social.php';
// } Secondary
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.AJAX.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.WYSIWYGButtons.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.CustomerFilters.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.InternalAutomatorRecipes.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.FileUploads.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Forms.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.InvoiceBuilder.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.QuoteBuilder.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.SystemChecks.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.IntegrationFuncs.php';
// Temporarily removed until MC2 catches up + finishes Mail Delivery:
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Mail.php';
// } OBJ List Class (ZeroBSCRM.List.php) & List render funcs (ZeroBSCRM.List.Views.php) & List Column data
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.List.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.List.Views.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.List.Columns.php';
// } OBJ Edit & Delete Classes (ZeroBSCRM.Edit.php)
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Edit.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Delete.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.TagManager.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Core.Page.Controller.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Edit.Segment.php';
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.List.Tasks.php';
// } Semantic UI Helper + columns list
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.SemanticUIHelpers.php';
// } Put Plugin update message (notifications into the transient /wp-admin/plugins.php) page.. that way the nag message is not needed at the top of pages (and will always show, not need to be dismissed)
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.PluginUpdates.php';
// } FROM PLUGIN HUNT THEME - LOT OF USEFUL CODE IN HERE.
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.NotifyMe.php';
// load dependency checker (since 4.5.0)
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-dependency-checker.php';
// load feature sniffer (since 4.5.0)
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-feature-sniffer.php';
if ( defined( 'WP_CLI' ) && WP_CLI ) {
// if we need CLI stuff
}
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_closeGlobalTest( 'includes' );
}
// =================== / General Perf Testing =========================
// ====================================================================
}
/**
* Hook into actions and filters.
*
* @since 2.3
*/
private function init_hooks() {
// Pre-init Hook
do_action( 'before_zerobscrm_init' );
// our 'pre-init', this is the last step before init
// ... and loads settings :)
// add_action('admin_init', array($this, 'preInit'), 1);
add_action( 'init', array( $this, 'preInit' ), 1 );
// our formal init
add_action( 'init', array( $this, 'init' ), 10 );
// post init (init 99)
add_action( 'init', array( $this, 'postInit' ), 99 );
// Admin init - should condition this per page..
add_action( 'admin_init', array( $this, 'admin_init' ) );
// Extension links
add_filter( 'plugin_action_links_' . plugin_basename( ZBS_ROOTFILE ), array( $this, 'add_action_links' ) );
// Row meta
add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_row_meta' ), 10, 2 );
// Install/uninstall - use uninstall.php here
register_deactivation_hook( ZBS_ROOTFILE, array( $this, 'uninstall' ) );
// CRM top menu
add_action( 'wp_after_admin_bar_render', 'zeroBSCRM_admin_top_menu', 10 );
// Learn menu
// Note the priority here. This causes the "learn" block to present after the top menu
add_action( 'wp_after_admin_bar_render', array( $this, 'initialise_learn_menu' ), 11 );
// Run late-stack events, e.g. post-loaded migrations, exports
// note: this fires AFTER all advanced segments loaded, reliably
add_action( 'wp_loaded', array( $this, 'post_wp_loaded' ) );
}
public function filterExtensions( $extensions_array = false ) {
$extensions_array = apply_filters( 'zbs_extensions_array', $extensions_array );
// remove dupes - even this doesn't seem to remove the dupes!
return array_unique( $extensions_array );
}
// load initial external sources
private function loadBaseExternalSources() {
// simply loads our initial set from array, for now.
$this->external_sources = zeroBS_baseExternalSources();
}
// load any extra hooked-in external sources
private function loadExtraExternalSources() {
// load initials if not loaded/borked
if ( ! is_array( $this->external_sources ) || count( $this->external_sources ) < 1 ) {
// reload initial
$this->loadBaseExternalSources();
}
// should be guaranteed that this->external_sources is an array now, but if for god-knows what reason, it's not, error.
if ( ! is_array( $this->external_sources ) ) {
// error out? (hard error not useful as err500's peeps)
// ... rude text? (no translation, this way if someone EVER sees, they'll hopefully tell us)
echo 'CRM ERROR #399: No external sources!<br>';
// should NEVER happen:
$this->external_sources = array();
}
// NOW we apply any filters to a blank array, then merge that with our HARD typed array to insure we never LOOSE originals
$newExtSources = $this->filterExternalSources( array() );
// ^^ this is kind of miss-use of filters, but it'll work well here.
// if anything to add, manually parse here (for complete control)
if ( is_array( $newExtSources ) && count( $newExtSources ) > 0 ) {
foreach ( $newExtSources as $extKey => $extDeets ) {
// will look like this:
// $external_sources['woo'] = array('WooCommerce', 'ico' => 'fa-shopping-cart');
// override/add to main (if checks out):
if ( is_string( $extKey ) && ! empty( $extKey ) && is_array( $extDeets ) && count( $extDeets ) > 0 ) {
// seems in right format
$this->external_sources[ $extKey ] = $extDeets;
}
} // / if any new to add
}
// at this point $this->external_sources should be fully inline with apply_filter's added,
// but will NEVER lack the original 'pack'
// and 100% will be an array.
}
// simply applies filters to anny passed array
// NOTE: From 2.97.7 this is only taken as a 'second' layer, as per loadExtraExternalSources() above.
// ... so it can stay super simple.
public function filterExternalSources( $approved_sources = false ) {
return apply_filters( 'zbs_approved_sources', $approved_sources );
}
// } Build-out Object Models
public function buildOutObjectModels() {
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_startTimer( 'customfields' );
}
// =================== / General Perf Testing =========================
// ====================================================================
// } Unpack Custom Fields + Apply sorts
zeroBSCRM_unpackCustomFields();
zeroBSCRM_unpackCustomisationsToFields();
if ( 1 == 1 ) { // } switch off for perf?
zeroBSCRM_applyFieldSorts();
}
// } Unpacks any settings logged against listview setups
zeroBSCRM_unpackListViewSettings();
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_closeGlobalTest( 'customfields' );
}
// =================== / General Perf Testing =========================
// ====================================================================
}
public function add_action_links( $links ) {
global $zbs;
$mylinks = array(
'<a href="' . zeroBSCRM_getAdminURL( $zbs->slugs['settings'] ) . '">' . __( 'Settings', 'zero-bs-crm' ) . '</a>',
'<a href="' . zeroBSCRM_getAdminURL( $zbs->slugs['extensions'] ) . '">' . __( 'Extensions', 'zero-bs-crm' ) . '</a>',
);
return array_merge( $mylinks, $links );
}
/**
* Show row meta on the plugin screen for Jetpack CRM plugin.
*
* @param mixed $links_array Plugin Row Meta.
* @param mixed $plugin Plugin Base Name.
*
* @return array
*/
public static function plugin_row_meta( $links_array, $plugin ) {
if ( ! str_contains( $plugin, plugin_basename( ZBS_ROOTFILE ) ) ) {
return $links_array;
}
global $zbs;
$row_meta = array(
'docs' => '<a href="' . esc_url( $zbs->urls['docs'] ) . '" aria-label="' . esc_attr__( 'Jetpack CRM knowledgebase', 'zero-bs-crm' ) . '" target="_blank">' . esc_html__( 'Docs', 'zero-bs-crm' ) . '</a>',
);
##WLREMOVE
$license_key_array = zeroBSCRM_getSetting( 'license_key' );
if ( is_array( $license_key_array ) && ! empty( $license_key_array['key'] ) ) {
$row_meta['account'] = '<a href="' . esc_url( $zbs->urls['account'] ) . '" aria-label="' . esc_attr__( 'Your account', 'zero-bs-crm' ) . '" target="_blank">' . esc_html__( 'Your account', 'zero-bs-crm' ) . '</a>';
}
##/WLREMOVE
return array_merge( $links_array, $row_meta );
}
public function post_init_plugins_loaded() {
// } renamed to postSettingsIncludes and moved into that flow, (made more logical sense)
// Veriy extension requirements
$this->verify_extension_minimum_requirements();
// } Forms - only initiate if installed :)
if ( zeroBSCRM_isExtensionInstalled( 'forms' ) ) {
zeroBSCRM_forms_includeEndpoint();
}
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_closeGlobalTest( 'postsettingsincludes' );
}
// =================== / General Perf Testing =========================
// ====================================================================
}
public function preInit() {
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_startTimer( 'preinit' );
}
// =================== / General Perf Testing =========================
// ====================================================================
global $zeroBSCRM_Conf_Setup, $zbscrmApprovedExternalSources;
// } Init DAL (DAL2, now always enabled)
$this->DAL = new zbsDAL();
// } ASAP after DAL is initialised, need to run this, which DEFINES all DAL3.Obj.Models into old-style $globalFieldVars
// } #FIELDLOADING'
zeroBSCRM_fields_initialise();
// } Setup Config (centralises version numbers temp)
global $zeroBSCRM_Conf_Setup;
$zeroBSCRM_Conf_Setup['conf_pluginver'] = $this::VERSION; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
$zeroBSCRM_Conf_Setup['conf_plugindbver'] = $this->db_version;
// Not needed yet :) do_action( 'before_zerobscrm_settings_init' );
// } Init settings + sources
$this->settings = new WHWPConfigLib( $zeroBSCRM_Conf_Setup );
// register any modules with core
$this->jpcrm_register_modules();
// external sources, load, then initially filter
$this->loadBaseExternalSources();
$this->loadExtraExternalSources();
// This just sets up metaboxes (empty array for now) - see zeroBSCRM_add_meta_box in Edit.php
if ( ! is_array( $this->metaboxes ) ) {
$this->metaboxes = array();
}
// } This houses includes which need to fire post settings model load
// NOTE: BECAUSE this has some things which add_action to init
// ... this MUST fire on init with a priority of 1, so that these still "have effect"
$this->postSettingsIncludes();
// TEMP (ext update for 2.5 notice):
if ( defined( 'ZBSTEMPLEGACYNOTICE' ) ) {
zeroBS_temp_ext_legacy_notice();
}
// Legacy support for pre v2.50 settings in extensions
zeroBSCRM_legacySupport();
// load dependency checker for any modules/extensions
$this->dependency_checker = new JPCRM_DependencyChecker();
// load feature sniffer to alert user to available integrations
##WLREMOVE
$this->feature_sniffer = new JPCRM_FeatureSniffer();
$this->jpcrm_sniff_features();
##/WLREMOVE
// load WordPress User integrations
$this->wordpress_user_integration = new Automattic\JetpackCRM\Wordpress_User_Integration();
// fire an action
do_action( 'after_zerobscrm_settings_preinit' );
// load included modules
// this needs to be fired early so modules can hook into third-party plugin actions/filters
do_action( 'jpcrm_load_modules' );
// Where on frontend, load our endpoint listener and OAuth handler
if ( $this->is_request( 'frontend' ) && ! $this->is_request( 'ajax' ) ) {
// load
$this->load_oauth_handler();
$this->load_listener();
// catch listener requests (if any)
$this->listener->catch_listener_request();
}
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_closeGlobalTest( 'preinit' );
}
// =================== / General Perf Testing =========================
// ====================================================================
}
public function postSettingsIncludes() {
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_startTimer( 'postsettingsincludes' );
}
// =================== / General Perf Testing =========================
// ====================================================================
// } extensions :D - here are files that don't need including if they're switched off...
// } ^^ can probably include this via free extension manager class (longer term tidier?)
// WH addition: this was firing PRE init (you weren't seeing because no PHP warnings...needs to fire after)
// } free extensions setup (needs to be post settings)
zeroBSCRM_freeExtensionsInit();
// } CSV Importer LITE
// } only run all this is no PRO installed :)
if ( ! zeroBSCRM_isExtensionInstalled( 'csvpro' ) && zeroBSCRM_isExtensionInstalled( 'csvimporterlite' ) && ! defined( 'ZBSCRM_INC_CSVIMPORTERLITE' ) ) {
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.CSVImporter.php';
}
// } API
if ( zeroBSCRM_isExtensionInstalled( 'api' ) && ! defined( 'ZBSCRM_INC_API' ) ) {
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.API.php';
}
// } If zbs admin: Tour
if ( zeroBSCRM_isZBSAdminOrAdmin() && ! defined( 'ZBSCRM_INC_ONBOARD_ME' ) ) {
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.OnboardMe.php';
}
// If usage tracking is active - include the tracking code.
$this->load_usage_tracking();
if ( zeroBSCRM_isExtensionInstalled( 'jetpackforms' ) ) {
// } Jetpack - can condition this include on detection of Jetpack - BUT the code in Jetpack.php only fires on actions so will be OK to just include
require_once ZEROBSCRM_INCLUDE_PATH . 'ZeroBSCRM.Jetpack.php';
}
}
// } Initialisation - enqueueing scripts/styles
public function init() {
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_startTimer( 'init' );
}
// =================== / General Perf Testing =========================
// ====================================================================
// this catches zbs_customers who may be accessing backend (shouldn't)
$this->checkBackendAccess();
global $zeroBSCRM_Conf_Setup, $zeroBSCRM_extensionsInstalledList, $zbscrmApprovedExternalSources;
// unpack custom fieldsbuildOutObjectModels
// #} #FIELDLOADING
$this->buildOutObjectModels();
// } Unpacks any settings logged against listview setups
zeroBSCRM_unpackListViewSettings();
// } Post settings hook - all meta views load in this hook :)
// this has to fire for public + admin (things like mail campaigns rely on this for link tracking)
do_action( 'after_zerobscrm_settings_init' );
// } this needs to be post settings
$this->extensions = $this->filterExtensions( $zeroBSCRM_extensionsInstalledList );
// } Post extensions loaded hook
do_action( 'after_zerobscrm_ext_init' );
// } Load the admin menu. Can consider in here the 'ORDER' of the menu
// } As well where extensions put their settings too
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
$this->include_updater();
// Admin unlock for ZBS users if WooCommerce installed
zeroBSCRM_wooCommerceRemoveBlock();
// Registers stuff that needs settings etc.
$this->post_init_plugins_loaded();
// run migrations
$this->run_migrations( 'init' );
// } Brutal override for feeding in json data to typeahead
// WH: should these be removed now we're using REST?
if ( isset( $_GET['zbscjson'] ) && is_user_logged_in() && zeroBSCRM_permsCustomers() ) {
// This function outputs JSON-encoded contacts and exits.
zeroBSCRM_cjson();
} elseif ( isset( $_GET['zbscojson'] ) && is_user_logged_in() && zeroBSCRM_permsCustomers() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
// This function outputs JSON-encoded companies and exits.
zeroBSCRM_cojson();
}
// } Catch Dashboard + redir (if override mode)
// } but not for wp admin (wptakeovermodeforall)
if ( $this->settings->get( 'wptakeovermode' ) == 1 ) {
// Not if API or Client Portal...
// ... moved them inside this func..
zeroBSCRM_catchDashboard();
}
// } JUST before cpt, we do any install/uninstall of extensions, so that cpt's can adjust instantly:
zeroBSCRM_extensions_init_install();
// } Here we do any 'default content' installs (quote templates) (In CPT <DAL3, In DAL3.Helpers DAL3+)
zeroBSCRM_installDefaultContent();
// } Admin & Public req
wp_enqueue_script( 'jquery' );
// } Post Init hook
do_action( 'zerobscrm_post_init' );
// } Public & non wp-cli only
if ( ! is_admin() && ! defined( 'WP_CLI' ) ) {
// } Catch front end loads :)
if ( $this->settings->get( 'killfrontend' ) == 1 ) {
global $pagenow;
if ( ! zeroBSCRM_isLoginPage()
&& ! zeroBSCRM_isWelcomeWizPage()
&& ! zeroBSCRM_isAPIRequest()
&& ! defined( 'XMLRPC_REQUEST' )
&& ! defined( 'REST_REQUEST' )
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
&& ! ( 'index.php' === $pagenow && ! empty( $_GET['rest_route'] ) )
) {
zeroBSCRM_stopFrontEnd();
}
}
}
// } Finally, if it's an edit page for a (obj) which is hard owned by another, redir away
// if admin, ignore :)
if ( $this->settings->get( 'perusercustomers' ) && ! zeroBSCRM_isZBSAdminOrAdmin() ) {
// } Using ownership
if ( ! $this->settings->get( 'usercangiveownership' ) ) {
// } is one of our dal3 edit pages
if ( zeroBSCRM_is_zbs_edit_page() ) {
// in this specific case we pre-call globalise_vars
// ... which later gets recalled if on an admin page (but it's safe to do so here too)
// this moves any _GET into $zbsPage
$this->globalise_vars();
// this allows us to use these:
$obj_id = $this->zbsvar( 'zbsid' ); // -1 or 123 ID
$obj_type_str = $this->zbsvar( 'zbstype' ); // -1 or 'contact'
// if objtypestr is -1, assume contact (default)
if ( $obj_type_str === -1 ) {
$obj_type_id = ZBS_TYPE_CONTACT;
} else {
$obj_type_id = $this->DAL->objTypeID( $obj_type_str ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
}
// if is edit page + has obj id, (e.g. is not "new")
// then check ownership
if ( isset( $obj_id ) && $obj_id > 0 && $obj_type_id > 0 ) {
$is_ownership_valid = $this->DAL->checkObjectOwner( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
array(
'objID' => $obj_id,
'objTypeID' => $obj_type_id,
'potentialOwnerID' => get_current_user_id(),
'allowNoOwnerAccess' => true, // ?
)
);
// } If user ! has rights, redir
if ( ! $is_ownership_valid ) {
// Redirect to our "no rights" page
// OLD WAY header("Location: edit.php?post_type=".$postType."&page=".$this->slugs['zbs-noaccess']."&id=".$postID);
header( 'Location: admin.php?page=' . $this->slugs['zbs-noaccess'] . '&zbsid=' . $obj_id . '&zbstype=' . $obj_type_str );
exit( 0 );
} // / no rights.
} // / obj ID
} // / is edit page
} // / is setting usercangiveownership
} // / !is admin
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_closeGlobalTest( 'init' );
}
// =================== / General Perf Testing =========================
// ====================================================================
}
public function postInit() {
// pre 2.97.7:
// WH note: filterExternalSources() above didn't seem to be adding them all (stripesync e.g. was being added on init:10)
// ... so this gets called a second time (should be harmless) at init:99 (here)
// $this->external_sources = $this->filterExternalSources($this->external_sources);
// 2.97.7, switched to this, a more ROBUST check which only 'adds' and won't remove.
$this->loadExtraExternalSources();
// this allows various extensions to add users AFTER external sources def loaded
do_action( 'after_zerobscrm_extsources_init' );
// This action should replace after_zerobscrm_extsources_init when we refactor load order in this class.
// initially used by advanced segments to add custom field segment condition classes after the class is declared in jpcrm-segment-conditions.php
do_action( 'jpcrm_post_init' );
$default_listview_filters = array();
$this->listview_filters = apply_filters( 'jpcrm_listview_filters', $default_listview_filters );
// this allows us to do stuff (e.g. redirect based on a condition) prior to headers being sent
$this->catch_preheader_interrupts();
}
/**
* Fires after CRM and WP fully loaded
* (Late in stack)
**/
public function post_wp_loaded() {
// Run any migrations
$this->run_migrations( 'wp_loaded' );
// do our late-fire actions
do_action( 'jpcrm_post_wp_loaded' );
}
/**
* Fires on admin_init
**/
public function admin_init() {
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_startTimer( 'admin_init' );
}
// =================== / General Perf Testing =========================
// ====================================================================
// Autoload AJAX files for any admin pages
$this->load_admin_ajax();
// only load if we are a ZBS admin page? Will this break the world?!?
if ( zeroBSCRM_isAdminPage() ) {
// catch wiz + redirect
$this->wizardInitCheck();
// Let's ensure that our cronjobs are there
if ( ! wp_next_scheduled( 'jpcrm_cron_watcher' ) ) {
jpcrm_cron_watcher();
}
// apply any filters req. to the exclude-from-settings arr
global $zbsExtensionsExcludeFromSettings;
$zbsExtensionsExcludeFromSettings = apply_filters( 'zbs_exclude_from_settings', $zbsExtensionsExcludeFromSettings );
// this moves any _GET into $zbsPage
$this->globalise_vars();
// this sets page titles where it can ($this->setPageTitle();)
add_filter( 'zbs_admin_title_modifier', array( $this, 'setPageTitle' ), 10, 2 );
// This is a pre-loader for edit page classes, allows us to save data before loading the page :)
zeroBSCRM_prehtml_pages_admin_addedit();
// Again, necessary? do_action('before_zerobscrm_admin_init');
// All style registering moved into ZeroBSCRM.ScriptsStyles.php for v3.0, was getting messy
zeroBSCRM_scriptStyles_initStyleRegister();
// JS Root obj (zbs_root)
zeroBSCRM_scriptStyles_enqueueJSRoot();
// Check for stored messages in case we were redirected.
$this->maybe_retrieve_page_messages();
// autohide admin_notices on pages we specify
jpcrm_autohide_admin_notices_for_specific_pages();
}
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_closeGlobalTest( 'admin_init' );
}
// =================== / General Perf Testing =========================
// ====================================================================
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_startTimer( 'after-zerobscrm-admin-init' );
}
// =================== / General Perf Testing =========================
// ====================================================================
// Action hook
do_action( 'after-zerobscrm-admin-init' );
// ====================================================================
// ==================== General Perf Testing ==========================
if ( defined( 'ZBSPERFTEST' ) ) {
zeroBSCRM_performanceTest_closeGlobalTest( 'after-zerobscrm-admin-init' );
}
// =================== / General Perf Testing =========================
// ====================================================================
}
// this checks whether any extensions are active which might bring down an install to 500 error
// backstop in case extensions used which don't deactivate for whatver reason (being doubly sure in core)
// as part of UX work also make sure all extensions are classified and only load when core hook triggers
// some users were still hitting 500 errors so worth having this in place to protect us / help retain / PICNIC
// wh renamed: check_active_zbs_extensions -> pre_deactivation_check_exts_deactivated
function pre_deactivation_check_exts_deactivated() {
global $zbs;
// } from telemetry however what if someone has extensions installed this should show up
// } this is the full count (not whether they are active)
$extensions_installed = zeroBSCRM_extensionsInstalledCount( true );
if ( $extensions_installed > 0 ) {
// tried to add an error above the plugins.php list BUT it did not seem to show
// instead re-direct to one of our pages which tells them about making sure extensions are
// deactivated before deactivating core
wp_safe_redirect( admin_url( 'admin.php?page=' . $zbs->slugs['extensions-active'] ) );
die( 0 ); // will killing it here stop deactivation?
// failsafe?
return false;
}
return true;
}
public function uninstall() {
// Deactivate all the extensions
zeroBSCRM_extensions_deactivateAll();
// Skip the deactivation feedback if it's a JSON/AJAX request or via WP-CLI
if ( wp_doing_ajax() || wp_is_json_request() || ( defined( 'WP_CLI' ) && WP_CLI ) || wp_is_xml_request() ) {
return;
}
##WLREMOVE
// Remove roles :)
zeroBSCRM_clearUserRoles();
// Skip redirect if it's a bulk deactivation with more than one plugin.
if (
// phpcs:disable WordPress.Security.NonceVerification.Recommended,WordPress.Security.NonceVerification.Missing -- This is safe.
isset( $_POST['action'] )
&& $_POST['action'] === 'deactivate-selected'
&& isset( $_POST['checked'] )
&& count( $_POST['checked'] ) > 1
// phpcs:enable WordPress.Security.NonceVerification.Recommended,WordPress.Security.NonceVerification.Missing -- This is safe.
) {
return;
}
$feedbackAlready = get_option( 'zbsfeedback' );
// if php notice, (e.g. php ver to low, skip this)
if ( ! defined( 'ZBSDEACTIVATINGINPROG' ) && $feedbackAlready == false && ! defined( 'ZBSPHPVERDEACTIVATE' ) ) {
// } Show stuff + Deactivate
// } Define is to stop an infinite loop :)
// } (Won't get here the second time)
define( 'ZBSDEACTIVATINGINPROG', true );
// } Before you go...
if ( function_exists( 'file_get_contents' ) ) {
// } telemetry
// V3.0 No more telemetry if (!zeroBSCRM_isWL()) zeroBSCRM_teleLogAct(3);
try {
// } Also manually deactivate before exit
deactivate_plugins( plugin_basename( ZBS_ROOTFILE ) );
// } require template
require_once ZEROBSCRM_PATH . 'admin/activation/before-you-go.php';
exit( 0 );
} catch ( Exception $e ) {
// } Nada
}
}
}
##/WLREMOVE
// } //end of check if there are extensions active
}
public function install() {
// dir build
zeroBSCRM_privatisedDirCheck();
zeroBSCRM_privatisedDirCheckWorks(); // the folder used to be '_wip', updated to 'tmp'
// Additional DB tables hook on activation (such as api keys table) - requires ZeroBSCRM.Database.php
zeroBSCRM_database_check();
// roles
zeroBSCRM_clearUserRoles();
// roles +
zeroBSCRM_addUserRoles();
}
// this func runs on admin_init and xxxx
public function wizardInitCheck() {
// not authorized to run the wizard
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$force_wizard = false;
// reset any wizard overrides if URL param is present
if ( ! empty( $_GET['jpcrm_force_wizard'] ) ) {
delete_option( 'jpcrm_skip_wizard' );
delete_transient( 'jpcrm_defer_wizard' );
$force_wizard = true;
}
// set option if URL param
if ( ! empty( $_GET['jpcrm_skip_wizard'] ) ) {
update_option( 'jpcrm_skip_wizard', 1, false );
}
// wizard was purposely skipped
if ( get_option( 'jpcrm_skip_wizard' ) ) {
return;
}
// set transient if URL param
if ( ! empty( $_GET['jpcrm_defer_wizard'] ) ) {
set_transient( 'jpcrm_defer_wizard', 1, 30 );
}
// Skip wizard temporarily if transient is set
// this can be used for Jetpack CTA installs, for example
if ( get_transient( 'jpcrm_defer_wizard' ) ) {
return;
}
// Bail if activating from network, or bulk
if ( is_network_admin() ) { // WH removed this, if bulk, still do it :D || isset( $_GET['activate-multi'] ) ) {
return;
}
##WLREMOVE
// Bail if already completed wizard
// $run_count increments each time the wizard is loaded
// always run if forced
$run_count = get_option( 'zbs_wizard_run', 0 );
if ( $run_count <= 0 || $force_wizard ) {
// require welcome wizard template
require_once ZEROBSCRM_PATH . 'admin/activation/welcome-to-jpcrm.php';
exit( 0 );
}
##/WLREMOVE
}
/**
* Loads the Plugin Updater Class
*
* @since 2.97.x
*/
public function include_updater() {
// } Initialise ZBS Updater Class
global $zeroBSCRM_Updater;
if ( ! isset( $zeroBSCRM_Updater ) ) {
$zeroBSCRM_Updater = new zeroBSCRM_Plugin_Updater(
$this->urls['api'],
$this->update_api_version,
ZBS_ROOTFILE,
array(
'version' => $this::VERSION,
'license' => false, // license initiated to false..
)
);
}
}
/**
*
* Autoloads the modules (core extensions) included with core
*
* Ultimately we should probably include Jetpack Forms and maybe CSV Importer.
*
* Modularisation of this manner may allow easier drop-in integrations by third-party devs as well.
*/
public function jpcrm_register_modules() {
// include modules class
require_once ZEROBSCRM_INCLUDE_PATH . 'class-crm-modules.php';
// load it (which registers modules and creates $zbs->modules)
$this->modules = new Automattic\JetpackCRM\CRM_Modules();
}
/**
*
* Check to see if there's an integration our users could be using
* At some point we should modularize this as well
*/
public function jpcrm_sniff_features() {
$this->feature_sniffer->sniff_for_plugin(
array(
'feature_slug' => 'jetpackforms',
'plugin_slug' => 'jetpack/jetpack.php',
'more_info_link' => 'https://kb.jetpackcrm.com/knowledge-base/jetpack-contact-forms/',
)
);
do_action( 'jpcrm_sniff_features' );
$this->feature_sniffer->show_feature_alerts();
}
/**
* Ensures fatal errors are logged so they can be picked up in the status report.
*
* @since 3.2.0
*/
public function log_errors() {
$error = error_get_last();
if ( E_ERROR === $error['type'] ) {
$this->write_log( $error['message'] . PHP_EOL ); // check this method.. should be OK
}
}
public function write_log( $log ) {
if ( is_array( $log ) || is_object( $log ) ) {
error_log( print_r( $log, true ) );
} else {
error_log( $log );
}
}
/**
* Define constant if not already set.
*
* @param string $name Constant name.
* @param string|bool $value Constant value.
*/
private function define( $name, $value ) {
if ( ! defined( $name ) ) {
define( $name, $value );
}
}
/**
* What type of request is this?
* Note: 'frontend' returns true for ajax calls too.
*
* @param string $type admin, ajax, cron or frontend.
* @return bool
*/
private function is_request( $type ) {
switch ( $type ) {
case 'admin':
return is_admin();
case 'ajax':
return defined( 'DOING_AJAX' );
case 'cron':
return defined( 'DOING_CRON' );
case 'frontend':
return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' );
}
}
/**
* Check the active theme.
*
* @since 2.6.9
* @param string $theme Theme slug to check.
* @return bool
*/
private function is_active_theme( $theme ) {
return get_template() === $theme;
}
/**
* Include required frontend files.
*/
public function frontend_includes() {
}
/**
* Get the plugin url.
*
* @return string
*/
public function plugin_url() {
return untrailingslashit( plugins_url( '/', ZBS_ROOTFILE ) );
}
/**
* Get the plugin path.
*
* @return string
*/
public function plugin_path() {
return untrailingslashit( plugin_dir_path( ZBS_ROOTFILE ) );
}
/**
* Check if Settings exists, load default if not
*
* @return string
*/
public function checkSettingsSetup() {
global $zeroBSCRM_Conf_Setup;
if ( ! isset( $this->settings ) ) {
$this->settings = null; // https://stackoverflow.com/questions/8900701/creating-default-object-from-empty-value-in-php
$this->settings = new WHWPConfigLib( $zeroBSCRM_Conf_Setup );
}
}
/**
* Check if user has capabilities to view backend :)
*
* @return string
*/
public function checkBackendAccess() {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return;
}
// if zbs_customer in admin area, kick em out :)
if ( zeroBSCRM_isRole( 'zerobs_customer' ) ) {
if ( is_admin() ) {
$redirect = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : home_url( '/' );
if ( current_user_can( 'zerobs_customer' ) ) {
wp_redirect( $redirect );
exit( 0 );
}
}
// and remove wp bar from front end
add_filter( 'show_admin_bar', '__return_false' );
}
}
/**
* Get Ajax URL.
*
* @return string
*/
public function ajax_url() {
return admin_url( 'admin-ajax.php', 'relative' );
}
/**
* Get Site Domain
*
* @return string
*/
public function get_domain() {
$urlparts = parse_url( home_url() );
if ( isset( $urlparts['host'] ) ) {
return $urlparts['host'];
}
return false;
}
/**
* Globalise ZBS Vars
*
* @return nout
*/
public function globalise_vars() {
// here, where things are consistently used through a page
// e.g. admin.php?page=zbs-add-edit&action=edit&zbsid=3
// we globally set them to save time later :)
global $zbsPage;
$zbsPage = array();
// zbsid
if ( isset( $_GET['zbsid'] ) && ! empty( $_GET['zbsid'] ) ) {
$zbsid = (int) sanitize_text_field( $_GET['zbsid'] );
// if $zbsid is set, make it a GLOBAL (save keep re-getting)
// this is used by metaboxes, insights + hypothesis, titles below etc. DO NOT REMOVE
if ( $zbsid > 0 ) {
$zbsPage['zbsid'] = $zbsid;
}
}
// page
if ( isset( $_GET['page'] ) && ! empty( $_GET['page'] ) ) {
$page = sanitize_text_field( $_GET['page'] );
// if $page is set, make it a GLOBAL (save keep re-getting)
// this is used by metaboxes, insights + hypothesis, titles below etc. DO NOT REMOVE
if ( ! empty( $page ) ) {
$zbsPage['page'] = $page;
}
}
// action
if ( isset( $_GET['action'] ) && ! empty( $_GET['action'] ) ) {
$action = sanitize_text_field( $_GET['action'] );
// if $action is set, make it a GLOBAL (save keep re-getting)
// this is used by metaboxes, insights + hypothesis, titles below etc. DO NOT REMOVE
if ( ! empty( $action ) ) {
$zbsPage['action'] = $action;
}
}
// type
if ( isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ) {
$type = sanitize_text_field( $_GET['type'] );
// if $type is set, make it a GLOBAL (save keep re-getting)
// this is used by metaboxes, insights + hypothesis, titles below etc. DO NOT REMOVE
if ( ! empty( $type ) ) {
$zbsPage['type'] = $type;
}
}
// zbstype
if ( isset( $_GET['zbstype'] ) && ! empty( $_GET['zbstype'] ) ) {
$zbstype = sanitize_text_field( $_GET['zbstype'] );
// if $zbstype is set, make it a GLOBAL (save keep re-getting)
// this is used by metaboxes, insights + hypothesis, titles below etc. DO NOT REMOVE
if ( ! empty( $zbstype ) ) {
$zbsPage['zbstype'] = $zbstype;
}
}
// if action = 'edit' + no 'zbsid' = NEW EDIT (e.g. new contact)
if ( isset( $zbsPage['action'] ) && $zbsPage['action'] == 'edit' && ( ! isset( $zbsPage['zbsid'] ) || $zbsPage['zbsid'] < 1 ) ) {
$zbsPage['new_edit'] = true;
}
}
/**
* Get Globalised ZBS Vars
*
* @return string|int|bool
*/
public function zbsvar( $key = '' ) {
// globalise_vars returned
global $zbsPage;
// zbsid
if ( is_array( $zbsPage ) && ! empty( $key ) && isset( $zbsPage[ $key ] ) && ! empty( $zbsPage[ $key ] ) ) {
return $zbsPage[ $key ];
}
return -1;
}
/**
* Tries to set page title (where it can)
*
* @return nout
*/
public function setPageTitle( $title = '', $adminTitle = '' ) {
// default
$pageTitle = ( ( $adminTitle == '' ) ? __( 'Jetpack CRM', 'zero-bs-crm' ) : $adminTitle );
// we only need to do this for pages where we're using custom setups (not added via wp_add_menu whatever)
if ( $this->zbsvar( 'page' ) != -1 ) {
switch ( $this->zbsvar( 'page' ) ) {
case 'zbs-add-edit':
// default
$pageTitle = __( 'View | Jetpack CRM' . $this->zbsvar( 'action' ), 'zero-bs-crm' );
// default/no type passed
$objType = __( 'Contact', 'zero-bs-crm' );
switch ( $this->zbsvar( 'zbstype' ) ) {
case 'contact':
$objType = __( 'Contact', 'zero-bs-crm' );
break;
case 'company':
$objType = jpcrm_label_company();
break;
case 'segment':
$objType = __( 'Segment', 'zero-bs-crm' );
break;
case 'quote':
$objType = __( 'Quote', 'zero-bs-crm' );
break;
case 'invoice':
$objType = __( 'Invoice', 'zero-bs-crm' );
break;
case 'transaction':
$objType = __( 'Transaction', 'zero-bs-crm' );
break;
case 'event':
$objType = __( 'Task', 'zero-bs-crm' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
break;
case 'form':
$objType = __( 'Form', 'zero-bs-crm' );
break;
case 'quotetemplate':
$objType = __( 'Quote Template', 'zero-bs-crm' );
break;
case 'log':
$objType = __( 'Log', 'zero-bs-crm' );
break;
}
// just formatting:
if ( ! empty( $objType ) ) {
$objType = ' ' . $objType;
}
switch ( $this->zbsvar( 'action' ) ) {
case 'edit':
$pageTitle = __( 'Edit ' . $objType . ' | Jetpack CRM', 'zero-bs-crm' );
break;
case 'delete':
$pageTitle = __( 'Delete ' . $objType . ' | Jetpack CRM', 'zero-bs-crm' );
break;
case 'view':
$pageTitle = __( 'View ' . $objType . ' | Jetpack CRM', 'zero-bs-crm' );
break;
}
break;
case 'zerobscrm-emails':
// default
$pageTitle = __( 'Email Manager | Jetpack CRM', 'zero-bs-crm' );
break;
case 'tag-manager':
$pageTitle = __( 'Tag Manager | Jetpack CRM', 'zero-bs-crm' );
break;
case 'zerobscrm-notifications':
$pageTitle = __( 'Notifications | Jetpack CRM', 'zero-bs-crm' );
break;
case 'zbs-email-templates':
$pageTitle = __( 'Email Templates | Jetpack CRM', 'zero-bs-crm' );
break;
case 'zbs-export-tools':
$pageTitle = __( 'Export Tools | Jetpack CRM', 'zero-bs-crm' );
break;
case 'zerobscrm-csvimporterlite-app':
$pageTitle = __( 'Import Tools | Jetpack CRM', 'zero-bs-crm' );
break;
}
}
return $pageTitle;
}
/**
* Get Current User's screen options for current page
* This requires add_filter on page to work :)
* // actually just use a global for now :) - so just set global $zbs->pageKey on page :)
* // 2.94.2+ can pass pagekey to get opts for page other than current (used for list view perpage)
*
* @return array() screen options
*/
public function userScreenOptions( $pageKey = false ) {
// TO ADD LATER: (optionally) allow admins to create a 'forced' screen options set (e.g. metabox layout etc.)
// ... forced or default :)
$currentUserID = get_current_user_id();
if ( ! $pageKey ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
// actually just use a global for now :) - so just set global $zbs->pageKey on page :)
$pageKeyCheck = apply_filters( 'zbs_pagekey', $this->pageKey );
} else {
$pageKeyCheck = $pageKey;
}
if ( $currentUserID > 0 && ! empty( $pageKeyCheck ) ) {
// retrieve via dal
return $this->DAL->userSetting( $currentUserID, 'screenopts_' . $pageKeyCheck, false );
}
return array();
}
/**
* Get global screen option settings
*
* @param string $page_key Page key.
*/
public function global_screen_options( $page_key = false ) {
if ( empty( $page_key ) ) {
$page_key = apply_filters( 'zbs_pagekey', $this->pageKey ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
}
if ( empty( $page_key ) ) {
return array();
}
$screen_options = $this->DAL->getSetting( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
array(
'key' => 'screenopts_' . $page_key,
)
);
return $screen_options;
}
/**
* Shorthand for get_Current_user_id
*
* @return int user id
*/
public function user() {
return get_current_user_id();
}
/**
* Shorthand for zeroBSCRM_getSetting('license_key')
*
* @return array() license settings (trimmed down)
*/
public function license() {
// default
$ret = array(
'validity' => false,
'access' => 'none',
'expires' => -1,
);
// retrieve
$licenseKeyArr = zeroBSCRM_getSetting( 'license_key' );
// return only these (not key, for simple semi-security? lol. not even)
if ( is_array( $licenseKeyArr ) ) {
if ( isset( $licenseKeyArr['validity'] ) ) {
$ret['validity'] = $licenseKeyArr['validity'];
}
if ( isset( $licenseKeyArr['access'] ) ) {
$ret['access'] = $licenseKeyArr['access'];
}
if ( isset( $licenseKeyArr['expires'] ) ) {
$ret['expires'] = $licenseKeyArr['expires'];
}
}
return $ret;
}
/*
* Do we have a license key?
*/
public function has_license_key() {
$settings = $this->settings->get( 'license_key' );
// checks if exists and it's not empty
if ( ! empty( $settings['key'] ) ) {
return true;
}
return false;
}
/**
* Returns true/false if has AT LEAST entrepreneur Bundle
* ... suspect this is an easy way to HACK out show promotional material. So rethink around that at some point.
*
* @return bool
*/
public function hasEntrepreneurBundleMin() {
$license = $this->license();
$valid = array( 'entrepreneur', 'reseller' );
$license['validity'] = ( $license['validity'] === 'true' ? true : false );
if ( $license['validity'] && ( in_array( $license['access'], $valid ) ) ) {
return true;
}
return false;
}
/**
* Returns true/false if has AT LEAST entrepreneur Bundle
* ... suspect this is an easy way to HACK out show promotional material. So rethink around that at some point.
*
* @return bool
*/
public function hasFreelancerBundleMin() {
$license = $this->license();
$valid = array( 'freelancer', 'entrepreneur', 'reseller' );
$license['validity'] = ( $license['validity'] === 'true' ? true : false );
if ( $license['validity'] && ( in_array( $license['access'], $valid ) ) ) {
return true;
}
return false;
}
/**
* Returns pretty label for subscription
* ... suspect this is an easy way to HACK out show promotional material. So rethink around that at some point.
*
* @return string
*/
public function getSubscriptionLabel( $str = '' ) {
if ( empty( $str ) ) {
// get from license
$license = $this->license();
if ( isset( $license['validity'] ) ) {
$license['validity'] = ( $license['validity'] === 'true' ? true : false );
if ( $license['validity'] && isset( $license['access'] ) && ! empty( $license['access'] ) ) {
$str = $license['access'];
}
}
}
switch ( $str ) {
case 'freelancer':
return 'Freelancer Bundle';
break;
case 'entrepreneur':
return 'Entrepreneur Bundle';
break;
case 'reseller':
return 'Branded Bundle';
break;
// for all others, use this:
default:
return 'Extension: ' . ucwords( $str );
break;
}
return false;
}
// ======= Menu Management =========
/**
* Return private $menu
*
* @since 3.0
*/
public function getMenu() {
return $this->menu; }
/**
* Sets up admin menu
*
* @since 3.0
*/
public function admin_menu() {
$this->applyMenu();
// hook for extensions to add menus :)
do_action( 'zerobs_admin_menu' );
}
/**
* Applys admin menu
* (v3.0 + this replaces zeroBSCRM_admin_menu)
*
* @since 3.0
*/
private function applyMenu() {
// build init, if not there
if ( ! isset( $this->menu ) && ! is_array( $this->menu ) ) {
$this->menu = zeroBSCRM_menu_buildMenu();
}
// ready?
if ( isset( $this->menu ) && is_array( $this->menu ) ) {
// Here we apply filters, this allows other ext etc. to modify menu items before we priotise + build
$menu = apply_filters( 'zbs_menu_wpmenu', $this->menu );
// remove non-permissioned
$menu = zeroBSCRM_menu_securityGuard( $menu );
// resort based on 'order'
$menu = zeroBSCRM_menu_order( $menu );
// output (adds menus)
zeroBSCRM_menu_applyWPMenu( $menu );
}
}
/**
* Learn Menu
*
* @since 3.0
*/
public function initialise_learn_menu() {
$this->learn_menu = new Automattic\JetpackCRM\Learn_Menu();
// render the menu where possible
$this->learn_menu->render_learn_menu();
}
// ======= / Menu Management =========
// ========== Basic Library Management =========
/**
* Retrieve array of details for a library
* Returns: array() or false
*/
public function lib( $libKey = '' ) {
if ( isset( $this->libs[ $libKey ] ) && is_array( $this->libs[ $libKey ] ) ) {
// update path to use ZEROBSCRM_PATH
$ret = $this->libs[ $libKey ];
$ret['path'] = ZEROBSCRM_PATH . $this->libs[ $libKey ]['path'];
$ret['include'] = ZEROBSCRM_PATH . $this->libs[ $libKey ]['include'];
return $ret;
}
return false;
}
/**
* Retrieve root path for a library
* Returns: str or false
*/
public function libPath( $libKey = '' ) {
if ( isset( $this->libs[ $libKey ] ) && isset( $this->libs[ $libKey ]['path'] ) ) {
return ZEROBSCRM_PATH . $this->libs[ $libKey ]['path'];
}
return false;
}
/**
* Retrieve full include path for a library
* Returns: str or false
*/
public function libInclude( $libKey = '' ) {
if ( isset( $this->libs[ $libKey ] ) && isset( $this->libs[ $libKey ]['include'] ) ) {
return ZEROBSCRM_PATH . $this->libs[ $libKey ]['include'];
}
return false;
}
/**
* Returns the correct dompdf lib version depending on php compatibility
*
* @deprecated We no longer load Dompdf through this library system.
*
* @param string $lib_key The key/machine name.
* @return string
*/
private function checkDompdfVersion( $lib_key ) {
if ( $lib_key === 'dompdf' ) {
$lib_key = 'dompdf-2';
}
return $lib_key;
}
/*
* Returns bool, are we running on a PHP version $operator (e.g. '>=') to $version
*/
public function has_min_php_version( $php_version ) {
return version_compare( PHP_VERSION, $php_version, '>=' );
}
/**
* Retrieve version of a library
* Returns: str or false
*/
public function libVer( $libKey = '' ) {
if ( isset( $this->libs[ $libKey ] ) && isset( $this->libs[ $libKey ]['version'] ) ) {
return $this->libs[ $libKey ]['version'];
}
return false;
}
/**
* Check if library already loaded
* Returns: bool
*/
public function libIsLoaded( $libKey = '' ) {
if ( isset( $this->libs[ $libKey ] ) && isset( $this->libs[ $libKey ]['include'] ) && ! isset( $this->libs[ $libKey ]['loaded'] ) ) {
return false;
}
return true;
}
/**
* Load a library via include
* Returns: str or false
*/
public function libLoad( $libKey = '' ) {
if (
isset( $this->libs[ $libKey ] ) &&
isset( $this->libs[ $libKey ]['include'] ) &&
! isset( $this->libs[ $libKey ]['loaded'] ) &&
file_exists( ZEROBSCRM_PATH . $this->libs[ $libKey ]['include'] )
) {
require_once ZEROBSCRM_PATH . $this->libs[ $libKey ]['include'];
$this->libs[ $libKey ]['loaded'] = true;
}
return false;
}
/**
* Autoload files from a directory which match a regex filter
*/
public function autoload_from_directory( string $directory, string $regex_filter ) {
$files = scandir( $directory );
if ( is_array( $files ) ) {
foreach ( $files as $file ) {
// find files `*.ajax.*`
if ( preg_match( $regex_filter, $file ) ) {
// load it
require_once $directory . '/' . $file;
}
}
}
}
/**
* Autoload page AJAX
* (This should be fired on admin_init and later should be rethought to be true autoloading, not loading all AJAX partials as this does)
*/
private function load_admin_ajax() {
$admin_page_directories = jpcrm_get_directories( ZEROBSCRM_PATH . 'admin' );
if ( is_array( $admin_page_directories ) ) {
foreach ( $admin_page_directories as $directory ) {
$files = scandir( ZEROBSCRM_PATH . 'admin/' . $directory );
if ( is_array( $files ) ) {
foreach ( $files as $file ) {
// find files `*.ajax.*`
if ( strrpos( $file, '.ajax.' ) > 0 ) {
// load it
require_once ZEROBSCRM_PATH . 'admin/' . $directory . '/' . $file;
}
}
}
}
}
}
/**
* Runs migrations routine
*/
public function run_migrations( $run_at = 'init' ) {
// Run any migrations
zeroBSCRM_migrations_run( $this->settings->get( 'migrations' ), $run_at );
}
/**
* Centralised method for detecting presence of WooCommerce
*/
public function woocommerce_is_active() {
// check for Woo Presence
if ( is_plugin_active( 'woocommerce/woocommerce.php' ) || ( isset( $GLOBALS['woocommerce'] ) && $GLOBALS['woocommerce'] ) ) {
return true;
}
return false;
}
/**
* Centralised method for detecting presence of MailPoet
*/
public function mailpoet_is_active() {
// check for mailpoet Presence
if ( is_plugin_active( 'mailpoet/mailpoet.php' ) ) {
return true;
}
return false;
}
// ======= / Basic Library Management =========
// } If usage tracking is active - include the tracking code.
// =========== Resource Loading ===============
/**
* Loads usage tracking where user has accepted via settings
*/
public function load_usage_tracking() {
// load if not loaded, and permitted
if ( $this->tracking === false ) {
$tracking_active = zeroBSCRM_getSetting( 'shareessentials' );
if ( $tracking_active ) {
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-usage-tracking.php';
$this->tracking = new jpcrm_usage_tracking();
}
}
return $this->tracking;
}
/**
* Loads Endpoint Listener library
*/
public function load_listener() {
if ( ! isset( $this->listener ) || $this->listener == null ) {
$this->listener = new \Automattic\JetpackCRM\Endpoint_Listener();
}
return $this->listener;
}
/**
* Loads OAuth handler library
*/
public function load_oauth_handler() {
if ( ! isset( $this->oauth ) || $this->oauth == null ) {
$this->oauth = new \Automattic\JetpackCRM\Oauth_Handler();
}
return $this->oauth;
}
/**
* Loads Encryption library
*/
public function load_encryption() {
require_once ZEROBSCRM_INCLUDE_PATH . 'class-encryption.php';
if ( ! isset( $this->encryption ) || $this->encryption == null ) {
$this->encryption = new \Automattic\JetpackCRM\Encryption();
}
return $this->encryption;
}
/**
* Loads Package Installer library
*/
public function load_package_installer() {
if ( ! isset( $this->package_installer ) || $this->package_installer == null ) {
// Package installer
require_once ZEROBSCRM_INCLUDE_PATH . 'class-package-installer.php';
$this->package_installer = new \Automattic\JetpackCRM\Package_Installer();
}
return $this->package_installer;
}
/**
* Package Installer pass through to simplify package dependency
*/
public function ensure_package_installed( $package_key, $min_version = 0 ) {
$this->load_package_installer();
return $this->package_installer->ensure_package_is_installed( $package_key, $min_version );
}
// ============ / Resource Loading ============
// ============= PDF engine ============
/**
* Initialise Dompdf instance
*/
public function pdf_engine() {
// PDF Install check:
zeroBSCRM_extension_checkinstall_pdfinv();
// if we don't set options initially, weird issues happen (e.g. `installed-fonts.json` is overwritten at times):
// https://github.com/dompdf/dompdf/issues/2990
$options = new Dompdf\Options();
// this batch of option setting ensures we allow remote images (http/s)
// ... but they're only allowed from same-site urls
$options->set( 'isRemoteEnabled', true );
// We have to specify a temporary dir to download the remote images. Not all systems have a writable /tmp dir.
$jpcrm_storage_path = wf_jpcrm_storage_dir_path();
if ( $jpcrm_storage_path ) {
$options->setTempDir( $jpcrm_storage_path . '/tmp' );
}
// Commented: Not necessary. Using CDN sites (Jetpack Boost) for assets will fail because of the validation.
// $options->addAllowedProtocol( 'http://', 'jpcrm_dompdf_assist_validate_remote_uri' );
// $options->addAllowedProtocol( 'https://', 'jpcrm_dompdf_assist_validate_remote_uri' );
// use JPCRM storage dir for extra fonts
$options->set( 'fontDir', jpcrm_storage_fonts_dir_path() );
// build PDF
$dompdf = new Dompdf\Dompdf( $options );
// set some generic defaults, (can be overriden later)
$dompdf->set_paper( 'A4', 'portrait' );
$dompdf->setHttpContext(
stream_context_create(
array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
),
)
)
);
return $dompdf;
}
// ============ / PDF engine ============
// =========== Templating Class ===============
/**
* Loads templating placeholder class into this->templating_placeholders
* and returns it
* (Can be loaded on-demand)
*/
public function get_templating() {
// load if not loaded
if ( $this->templating_placeholders === false ) {
$this->templating_placeholders = new jpcrm_templating_placeholders();
}
return $this->templating_placeholders;
}
/**
* Loads fonts class into this->fonts
* and returns it
* (Can be loaded on-demand)
*/
public function get_fonts() {
// load if not loaded
require_once ZEROBSCRM_INCLUDE_PATH . 'jpcrm-fonts.php';
// load if not loaded
if ( ! $this->fonts ) {
$this->fonts = new JPCRM_Fonts();
}
return $this->fonts;
}
// ============ / Templating Class ============
// =========== Error Coding ===================
public function getErrorCode( $errorCodeKey = -1 ) {
if ( $errorCodeKey ) {
// load err codes if not loaded
if ( ! isset( $this->errorCodes ) ) {
$this->errorCodes = zeroBSCRM_errorCodes();
}
// if set, return
if ( isset( $this->errorCodes[ $errorCodeKey ] ) ) {
return $this->errorCodes[ $errorCodeKey ];
}
}
return false;
}
// =========== / Error Coding ===================
private function get_page_messages_transient_key( $obj_type, $inserted_id ) {
return sprintf( 'pageMessages_%d_%d_%d', $this->DAL->objTypeID( $obj_type ), get_current_user_id(), $inserted_id );
}
private function maybe_retrieve_page_messages() {
if ( zeroBS_hasGETParamsWithValues(
array( 'admin.php' ),
array(
'page' => 'zbs-add-edit',
'action' => 'edit',
)
)
&& zeroBS_hasGETParams( array( 'admin.php' ), array( 'zbstype', 'zbsid' ) ) ) {
$transient_key = $this->get_page_messages_transient_key( $_GET['zbstype'], $_GET['zbsid'] );
$page_messages = get_transient( $transient_key );
if ( ! empty( $page_messages ) ) {
$this->pageMessages = $page_messages;
delete_transient( $transient_key );
}
}
}
public function new_record_edit_redirect( $obj_type, $inserted_id ) {
if ( ! empty( $this->pageMessages ) ) {
$transient_key = $this->get_page_messages_transient_key( $obj_type, $inserted_id );
set_transient( $transient_key, $this->pageMessages, MINUTE_IN_SECONDS );
}
wp_redirect( jpcrm_esc_link( 'edit', $inserted_id, $obj_type ) );
exit( 0 );
}
public function catch_preheader_interrupts() {
// This intercepts the request, looking for $_GET['page'] == $zbs->slugs['module-activate-redirect'].
// If it sucessfully finds it, activates the module in $_GET['jpcrm-module-name'] and redirects to its 'hub' slug.
if ( isset( $_GET['page'] ) && $_GET['page'] == $this->slugs['module-activate-redirect'] ) {
$this->modules->activate_module_and_redirect();
}
}
}