Merge pull request #2712 from pratik-joshi/CRM-14363
[civicrm-core.git] / CRM / Utils / System / WordPress.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35
36 /**
37 * WordPress specific stuff goes here
38 */
39 class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
40 function __construct() {
41 $this->is_drupal = FALSE;
42 }
43
44 /**
45 * sets the title of the page
46 *
47 * @param string $title
48 * @paqram string $pageTitle
49 *
50 * @return void
51 * @access public
52 */
53 function setTitle($title, $pageTitle = NULL) {
54 if (!$pageTitle) {
55 $pageTitle = $title;
56 }
57 if (civicrm_wp_in_civicrm()) {
58 global $civicrm_wp_title;
59 $civicrm_wp_title = $pageTitle;
60 $template = CRM_Core_Smarty::singleton();
61 $template->assign('pageTitle', $pageTitle);
62 }
63 }
64
65 /**
66 * Append an additional breadcrumb tag to the existing breadcrumb
67 *
68 * @param string $title
69 * @param string $url
70 *
71 * @return void
72 * @access public
73 * @static
74 */
75 function appendBreadCrumb($breadCrumbs) {
76 $breadCrumb = wp_get_breadcrumb();
77
78 if (is_array($breadCrumbs)) {
79 foreach ($breadCrumbs as $crumbs) {
80 if (stripos($crumbs['url'], 'id%%')) {
81 $args = array('cid', 'mid');
82 foreach ($args as $a) {
83 $val = CRM_Utils_Request::retrieve($a, 'Positive', CRM_Core_DAO::$_nullObject,
84 FALSE, NULL, $_GET
85 );
86 if ($val) {
87 $crumbs['url'] = str_ireplace("%%{$a}%%", $val, $crumbs['url']);
88 }
89 }
90 }
91 $breadCrumb[] = "<a href=\"{$crumbs['url']}\">{$crumbs['title']}</a>";
92 }
93 }
94
95 $template = CRM_Core_Smarty::singleton();
96 $template->assign_by_ref('breadcrumb', $breadCrumb);
97 wp_set_breadcrumb($breadCrumb);
98 }
99
100 /**
101 * Reset an additional breadcrumb tag to the existing breadcrumb
102 *
103 * @return void
104 * @access public
105 * @static
106 */
107 function resetBreadCrumb() {
108 $bc = array();
109 wp_set_breadcrumb($bc);
110 }
111
112 /**
113 * Append a string to the head of the html file
114 *
115 * @param string $head the new string to be appended
116 *
117 * @return void
118 * @access public
119 * @static
120 */
121 function addHTMLHead($head) {
122 static $registered = FALSE;
123 if (!$registered) {
124 // front-end view
125 add_action('wp_head', array(__CLASS__, '_showHTMLHead'));
126 // back-end views
127 add_action('admin_head', array(__CLASS__, '_showHTMLHead'));
128 }
129 CRM_Core_Region::instance('wp_head')->add(array(
130 'markup' => $head,
131 ));
132 }
133
134 static function _showHTMLHead() {
135 $region = CRM_Core_Region::instance('wp_head', FALSE);
136 if ($region) {
137 echo $region->render('');
138 }
139 }
140
141 /**
142 * Add a script file
143 *
144 * @param $url: string, absolute path to file
145 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
146 *
147 * Note: This function is not to be called directly
148 * @see CRM_Core_Region::render()
149 *
150 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
151 * @access public
152 */
153 public function addScriptUrl($url, $region) {
154 return FALSE;
155 }
156
157 /**
158 * Add an inline script
159 *
160 * @param $code: string, javascript code
161 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
162 *
163 * Note: This function is not to be called directly
164 * @see CRM_Core_Region::render()
165 *
166 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
167 * @access public
168 */
169 public function addScript($code, $region) {
170 return FALSE;
171 }
172
173 /**
174 * Add a css file
175 *
176 * @param $url: string, absolute path to file
177 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
178 *
179 * Note: This function is not to be called directly
180 * @see CRM_Core_Region::render()
181 *
182 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
183 * @access public
184 */
185 public function addStyleUrl($url, $region) {
186 return FALSE;
187 }
188
189 /**
190 * Add an inline style
191 *
192 * @param $code: string, css code
193 * @param $region string, location within the document: 'html-header', 'page-header', 'page-footer'
194 *
195 * Note: This function is not to be called directly
196 * @see CRM_Core_Region::render()
197 *
198 * @return bool TRUE if we support this operation in this CMS, FALSE otherwise
199 * @access public
200 */
201 public function addStyle($code, $region) {
202 return FALSE;
203 }
204
205 /**
206 * rewrite various system urls to https
207 *
208 * @param null
209 *
210 * @return void
211 * @access public
212 * @static
213 */
214 function mapConfigToSSL() {
215 global $base_url;
216 $base_url = str_replace('http://', 'https://', $base_url);
217 }
218
219 /**
220 * figure out the post url for the form
221 *
222 * @param mix $action the default action if one is pre-specified
223 *
224 * @return string the url to post the form
225 * @access public
226 * @static
227 */
228 function postURL($action) {
229 if (!empty($action)) {
230 return $action;
231 }
232
233 return $this->url($_GET['q'], NULL, TRUE, NULL, FALSE);
234 }
235
236 /**
237 * Generate an internal CiviCRM URL (copied from DRUPAL/includes/common.inc#url)
238 *
239 * @param $path string The path being linked to, such as "civicrm/add"
240 * @param $query string A query string to append to the link.
241 * @param $absolute boolean Whether to force the output to be an absolute link (beginning with http:).
242 * Useful for links that will be displayed outside the site, such as in an
243 * RSS feed.
244 * @param $fragment string A fragment identifier (named anchor) to append to the link.
245 * @param $htmlize boolean whether to convert to html eqivalant
246 * @param $frontend boolean a gross joomla hack
247 *
248 * @return string an HTML string containing a link to the given path.
249 * @access public
250 *
251 */
252 function url(
253 $path = NULL,
254 $query = NULL,
255 $absolute = FALSE,
256 $fragment = NULL,
257 $htmlize = TRUE,
258 $frontend = FALSE,
259 $forceBackend = FALSE
260 ) {
261 $config = CRM_Core_Config::singleton();
262 $script = '';
263 $separator = $htmlize ? '&amp;' : '&';
264 $pageID = '';
265
266 $path = CRM_Utils_String::stripPathChars($path);
267
268 //this means wp function we are trying to use is not available,
269 //so load bootStrap
270 if (!function_exists('get_option')) {
271 $this->loadBootStrap();
272 }
273 $permlinkStructure = get_option('permalink_structure');
274 if ($config->userFrameworkFrontend) {
275 if ($permlinkStructure != '') {
276 global $post;
277 $script = get_permalink($post->ID);
278 }
279
280 // when shortcode is included in page
281 // also make sure we have valid query object
282 global $wp_query;
283 if ( method_exists( $wp_query, 'get' ) ) {
284 if (get_query_var('page_id')) {
285 $pageID = "{$separator}page_id=" . get_query_var('page_id');
286 }
287 elseif (get_query_var('p')) {
288 // when shortcode is inserted in post
289 $pageID = "{$separator}p=" . get_query_var('p');
290 }
291 }
292 }
293
294 if (isset($fragment)) {
295 $fragment = '#' . $fragment;
296 }
297
298 if (!isset($config->useFrameworkRelativeBase)) {
299 $base = parse_url($config->userFrameworkBaseURL);
300 $config->useFrameworkRelativeBase = $base['path'];
301 }
302
303 $base = $absolute ? $config->userFrameworkBaseURL : $config->useFrameworkRelativeBase;
304
305 if ((is_admin() && !$frontend) || $forceBackend) {
306 $base .= 'wp-admin/admin.php';
307 }
308 elseif (defined('CIVICRM_UF_WP_BASEPAGE')) {
309 $base .= CIVICRM_UF_WP_BASEPAGE;
310 }
311 elseif (isset($config->wpBasePage)) {
312 $base .= $config->wpBasePage;
313 }
314
315 if (isset($path)) {
316 if (isset($query)) {
317 if ($permlinkStructure != '' && ($pageID || $script != '')) {
318 return $script . '?page=CiviCRM'. $separator . 'q=' . $path . $pageID . $separator . $query . $fragment;
319 }
320 else {
321 return $base . '?page=CiviCRM' . $separator . 'q=' . $path . $pageID . $separator . $query . $fragment;
322 }
323 }
324 else {
325 if ($permlinkStructure != '' && ($pageID || $script != '')) {
326 return $script . '?page=CiviCRM' . $separator . 'q=' . $path . $pageID . $fragment;
327 }
328 else {
329 return $base . '?page=CiviCRM' . $separator . 'q=' . $path . $pageID . $fragment;
330 }
331 }
332 }
333 else {
334 if (isset($query)) {
335 if ($permlinkStructure != '' && ($pageID || $script != '')) {
336 return $script . '?' . $query . $pageID . $fragment;
337 }
338 else {
339 return $base . $script . '?' . $query . $pageID . $fragment;
340 }
341 }
342 else {
343 return $base . $fragment;
344 }
345 }
346 }
347
348 /**
349 * Authenticate the user against the wordpress db
350 *
351 * @param string $name the user name
352 * @param string $password the password for the above user name
353 *
354 * @return mixed false if no auth
355 * array(
356 contactID, ufID, unique string ) if success
357 * @access public
358 * @static
359 */
360 function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realPath = NULL) {
361 $config = CRM_Core_Config::singleton();
362
363 if ($loadCMSBootstrap) {
364 $config->userSystem->loadBootStrap($name, $password);
365 }
366
367 $user = wp_authenticate($name, $password);
368 if (is_a($user, 'WP_Error')) {
369 return FALSE;
370 }
371
372 // need to change this to make sure we matched only one row
373
374 CRM_Core_BAO_UFMatch::synchronizeUFMatch($user->data, $user->data->ID, $user->data->user_email, 'WordPress');
375 $contactID = CRM_Core_BAO_UFMatch::getContactId($user->data->ID);
376 if (!$contactID) {
377 return FALSE;
378 }
379 return array($contactID, $user->data->ID, mt_rand());
380 }
381
382 /**
383 * Set a message in the UF to display to a user
384 *
385 * @param string $message the message to set
386 *
387 * @access public
388 * @static
389 */
390 function setMessage($message) {
391 }
392
393 function loadUser( $user ) {
394 return true;
395 }
396
397 function permissionDenied() {
398 CRM_Core_Error::fatal(ts('You do not have permission to access this page'));
399 }
400
401 function logout() {
402 // destroy session
403 if (session_id()) {
404 session_destroy();
405 }
406 wp_logout();
407 wp_redirect(wp_login_url());
408 }
409
410 function updateCategories() {}
411
412 /**
413 * Get the locale set in the hosting CMS
414 *
415 * @return string with the locale or null for none
416 */
417 function getUFLocale() {
418 return NULL;
419 }
420
421 /**
422 * load wordpress bootstrap
423 *
424 * @param $name string optional username for login
425 * @param $pass string optional password for login
426 */
427 function loadBootStrap($name = NULL, $pass = NULL) {
428 global $wp, $wp_rewrite, $wp_the_query, $wp_query, $wpdb;
429
430 $cmsRootPath = $this->cmsRootPath();
431 if (!$cmsRootPath) {
432 CRM_Core_Error::fatal("Could not find the install directory for WordPress");
433 }
434
435 require_once ($cmsRootPath . DIRECTORY_SEPARATOR . 'wp-load.php');
436 $wpUserTimezone = get_option('timezone_string');
437 if ($wpUserTimezone) {
438 date_default_timezone_set($wpUserTimezone);
439 CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
440 }
441 return true;
442 }
443
444 function validInstallDir($dir) {
445 $includePath = "$dir/wp-includes";
446 if (
447 @opendir($includePath) &&
448 file_exists("$includePath/version.php")
449 ) {
450 return TRUE;
451 }
452 return FALSE;
453 }
454
455 function cmsRootPath() {
456 $cmsRoot = $valid = NULL;
457 if (defined('CIVICRM_CMSDIR')) {
458 if ($this->validInstallDir(CIVICRM_CMSDIR)) {
459 $cmsRoot = CIVICRM_CMSDIR;
460 $valid = TRUE;
461 }
462 }
463 else {
464 $pathVars = explode('/', str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']));
465
466 //might be windows installation.
467 $firstVar = array_shift($pathVars);
468 if ($firstVar) {
469 $cmsRoot = $firstVar;
470 }
471
472 //start w/ csm dir search.
473 foreach ($pathVars as $var) {
474 $cmsRoot .= "/$var";
475 if ($this->validInstallDir($cmsRoot)) {
476 //stop as we found bootstrap.
477 $valid = TRUE;
478 break;
479 }
480 }
481 }
482
483 return ($valid) ? $cmsRoot : NULL;
484 }
485
486 function createUser(&$params, $mail) {
487 $user_data = array(
488 'ID' => '',
489 'user_pass' => $params['cms_pass'],
490 'user_login' => $params['cms_name'],
491 'user_email' => $params[$mail],
492 'nickname' => $params['cms_name'],
493 'role' => get_option('default_role'),
494 );
495 if (isset($params['contactID'])) {
496 $contactType = CRM_Contact_BAO_Contact::getContactType($params['contactID']);
497 if ($contactType == 'Individual') {
498 $user_data['first_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
499 $params['contactID'], 'first_name'
500 );
501 $user_data['last_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
502 $params['contactID'], 'last_name'
503 );
504 }
505 }
506
507 $uid = wp_insert_user($user_data);
508
509 $creds = array();
510 $creds['user_login'] = $params['cms_name'];
511 $creds['user_password'] = $params['cms_pass'];
512 $creds['remember'] = TRUE;
513 $user = wp_signon($creds, FALSE);
514
515 wp_new_user_notification($uid, $user_data['user_pass']);
516 return $uid;
517 }
518
519 /*
520 * Change user name in host CMS
521 *
522 * @param integer $ufID User ID in CMS
523 * @param string $ufName User name
524 */
525 function updateCMSName($ufID, $ufName) {
526 // CRM-10620
527 if (function_exists('wp_update_user')) {
528 $ufID = CRM_Utils_Type::escape($ufID, 'Integer');
529 $ufName = CRM_Utils_Type::escape($ufName, 'String');
530
531 $values = array ('ID' => $ufID, 'user_email' => $ufName);
532 if( $ufID ) {
533 wp_update_user( $values ) ;
534 }
535 }
536 }
537
538 function checkUserNameEmailExists(&$params, &$errors, $emailName = 'email') {
539 $config = CRM_Core_Config::singleton();
540
541 $dao = new CRM_Core_DAO();
542 $name = $dao->escape(CRM_Utils_Array::value('name', $params));
543 $email = $dao->escape(CRM_Utils_Array::value('mail', $params));
544
545 if (!empty($params['name'])) {
546 if (!validate_username($params['name'])) {
547 $errors['cms_name'] = ts("Your username contains invalid characters");
548 }
549 elseif (username_exists(sanitize_user($params['name']))) {
550 $errors['cms_name'] = ts('The username %1 is already taken. Please select another username.', array(1 => $params['name']));
551 }
552 }
553
554 if (!empty($params['mail'])) {
555 if (!is_email($params['mail'])) {
556 $errors[$emailName] = "Your email is invaid";
557 }
558 elseif (email_exists($params['mail'])) {
559 $resetUrl = $config->userFrameworkBaseURL . 'wp-login.php?action=lostpassword';
560 $errors[$emailName] = ts('The email address %1 is already registered. <a href="%2">Have you forgotten your password?</a>',
561 array(1 => $params['mail'], 2 => $resetUrl)
562 );
563 }
564 }
565 }
566
567 /**
568 * check is user logged in.
569 *
570 * @return boolean true/false.
571 */
572 public function isUserLoggedIn() {
573 $isloggedIn = FALSE;
574 if (function_exists('is_user_logged_in')) {
575 $isloggedIn = is_user_logged_in();
576 }
577
578 return $isloggedIn;
579 }
580
581 function getLoggedInUserObject() {
582 if (function_exists('is_user_logged_in') &&
583 is_user_logged_in()) {
584 global $current_user;
585 }
586 return $current_user;
587 }
588 /**
589 * Get currently logged in user uf id.
590 *
591 * @return int $userID logged in user uf id.
592 */
593 public function getLoggedInUfID() {
594 $ufID = NULL;
595 $current_user = $this->getLoggedInUserObject();
596 return isset($current_user->ID) ? $current_user->ID : NULL;
597 }
598
599 /**
600 * Get currently logged in user unique identifier - this tends to be the email address or user name.
601 *
602 * @return string $userID logged in user unique identifier
603 */
604 function getLoggedInUniqueIdentifier() {
605 $user = $this->getLoggedInUserObject();
606 return $this->getUniqueIdentifierFromUserObject($user);
607 }
608
609 /**
610 * Get User ID from UserFramework system (Joomla)
611 * @param object $user object as described by the CMS
612 * @return mixed <NULL, number>
613 */
614 function getUserIDFromUserObject($user) {
615 return !empty($user->ID) ? $user->ID : NULL;
616 }
617
618 /**
619 * Get Unique Identifier from UserFramework system (CMS)
620 * @param object $user object as described by the User Framework
621 * @return mixed $uniqueIdentifer Unique identifier from the user Framework system
622 *
623 */
624 function getUniqueIdentifierFromUserObject($user) {
625 return empty($user->user_email) ? NULL : $user->user_email;
626 }
627
628 /**
629 * Get user login URL for hosting CMS (method declared in each CMS system class)
630 *
631 * @param string $destination - if present, add destination to querystring (works for Drupal only)
632 *
633 * @return string - loginURL for the current CMS
634 *
635 */
636 public function getLoginURL($destination = '') {
637 $config = CRM_Core_Config::singleton();
638 $loginURL = $config->userFrameworkBaseURL;
639 $loginURL .= 'wp-login.php';
640 return $loginURL;
641 }
642
643 public function getLoginDestination(&$form) {
644 return;
645 }
646
647 /**
648 * Return the current WordPress version if relevant function exists
649 *
650 * @return string - version number
651 *
652 */
653 function getVersion() {
654 if (function_exists('get_bloginfo')) {
655 return get_bloginfo('version', 'display');
656 }
657 else {
658 return 'Unknown';
659 }
660 }
661
662 /**
663 * get timezone as a string
664 * @return string Timezone e.g. 'America/Los_Angeles'
665 */
666 function getTimeZoneString() {
667 return get_option('timezone_string');
668 }
669 }
670