diff --git a/civicrm.php b/civicrm.php index 081d36d..1d19f77 100644 --- a/civicrm.php +++ b/civicrm.php @@ -297,29 +297,22 @@ public function setup_instance() { wp_die( __( 'Only one instance of CiviCRM_For_WordPress please', 'civicrm' ) ); } - // Store context - $this->civicrm_in_wordpress_set(); - // there is no session handling in WP hence we start it for CiviCRM pages if (!session_id()) { session_start(); } - if ( $this->civicrm_in_wordpress() ) { - // this is required for AJAX calls in WordPress admin - $_GET['noheader'] = TRUE; - } else { - $_GET['civicrm_install_type'] = 'wordpress'; - } - // get classes and instantiate $this->include_files(); // do plugin activation $this->activation(); - // register all hooks - $this->register_hooks(); + // use translation files + $this->enable_translation(); + + // register all hooks on init + add_action( 'init', array( $this, 'register_hooks' ) ); // notify plugins do_action( 'civicrm_instance_loaded' ); @@ -341,8 +334,11 @@ public function setup_instance() { */ public function civicrm_in_wordpress_set() { + // get identifying query var + $page = get_query_var( 'page' ); + // store - self::$in_wordpress = ( isset( $_GET['page'] ) && $_GET['page'] == 'CiviCRM' ) ? TRUE : FALSE; + self::$in_wordpress = ( $page == 'CiviCRM' ) ? TRUE : FALSE; } @@ -443,7 +439,7 @@ public function include_files() { /** - * Register hooks + * Register hooks on init. * * @return void */ @@ -467,6 +463,29 @@ public function register_hooks() { // go no further if Civi not installed yet if ( ! CIVICRM_INSTALLED ) return; + // delay everything else until query has been parsed + add_action( 'parse_query', array( $this, 'register_hooks_other' ) ); + + } + + + /** + * Register hooks for the front end. + * + * @return void + */ + public function register_hooks_other() { + + // prevent multiple calls + static $alreadyRegistered = FALSE; + if ( $alreadyRegistered ) { + return; + } + $alreadyRegistered = TRUE; + + // Store context + $this->civicrm_in_wordpress_set(); + // when embedded via wpBasePage or AJAX call... if ( $this->civicrm_in_wordpress() ) { @@ -517,12 +536,115 @@ public function register_hooks() { */ public function register_hooks_common() { - // use translation files - add_action( 'plugins_loaded', array( $this, 'enable_translation' ) ); - // register user hooks $this->users->register_hooks(); + // have we flushed rewrite rules? + if ( get_option( 'civicrm_rules_flushed' ) !== 'true' ) { + + // apply custom rewrite rules, then flush rules afterwards + $this->rewrite_rules( true ); + + // set a one-time-only option to flag that this has been done + add_option( 'civicrm_rules_flushed', 'true' ); + + } else { + + // apply custom rewrite rules normally + $this->rewrite_rules(); + + } + + // add our query vars + add_filter( 'query_vars', array( $this, 'query_vars' ) ); + + + } + + + /** + * Add our rewrite rules. + * + * @since 4.7.30 + * + * @param bool $flush_rewrite_rules True if rules should be flushed, false otherwise. + */ + public function rewrite_rules( $flush_rewrite_rules = false ) { + + // kick out if admin + if (is_admin()) { + return; + } + + // kick out if not CiviCRM + if (!$this->initialize()) { + return; + } + + // get config + $config = CRM_Core_Config::singleton(); + + // get basepage object + $basepage = get_page_by_path( $config->wpBasePage ); + + // let's add rewrite rule when viewing the basepage + add_rewrite_rule( + '^' . $config->wpBasePage . '/([^/]*)/([^/]*)/?', + 'index.php?page_id=' . $basepage->ID . '&page=CiviCRM&q=civicrm/$matches[1]/$matches[2]', + 'top' + ); + + // maybe force flush + if ( $flush_rewrite_rules ) { + flush_rewrite_rules(); + } + //flush_rewrite_rules(); + + /** + * Broadcast the rewrite rules event. + * + * @since 4.7.30 + * + * @param bool $flush_rewrite_rules True if rules flushed, false otherwise. + */ + do_action( 'civicrm_after_rewrite_rules', $flush_rewrite_rules ); + + } + + + /** + * Add our query vars. + * + * @since 4.7.30 + * + * @param array $query_vars The existing query vars. + * @return array $query_vars The modified query vars. + */ + public function query_vars( $query_vars ) { + + // sanity check + if ( ! is_array( $query_vars ) ) { + $query_vars = array(); + } + + // add our URL query vars + $query_vars[] = 'page'; + $query_vars[] = 'q'; + $query_vars[] = 'reset'; + $query_vars[] = 'id'; + $query_vars[] = 'html'; + $query_vars[] = 'snippet'; + + // add our shortcode query vars + $query_vars[] = 'action'; + $query_vars[] = 'mode'; + $query_vars[] = 'cid'; + $query_vars[] = 'gid'; + $query_vars[] = 'sid'; + $query_vars[] = 'cs'; + $query_vars[] = 'force'; + + return $query_vars; } @@ -545,7 +667,8 @@ public function register_hooks_admin() { // if settings file does not exist, show notice with link to installer if ( ! CIVICRM_INSTALLED ) { if ( isset( $_GET['page'] ) && $_GET['page'] == 'civicrm-install' ) { - // register hooks for installer page? + // set install type + $_GET['civicrm_install_type'] = 'wordpress'; } else { // show notice add_action( 'admin_notices', array( $this, 'show_setup_warning' ) ); @@ -954,6 +1077,9 @@ private function create_basepage( $slug ) { */ public function admin_page_load() { + // required for AJAX calls + $_GET['noheader'] = TRUE; + // add resources for back end $this->add_core_resources( FALSE ); @@ -1188,6 +1314,11 @@ public function invoke() { // WP always quotes the request, CiviCRM needs to reverse what it just did $this->remove_wp_magic_quotes(); + // required for AJAX calls + if ($this->civicrm_in_wordpress()) { + $_REQUEST['noheader'] = $_GET['noheader'] = TRUE; + } + // Code inside invoke() requires the current user to be set up $current_user = wp_get_current_user(); @@ -1202,13 +1333,11 @@ public function invoke() { // set flag $alreadyInvoked = TRUE; - // get args - $argdata = $this->get_request_args(); - // set dashboard as default if args are empty - if ( !isset( $_GET['q'] ) ) { - $_GET['q'] = 'civicrm/dashboard'; - $_GET['reset'] = 1; + $argdata = $this->get_request_args(); + if ( empty( $argdata['argString'] ) ) { + $_GET['q'] = 'civicrm/dashboard'; + $_GET['reset'] = 1; $argdata['args'] = array('civicrm', 'dashboard'); } @@ -1245,10 +1374,45 @@ public function remove_wp_magic_quotes() { $this->wp_request = $_REQUEST; // reassign globals - $_GET = stripslashes_deep($_GET); - $_POST = stripslashes_deep($_POST); - $_COOKIE = stripslashes_deep($_COOKIE); - $_REQUEST = stripslashes_deep($_REQUEST); + $_GET = stripslashes_deep( $_GET ); + $_POST = stripslashes_deep( $_POST ); + $_COOKIE = stripslashes_deep( $_COOKIE ); + $_REQUEST = stripslashes_deep( $_REQUEST ); + + // test for query var + $q = get_query_var( 'q' ); + if (!empty($q)) { + + $page = get_query_var( 'page' ); + $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' ); + + $_REQUEST['q'] = $_GET['q'] = $q; + $_REQUEST['page'] = $_GET['page'] = 'CiviCRM'; + 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; } + + } } @@ -1278,33 +1442,44 @@ public function restore_wp_magic_quotes() { */ public function is_page_request() { + // assume false + $return = FALSE; + // kick out if not CiviCRM if (!$this->initialize()) { - return; + return $return; } // get args $argdata = $this->get_request_args(); + // grab query var + $html = get_query_var( 'html' ); + if (empty($html)) { + $html = isset($_GET['html']) ? $_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? if (CRM_Utils_Array::value('HTTP_X_REQUESTED_WITH', $_SERVER) == 'XMLHttpRequest' || ($argdata['args'][0] == 'civicrm' && in_array($argdata['args'][1], array('ajax', 'file')) ) || !empty($_REQUEST['snippet']) - || strpos($argdata['argString'], 'civicrm/event/ical') === 0 && empty($_GET['html']) + || strpos($argdata['argString'], 'civicrm/event/ical') === 0 && empty($html) || strpos($argdata['argString'], 'civicrm/contact/imagefile') === 0 ) { - return FALSE; + $return = FALSE; } else { - return TRUE; + $return = TRUE; } + + return $return; } /** - * Get arguments and request string from $_GET + * Get arguments and request string. * * @return array $argdata Array containing request arguments and request string */ @@ -1312,8 +1487,14 @@ public function get_request_args() { $argString = NULL; $args = array(); - if (isset( $_GET['q'])) { - $argString = trim($_GET['q']); + + $q = get_query_var( 'q' ); + if (empty($q)) { + $q = isset($_GET['q']) ? $_GET['q'] : ''; + } + + if (!empty($q)) { + $argString = trim($q); $args = explode('/', $argString); } $args = array_pad($args, 2, ''); @@ -1402,7 +1583,7 @@ public function clear_edit_post_menu_item() { * Clone of CRM_Utils_System_WordPress::getBaseUrl() whose access is set to * private. Until it is public, we cannot access the URL of the basepage since * CRM_Utils_System_WordPress::url() - * + * * 27-09-2016 * CRM-16421 CRM-17633 WIP Changes to support WP in it's own directory * https://wiki.civicrm.org/confluence/display/CRM/WordPress+installed+in+its+own+directory+issues @@ -1452,18 +1633,12 @@ function civi_wp() { /** - * Hook CiviCRM_For_WordPress early onto the 'plugins_loaded' action. + * Hook CiviCRM_For_WordPress onto the 'plugins_loaded' action. * * This gives all other plugins the chance to load before CiviCRM, to get their * actions, filters, and overrides setup without CiviCRM being in the way. */ -if ( defined( 'CIVICRM_LATE_LOAD' ) ) { - add_action( 'plugins_loaded', 'civi_wp', (int) CIVICRM_LATE_LOAD ); - -// initialize -} else { - civi_wp(); -} +add_action( 'plugins_loaded', 'civi_wp' ); /** diff --git a/includes/civicrm.basepage.php b/includes/civicrm.basepage.php index 4559e38..d91618f 100644 --- a/includes/civicrm.basepage.php +++ b/includes/civicrm.basepage.php @@ -223,15 +223,15 @@ public function wp_page_title( $title, $separator = '»', $separator_locati $separator_code = WPSEO_Options::get_default( 'wpseo_titles', 'separator' ); $separator_array = WPSEO_Option_Titles::get_instance()->get_separator_options(); if ( array_key_exists( $separator_code, $separator_array ) ) { - $separator = $separator_array[$separator_code]; + $separator = $separator_array[$separator_code]; } } // construct title depending on separator location if ( $separator_location == 'right' ) { - $title = $this->basepage_title . " $separator " . get_bloginfo( 'name', 'display' ); + $title = $this->basepage_title . " $separator " . get_bloginfo( 'name', 'display' ); } else { - $title = get_bloginfo( 'name', 'display' ) . " $separator " . $this->basepage_title; + $title = get_bloginfo( 'name', 'display' ) . " $separator " . $this->basepage_title; } // return modified title @@ -294,23 +294,41 @@ public function basepage_render() { * The complete URL to the page as it should be accessed. */ public function basepage_canonical_url( $canonical ) { - // It would be better to specify which params are okay to accept as the - // canonical URLs, but this will work for the time being. - if ( empty( $_GET['page'] ) - || empty( $_GET['q'] ) - || 'CiviCRM' !== $_GET['page'] ) { - return $canonical; + + // access Civi config object + $config = CRM_Core_Config::singleton(); + + // retain old logic when not using clean URLs + if (!$config->cleanURL) { + + // It would be better to specify which params are okay to accept as the + // canonical URLs, but this will work for the time being. + if ( empty( $_GET['page'] ) + || empty( $_GET['q'] ) + || 'CiviCRM' !== $_GET['page'] ) { + return $canonical; + } + $path = $_GET['q']; + unset( $_GET['q'] ); + unset( $_GET['page'] ); + $query = http_build_query( $_GET ); + + } + else { + + $argdata = $this->civi->get_request_args(); + $path = $argdata['argString']; + $query = http_build_query( $_GET ); + } - $path = $_GET['q']; - unset( $_GET['q'] ); - unset( $_GET['page'] ); - $query = http_build_query( $_GET ); // We should, however, build the URL the way that CiviCRM expects it to be // (rather than through some other funny base page). return CRM_Utils_System::url( $path, $query ); + } + /** * Get CiviCRM base page template. * @@ -389,34 +407,34 @@ public function basepage_template( $template ) { */ public function add_body_classes( $classes ) { - $args = $this->civi->get_request_args(); + $args = $this->civi->get_request_args(); - // bail if we don't have any - if ( is_null( $args['argString'] ) ) { - return $classes; - } + // bail if we don't have any + if ( is_null( $args['argString'] ) ) { + return $classes; + } - // check for top level - it can be assumed this always 'civicrm' - if ( isset( $args['args'][0] ) AND ! empty( $args['args'][0] ) ) { - $classes[] = $args['args'][0]; - } + // check for top level - it can be assumed this always 'civicrm' + if ( isset( $args['args'][0] ) AND ! empty( $args['args'][0] ) ) { + $classes[] = $args['args'][0]; + } - // check for second level - the component - if ( isset( $args['args'][1] ) AND ! empty( $args['args'][1] ) ) { - $classes[] = $args['args'][0] . '-' . $args['args'][1]; - } + // check for second level - the component + if ( isset( $args['args'][1] ) AND ! empty( $args['args'][1] ) ) { + $classes[] = $args['args'][0] . '-' . $args['args'][1]; + } - // check for third level - the component's configuration - if ( isset( $args['args'][2] ) AND ! empty( $args['args'][2] ) ) { - $classes[] = $args['args'][0] . '-' . $args['args'][1] . '-' . $args['args'][2]; - } + // check for third level - the component's configuration + if ( isset( $args['args'][2] ) AND ! empty( $args['args'][2] ) ) { + $classes[] = $args['args'][0] . '-' . $args['args'][1] . '-' . $args['args'][2]; + } - // check for fourth level - because well, why not? - if ( isset( $args['args'][3] ) AND ! empty( $args['args'][3] ) ) { - $classes[] = $args['args'][0] . '-' . $args['args'][1] . '-' . $args['args'][2] . '-' . $args['args'][3]; - } + // check for fourth level - because well, why not? + if ( isset( $args['args'][3] ) AND ! empty( $args['args'][3] ) ) { + $classes[] = $args['args'][0] . '-' . $args['args'][1] . '-' . $args['args'][2] . '-' . $args['args'][3]; + } - return $classes; + return $classes; } diff --git a/includes/civicrm.shortcodes.php b/includes/civicrm.shortcodes.php index 1ff858b..6fdca3b 100644 --- a/includes/civicrm.shortcodes.php +++ b/includes/civicrm.shortcodes.php @@ -273,7 +273,8 @@ public function render_single( $atts ) { // invoke() requires environment variables to be set foreach ( $args as $key => $value ) { if ( $value !== NULL ) { - $_REQUEST[$key] = $_GET[$key] = $value; + set_query_var($key, $value); + //$_REQUEST[$key] = $_GET[$key] = $value; } } @@ -351,18 +352,35 @@ private function render_multiple( $post_id = FALSE, $shortcode = FALSE, $multipl // $absolute, $frontend, $forceBackend $base_url = $this->civi->get_base_url(TRUE, FALSE, FALSE); - // construct query parts - $queryParts = array(); - $queryParts[] = 'page=CiviCRM'; - if (isset($args['q'])) { - $queryParts[] = 'q=' . $args['q']; - } - if (isset($query)) { - $queryParts[] = $query; + // when not using clean URLs + if (!$config->cleanURL) { + + // construct query parts + $queryParts = array(); + $queryParts[] = 'page=CiviCRM'; + if (isset($args['q'])) { + $queryParts[] = 'q=' . $args['q']; + } + if (isset($query)) { + $queryParts[] = $query; + } + + // construct link + $link = trailingslashit( $base_url ) . '?' . implode('&', $queryParts); + } + else { - // construct link - $link = trailingslashit( $base_url ) . '?' . implode('&', $queryParts); + // clean URLs + if (isset($args['q'])) { + $base_url = trailingslashit( $base_url ) . str_replace('civicrm/', '', $args['q']) . '/'; + } + if (isset($query)) { + $queryParts[] = $query; + } + $link = $base_url . '?' . implode('&', $queryParts); + + } // add a class for styling purposes $class = ' civicrm-shortcode-multiple'; @@ -608,7 +626,6 @@ public function preprocess_atts( $atts ) { case 'info': $args['q'] = 'civicrm/event/info'; - $_REQUEST['page'] = $_GET['page'] = 'CiviCRM'; break; default: diff --git a/includes/civicrm.users.php b/includes/civicrm.users.php index 6557fa8..611a4ca 100644 --- a/includes/civicrm.users.php +++ b/includes/civicrm.users.php @@ -65,14 +65,14 @@ function __construct() { /** - * Register hooks to handle CiviCRM in a WordPress wpBasePage context + * Register hooks for handling users. * * @return void */ public function register_hooks() { // add CiviCRM access capabilities to WordPress roles - add_action( 'init', array( $this, 'set_access_capabilities' ) ); + $this->set_access_capabilities(); // do not hook into user updates if Civi not installed yet if ( ! CIVICRM_INSTALLED ) return;