Newer
Older
<?php
/**
* Main plugin class.
*
*/
namespace CiviCRM_WP_REST;
use CiviCRM_WP_REST\Civi\Mailing_Hooks;
class Plugin {
add_action('rest_api_init', [$this, 'register_rest_routes']);
add_filter('rest_pre_dispatch', [$this, 'bootstrap_civi'], 10, 3);
add_filter('rest_post_dispatch', [$this, 'maybe_reset_php_timezone'], 10, 3);
/**
* Bootstrap CiviCRM when hitting a the 'civicrm' namespace.
*
* @param WP_REST_Server $server REST server instance.
* @param WP_REST_Request $request The request.
* @return mixed $result
*/
public function bootstrap_civi($result, $server, $request) {
if (FALSE !== strpos($request->get_route(), 'civicrm')) {
// rest calls need a wp user, do login
if (FALSE !== strpos($request->get_route(), 'rest')) {
$logged_in_wp_user = $this->do_user_login($request);
if (is_wp_error($logged_in_wp_user)) {
return $logged_in_wp_user;
}
}
}
return $result;
}
/**
* Setup objects.
*
/**
* Filter to replace the mailing tracking URLs.
*
* @param bool $replace_mailing_tracking_urls
*/
$replace_mailing_tracking_urls = apply_filters('civi_wp_rest/plugin/replace_mailing_tracking_urls', FALSE);
// Keep CIVICRM_WP_REST_REPLACE_MAILING_TRACKING for backwards compatibility.
if (
$replace_mailing_tracking_urls
|| (defined('CIVICRM_WP_REST_REPLACE_MAILING_TRACKING')
&& CIVICRM_WP_REST_REPLACE_MAILING_TRACKING)
) {
$mailing_hooks = (new Mailing_Hooks)->register_hooks();
}
}
/**
* Registers Rest API routes.
*
$rest_controller = new Controller\Rest();
$rest_controller->register_routes();
$url_controller = new Controller\Url();
$url_controller->register_routes();
$open_controller = new Controller\Open();
$open_controller->register_routes();
$authorizeIPN_controller = new Controller\AuthorizeIPN();
$authorizeIPN_controller->register_routes();
$paypalIPN_controller = new Controller\PayPalIPN();
$paypalIPN_controller->register_routes();
$paypalIPN_controller = new Controller\PxIPN();
$paypalIPN_controller->register_routes();
$cxn_controller = new Controller\Cxn();
$cxn_controller->register_routes();
$widget_controller = new Controller\Widget();
$widget_controller->register_routes();
/**
* Opportunity to add more rest routes.
*
*/
do_action('civi_wp_rest/plugin/rest_routes_registered');
}
/**
* Sets the PHP timezone to the timezone of the WordPress site when calling
* the civicrm/v3/rest endpoint.
private function maybe_set_php_timezone($request) {
if ($request->get_route() != '/civicrm/v3/rest') {
return;
}
$timezones = [
'original_timezone' => date_default_timezone_get(),
'site_timezone' => $this->get_timezone_string(),
// Filter timezones - retrieved in `maybe_reset_php_timezone()` below.
add_filter('civi_wp_rest/plugin/timezones', function() use ($timezones) {
return $timezones;
});
date_default_timezone_set($timezones['site_timezone']);
\CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
}
/**
* Resets the PHP timezone to the original timezone after calling the
* civicrm/v3/rest endpoint.
*
* @since 5.25
* @param WP_REST_Server $server REST server instance.
* @param WP_REST_Request $request The request.
public function maybe_reset_php_timezone($result, $server, $request) {
if ($request->get_route() != '/civicrm/v3/rest') {
return $result;
}
/**
* Filters this plugin's timezones.
*
* This is actually just a neat way to retrieve the values assigned to
* the `$timezones` array in `maybe_set_php_timezone()` above.
*
* @since 5.25
*
* @param null Passes `null` because return will be populated.
*/
$timezones = apply_filters('civi_wp_rest/plugin/timezones', NULL);
// Reset original timezone.
date_default_timezone_set($timezones['original_timezone']);
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/**
* Returns the timezone string for the current 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');
if (0 != $offset && floor($offset) == $offset) {
$offset_string = $offset > 0 ? "-$offset" : '+' . absint($offset);
$tzstring = 'Etc/GMT' . $offset_string;
}
// Default to "UTC" if the timezone string is still empty.
if (empty($tzstring)) {
$tzstring = 'UTC';
}
return $tzstring;
}
* Performs the necessary checks and data retrieval to login a WordPress user.
* @since 5.25
*
* @param \WP_REST_Request $request The request.
* @return \WP_User|\WP_Error|void $logged_in_wp_user The logged in WordPress user object, \Wp_Error, or nothing.
*/
public function do_user_login($request) {
/**
* Filter and opportunity to bypass the default user login.
*
* @since 5.25
*
* @param bool $login
*/
$logged_in = apply_filters('civi_wp_rest/plugin/do_user_login', FALSE, $request);
if ($logged_in) {
return;
}
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
if (!(new Controller\Rest)->is_valid_api_key($request)) {
return new \WP_Error(
'civicrm_rest_api_error',
__('Missing or invalid param "api_key".', 'civicrm')
);
}
$contact_id = \CRM_Core_DAO::getFieldValue(
'CRM_Contact_DAO_Contact',
$request->get_param('api_key'),
'id',
'api_key'
);
$wp_user = $this->get_wp_user($contact_id);
if (is_wp_error($wp_user)) {
return $wp_user;
}
return $this->login_wp_user($wp_user, $request);
}
/**
* Get WordPress user data.
*
* @since 5.25
*
* @param int $contact_id The Contact ID.
* @return WP_User|WP_Error $user The WordPress user data or WP_Error object.
*/
public function get_wp_user(int $contact_id) {
try {
// Call API.
$uf_match = civicrm_api3('UFMatch', 'getsingle', [
'contact_id' => $contact_id,
'domain_id' => $this->get_civi_domain_id(),
]);
}
return new \WP_Error(
'civicrm_rest_api_error',
__('A WordPress user must be associated with the contact for the provided API key.', 'civicrm')
);
}
add_filter('civi_wp_rest/plugin/uf_match', function() use ($uf_match) {
return !empty($uf_match) ? $uf_match : NULL;
});
return get_userdata($uf_match['uf_id']);
}
/**
* Logs in the WordPress user, and syncs it with it's CiviCRM Contact.
*
* @since 5.25
* @param \WP_User $wp_user The WordPress user object.
* @param \WP_REST_Request|NULL $request The request object or NULL.
* @return \WP_User|void $wp_user The logged in WordPress user object or nothing.
*/
public function login_wp_user(\WP_User $wp_user, $request = NULL) {
/**
* Filter the user about to be logged in.
*
* @param \WP_User $user The WordPress user object
* @param \WP_REST_Request|NULL $request The request object or NULL
*/
$wp_user = apply_filters('civi_wp_rest/plugin/wp_user_login', $wp_user, $request);
wp_set_current_user($wp_user->ID, $wp_user->user_login);
wp_set_auth_cookie($wp_user->ID);
do_action('wp_login', $wp_user->user_login, $wp_user);
$this->set_civi_user_session($wp_user);
return $wp_user;
* Sets the necessary user session variables for CiviCRM.
*
* @since 5.25
*/
public function set_civi_user_session($wp_user): void {
$uf_match = apply_filters('civi_wp_rest/plugin/uf_match', NULL);
// Call API.
$uf_match = civicrm_api3('UFMatch', 'getsingle', [
'uf_id' => $wp_user->ID,
'domain_id' => $this->get_civi_domain_id(),
]);
}
// Set necessary session variables.
$session = \CRM_Core_Session::singleton();
$session->set('ufID', $wp_user->ID);
$session->set('userID', $uf_match['contact_id']);
* @since 5.25
*
* @return int $domain_id The Domain ID.
// Get CiviCRM domain group ID from constant, if set.
$domain_id = defined('CIVICRM_DOMAIN_ID') ? CIVICRM_DOMAIN_ID : 0;
// If this fails, get it from config.
if ($domain_id === 0) {
$domain_id = \CRM_Core_Config::domainID();
}