Newer
Older
// Pass to method in admin class.
return $this->admin->initialize();
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
/**
* Perform necessary stuff prior to CiviCRM being loaded on the front end.
* This needs to be a method because it can then be hooked into WordPress at
* the right time.
*/
public function front_end_page_load() {
static $frontend_loaded = FALSE;
// Add resources for front end.
$this->add_core_resources(TRUE);
// Merge CiviCRM's HTML header with the WordPress theme's header.
add_action('wp_head', [$this, 'wp_head']);
* This is needed because $this->front_end_page_load() is only called when
* there is a single CiviCRM entity present on a page or archive and, whilst
* we don't want all the Javascript to load, we do want stylesheets.
*
* @since 4.6
*/
public function front_end_css_load() {
static $frontend_css_loaded = FALSE;
return;
}
if (!$this->initialize()) {
return;
}
$config = CRM_Core_Config::singleton();
if (!CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'disable_core_css')) {
wp_enqueue_style(
'civicrm_css',
$config->resourceBase . 'css/civicrm.css',
// Dependencies.
NULL,
// Version.
CIVICRM_PLUGIN_VERSION,
// Media.
'all'
// Custom CSS is dependent.
$dependent = ['civicrm_css'];
if (!empty($config->customCSSURL)) {
wp_enqueue_style(
'civicrm_custom_css',
$config->customCSSURL,
// Dependencies.
$dependent,
// Version.
CIVICRM_PLUGIN_VERSION,
// Media.
'all'
* Add CiviCRM core resources.
*
* @since 4.6
* @param bool $front_end True if on WordPress front end, false otherwise.
public function add_core_resources($front_end = TRUE) {
if (!$this->initialize()) {
return;
}
$config = CRM_Core_Config::singleton();
$config->userFrameworkFrontend = $front_end;
CRM_Core_Resources::singleton()->addCoreResources();
}
/**
* Merge CiviCRM's HTML header with the WordPress theme's header.
* Callback from WordPress 'admin_head' and 'wp_head' hooks.
*
* @since 4.4
/*
* CRM-11823
* If CiviCRM bootstrapped, then merge its HTML header with the CMS's header.
*/
return;
}
$region = CRM_Core_Region::instance('html-header', FALSE);
}
}
// ---------------------------------------------------------------------------
// CiviCRM Invocation (this outputs CiviCRM's markup)
// ---------------------------------------------------------------------------
/**
* Invoke CiviCRM in a WordPress context.
*
* Callback function from add_menu_page()
* Callback from WordPress 'init' and 'the_content' hooks
* Also called by shortcode_render() and _civicrm_update_user()
*
*/
public function invoke() {
static $alreadyInvoked = FALSE;
// Bail if this is called via a content-preprocessing plugin.
if ($this->is_page_request() && !in_the_loop() && !is_admin()) {
return;
}
if (!$this->initialize()) {
return;
}
* WordPress has it's own timezone calculations. CiviCRM relies on the PHP
* default timezone which WordPress overrides with UTC in wp-settings.php
$original_timezone = date_default_timezone_get();
$wp_site_timezone = $this->get_timezone_string();
if ($wp_site_timezone) {
// phpcs:ignore WordPress.DateTime.RestrictedFunctions.timezone_change_date_default_timezone_set
CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
}
* At this point we are in a CiviCRM context. WordPress always quotes the
* request, so CiviCRM needs to reverse what it just did.
if ($this->civicrm_in_wordpress()) {
$_REQUEST['noheader'] = $_GET['noheader'] = TRUE;
}
// Code inside invoke() requires the current user to be set up.
* Bypass synchronize if running upgrade to avoid any serious non-recoverable
* error which might hinder the upgrade process.
*/
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if (CRM_Utils_Array::value('q', $_GET) !== 'civicrm/upgrade') {
// Set dashboard as default if args are empty.
if (empty($argdata['argString'])) {
$_GET['q'] = 'civicrm/dashboard';
$_GET['reset'] = 1;
// Restore original timezone.
if ($original_timezone) {
// phpcs:ignore WordPress.DateTime.RestrictedFunctions.timezone_change_date_default_timezone_set
date_default_timezone_set($original_timezone);
/**
* Broadcast that CiviCRM has been invoked.
*
* @since 4.4
*/
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
/**
* Returns the timezone string for the current WordPress site.
*
* If a timezone identifier is used, return that.
* If an offset is used, try to build a suitable timezone.
* If all else fails, uses UTC.
*
* @since 5.64
*
* @return string $tzstring The site timezone string.
*/
private function get_timezone_string() {
// Return the timezone string when set.
$tzstring = get_option('timezone_string');
if (!empty($tzstring)) {
return $tzstring;
}
/*
* Try and build a deprecated (but currently valid) timezone string
* from the GMT offset value.
*
* Note: manual offsets should be discouraged. WordPress works more
* reliably when setting an actual timezone (e.g. "Europe/London")
* because of support for Daylight Saving changes.
*
* Note: the IANA timezone database that provides PHP's timezone
* support uses (reversed) POSIX style signs.
*
* @see https://www.php.net/manual/en/timezones.others.php
*/
$offset = get_option('gmt_offset');
// phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
if (0 != $offset && floor($offset) == $offset) {
$offset_int = (int) $offset;
$offset_string = $offset > 0 ? "-$offset" : '+' . abs($offset_int);
$tzstring = 'Etc/GMT' . $offset_string;
}
// Default to "UTC" if the timezone string is still empty.
if (empty($tzstring)) {
$tzstring = 'UTC';
}
return $tzstring;
}
* Non-destructively override WordPress magic quotes.
*
* Only called by invoke() to undo WordPress default behaviour.
* @since 5.7 Rewritten to work with query vars.
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// phpcs:disable WordPress.Security.NonceVerification.Missing
$this->wp_get = $_GET;
$this->wp_post = $_POST;
$this->wp_cookie = $_COOKIE;
$this->wp_request = $_REQUEST;
// Reassign globals.
$_GET = stripslashes_deep($_GET);
$_POST = stripslashes_deep($_POST);
$_COOKIE = stripslashes_deep($_COOKIE);
$_REQUEST = stripslashes_deep($_REQUEST);
// phpcs:enable WordPress.Security.NonceVerification.Recommended
// phpcs:enable WordPress.Security.NonceVerification.Missing
$page = get_query_var('civiwp');
$reset = get_query_var('reset');
$id = get_query_var('id');
$html = get_query_var('html');
$snippet = get_query_var('snippet');
$action = get_query_var('action');
$mode = get_query_var('mode');
$cid = get_query_var('cid');
$gid = get_query_var('gid');
$sid = get_query_var('sid');
$cs = get_query_var('cs');
$force = get_query_var('force');
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
if (!empty($reset)) {
$_REQUEST['reset'] = $_GET['reset'] = $reset;
}
if (!empty($id)) {
$_REQUEST['id'] = $_GET['id'] = $id;
}
if (!empty($html)) {
$_REQUEST['html'] = $_GET['html'] = $html;
}
if (!empty($snippet)) {
$_REQUEST['snippet'] = $_GET['snippet'] = $snippet;
}
if (!empty($action)) {
$_REQUEST['action'] = $_GET['action'] = $action;
}
if (!empty($mode)) {
$_REQUEST['mode'] = $_GET['mode'] = $mode;
}
if (!empty($cid)) {
$_REQUEST['cid'] = $_GET['cid'] = $cid;
}
if (!empty($gid)) {
$_REQUEST['gid'] = $_GET['gid'] = $gid;
}
if (!empty($sid)) {
$_REQUEST['sid'] = $_GET['sid'] = $sid;
}
if (!empty($cs)) {
$_REQUEST['cs'] = $_GET['cs'] = $cs;
}
if (!empty($force)) {
$_REQUEST['force'] = $_GET['force'] = $force;
}
/**
* Broadcast that CiviCRM query vars have been assigned.
*
* Use in combination with `civicrm_query_vars` filter to ensure that any
* other query vars are included in the assignment to the super-global
* arrays.
*
* @since 5.7
*/
* Only called by invoke() to redo WordPress default behaviour.
*
* @since 4.4
$_GET = $this->wp_get;
$_POST = $this->wp_post;
$_COOKIE = $this->wp_cookie;
$_REQUEST = $this->wp_request;
unset($this->wp_get, $this->wp_post, $this->wp_cookie, $this->wp_request);
* Detect Ajax, snippet, or file requests.
*
* @since 4.4
* @return boolean $is_page True if request is for a CiviCRM page, false otherwise.
// Try and populate "html" query var for testing snippet requests.
// We do not use $html apart to test for empty.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$html = isset($_GET['html']) ? wp_unslash($_GET['html']) : '';
/*
* FIXME: It's not sustainable to hardcode a whitelist of all of non-HTML
* pages. Maybe the menu-XML should include some metadata to make this
* unnecessary?
*/
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
// Is this an AJAX request?
$is_ajax = (CRM_Utils_Array::value('HTTP_X_REQUESTED_WITH', $_SERVER) === 'XMLHttpRequest') ? TRUE : FALSE;
// Is this a non-page CiviCRM path?
$paths = ['ajax', 'file', 'asset'];
$is_civicrm_path = ($argdata['args'][0] === 'civicrm' && in_array($argdata['args'][1], $paths)) ? TRUE : FALSE;
// Is this a CiviCRM "snippet" request?
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$is_snippet = !empty($_REQUEST['snippet']) ? TRUE : FALSE;
// Is this a CiviCRM iCal file request?
$is_ical = (strpos($argdata['argString'], 'civicrm/event/ical') === 0 && empty($html)) ? TRUE : FALSE;
// Is this a CiviCRM image file request?
$is_image = (strpos($argdata['argString'], 'civicrm/contact/imagefile') === 0) ? TRUE : FALSE;
// Any one of the above conditions being true means this is a "non-page" request.
$non_page = ($is_ajax || $is_civicrm_path || $is_snippet || $is_ical || $is_image) ? TRUE : FALSE;
/**
* Filter the result of the "non-page" checks.
*
* This filter can be used to force CiviCRM into considering a given request to be
* a "non-page" request (return TRUE) or a "page" request (return FALSE).
*
* @since 5.74
*
* @param bool $non_page Boolean TRUE for requests that CiviCRM should not render as a "page".
* @param array $argdata The arguments and request string from query vars.
*/
$non_page = apply_filters('civicrm_is_non_page_request', $non_page, $argdata);
if ($non_page) {
$is_page = FALSE;
* Get arguments and request string from query vars.
* @return array{args: array, argString: string}
// Get path from query vars.
$q = get_query_var('q');
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$q = isset($_GET['q']) ? sanitize_text_field(wp_unslash($_GET['q'])) : '';
// phpcs:enable WordPress.Security.NonceVerification.Recommended
/*
* Fix 'civicrm/civicrm' elements derived from CRM:url()
* @see https://lab.civicrm.org/dev/rc/issues/5#note_16205
*/
if (defined('CIVICRM_CLEANURL') && CIVICRM_CLEANURL) {
if (substr($q, 0, 16) === 'civicrm/civicrm/') {
$q = str_replace('civicrm/civicrm/', 'civicrm/', $q);
$_REQUEST['q'] = $_GET['q'] = $q;
}
}
if (!empty($q)) {
$argString = trim($q);
// Remove / from the beginning and ending of query string.
$args = explode('/', $argString);
}
$args = array_pad($args, 2, '');
* Clone of CRM_Utils_System_WordPress::getBaseUrl() whose access was set to
* private. Now that it is public, we can access that method instead.
* @param bool $absolute Passing TRUE prepends the scheme and domain, FALSE doesn't.
* @param bool $frontend Passing FALSE returns the admin URL.
* @param bool $forceBackend Passing TRUE overrides $frontend and returns the admin URL.
* @return mixed|null|string
*/
public function get_base_url($absolute, $frontend, $forceBackend) {
_deprecated_function(__METHOD__, '5.69', 'CRM_Utils_System::getBaseUrl');
return Civi::paths()->getUrl('[wp.backend]/.', $absolute ? 'absolute' : 'relative');
else {
return Civi::paths()->getUrl('[wp.frontend]/.', $absolute ? 'absolute' : 'relative');
* -----------------------------------------------------------------------------
* Procedures start here
* -----------------------------------------------------------------------------
*/
/**
* The main function responsible for returning the CiviCRM_For_WordPress instance
* to functions everywhere.
*
* Use this function like you would a global variable, except without needing to
* declare the global.
* @since 4.4
*
* @return CiviCRM_For_WordPress The plugin instance.
*/
function civi_wp() {
return CiviCRM_For_WordPress::singleton();
}
/*
* Instantiate CiviCRM_For_WordPress immediately.
*
* @see CiviCRM_For_WordPress::setup_instance()
* Tell WordPress to call plugin activation method - no longer calls legacy
register_activation_hook(CIVICRM_PLUGIN_FILE, [civi_wp(), 'activate']);
* Tell WordPress to call plugin deactivation method - needed in order to reset
* the option that is set on activation.
*/
register_deactivation_hook(CIVICRM_PLUGIN_FILE, [civi_wp(), 'deactivate']);
* @see https://developer.wordpress.org/reference/functions/register_uninstall_hook/