Newer
Older
<?php
/*
+--------------------------------------------------------------------+
| This work is published under the GNU AGPLv3 license with some |
| permitted exceptions and without any warranty. For full license |
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* Define CiviCRM_For_WordPress_Shortcodes Class.
*
* @since 4.6
* Plugin object reference.
*
* @since 4.6
* @access public
* @var object $civi The plugin object reference.
/**
* Stored shortcodes.
*
* @since 4.6
* @access public
* @var array $shortcodes The stored shortcodes.
*/
/**
* Rendered shortcode markup.
*
* @since 4.6
* @access public
* @var array $shortcode_markup The array of rendered shortcode markup.
*/
/**
* Count multiple passes of do_shortcode in a post.
*
* @since 4.6
* @access public
* @var array $shortcode_in_post Count multiple passes of do_shortcode in a post.
*/
* Register hooks to handle the presence of shortcodes in content.
add_shortcode( 'civicrm', array( $this, 'render_single' ) );
// Add CiviCRM core resources when a shortcode is detected in the post content
add_action( 'wp', array( $this, 'prerender' ), 10, 1 );
}
/**
* Determine if a CiviCRM shortcode is present in any of the posts about to be displayed.
*
* Callback method for 'wp' hook, always called from WP front-end.
* @since 4.6
*
* @param object $wp The WP object, present but not used.
* At this point, all conditional tags are available
* @see http://codex.wordpress.org/Conditional_Tags
*/
/*
* Let's loop through the results
* This also has the effect of bypassing the logic in
* https://github.com/civicrm/civicrm-wordpress/pull/36
*/
if ( have_posts() ) {
while ( have_posts() ) : the_post();
global $post;
if ( has_shortcode( $post->post_content, 'civicrm' ) ) {
$shortcodes_array = $this->get_for_post( $post->post_content );
$shortcodes_present += count( $this->shortcodes[$post->ID] );
}
}
endwhile;
}
// We need CiviCRM initialised prior to parsing shortcodes
if (!$this->civi->initialize()) {
return;
}
add_action( 'wp_enqueue_scripts', array( $this->civi, 'front_end_css_load' ), 100 );
foreach( $this->shortcodes AS $post_id => $shortcode_array ) {
// Set flag if there are multple shortcodes in this post
$multiple = ( count( $shortcode_array ) > 1 ) ? 1 : 0;
foreach( $shortcode_array AS $shortcode ) {
$this->shortcode_markup[$post_id][] = $this->render_multiple( $post_id, $shortcode, $multiple );
}
}
} else {
add_action( 'wp', array( $this->civi, 'front_end_page_load' ), 100 );
/*
* Since we have only one shortcode, run the_loop again
* the DB query has already been done, so this has no significant impact
*/
if ( have_posts() ) {
while ( have_posts() ) : the_post();
global $post;
if ( ! array_key_exists( $post->ID, $this->shortcodes ) ) {
continue;
}
// The shortcode must be the first item in the shortcodes array
// Check to see if a shortcode component has been repeated?
if ( isset( $atts['hijack'] ) AND $atts['hijack'] == '1' ) {
add_filter( 'civicrm_context', array( $this, 'get_context' ) );
}
$this->shortcode_markup[$post->ID][] = do_shortcode( $shortcode );
if ( isset( $atts['hijack'] ) AND $atts['hijack'] == '1' ) {
remove_filter( 'civicrm_context', array( $this, 'get_context' ) );
global $civicrm_wp_title;
$post->post_title = $civicrm_wp_title;
add_filter( 'single_post_title', array( $this->civi, 'single_page_title' ), 50, 2 );
add_filter( 'the_content', array( $this, 'get_content' ) );
}
endwhile;
}
/**
* Broadcast that shortcodes have been parsed.
*
* @since 4.6
*/
do_action( 'civicrm_shortcodes_parsed' );
}
/**
* Handles CiviCRM-defined shortcodes.
*
* @since 4.6
* @param array $atts Shortcode attributes array.
* @return string HTML for output.
// Do not parse shortcodes in REST context for PUT, POST and DELETE methods
if(defined('REST_REQUEST') && REST_REQUEST && (isset($_PUT) || isset($_POST) || isset($_DELETE)) ){
// Return the original shortcode
$shortcode = '[civicrm';
foreach($atts as $att=>$val){
$shortcode.=' '.$att.'="'.$val.'"';
}
$shortcode.=']';
return $shortcode;
}
global $post;
if ( is_object($post) ) {
if ( !empty( $this->shortcode_markup ) ) {
if ( isset( $this->shortcode_markup[$post->ID] ) ) {
if ( ! isset( $this->shortcode_in_post[$post->ID] ) ) {
$this->shortcode_in_post[$post->ID] = 0;
} else {
$this->shortcode_in_post[$post->ID]++;
}
return $this->shortcode_markup[$post->ID][$this->shortcode_in_post[$post->ID]];
}
}
}
// Sanity check for improperly constructed shortcode
if ( $args === FALSE ) {
return '<p>' . __( 'Do not know how to handle this shortcode.', 'civicrm' ) . '</p>';
}
// invoke() requires environment variables to be set
foreach ( $args as $key => $value ) {
if ( $value !== NULL ) {
if (!$this->civi->initialize()) {
return '';
}
$argdata = $this->civi->get_request_args();
if ( ! $this->civi->users->check_permission( $argdata['args'] ) ) {
return $this->civi->users->get_permission_denied();;
}
// CMW: why do we need this? Nothing that follows uses it...
require_once ABSPATH . WPINC . '/pluggable.php';
ob_start(); // Start buffering
$this->civi->invoke(); // Now, instead of echoing, shortcode output ends up in buffer
$content = ob_get_clean(); // Save the output and flush the buffer
* Return a generic display for a shortcode instead of a CiviCRM invocation.
*
* @since 4.6
* @param int $post_id The containing WordPress post ID.
* @param string $shortcode The shortcode being parsed.
* @param bool $multiple Boolean flag, TRUE if post has multiple shortcodes, FALSE otherwise.
* @return string $markup Generic markup for multiple instances.
*/
private function render_multiple( $post_id = FALSE, $shortcode = FALSE, $multiple = 0 ) {
// Sanity check for improperly constructed shortcode
if ( $args === FALSE ) {
return '<p>' . __( 'Do not know how to handle this shortcode.', 'civicrm' ) . '</p>';
}
// Get data for this shortcode
$title = __( 'Content via CiviCRM', 'civicrm' );
if ( ! empty( $data['title'] ) ) $title = $data['title'];
if ( $multiple != 0 ) {
$links = array();
foreach( $args AS $var => $arg ) {
if ( ! empty( $arg ) AND $var != 'q' ) {
$links[] = $var . '=' . $arg;
}
}
$query = implode( '&', $links );
// $absolute, $frontend, $forceBackend
$base_url = $this->civi->get_base_url(TRUE, FALSE, FALSE);
// When not using clean URLs
if (!$config->cleanURL) {
// Construct query parts
if (isset($args['q'])) {
$queryParts[] = 'q=' . $args['q'];
}
if (isset($query)) {
$queryParts[] = $query;
}
// 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);
}
if ( !$multiple ) {
if ( isset( $atts['hijack'] ) AND $atts['hijack'] == '1' ) {
add_filter( 'the_title', array( $this, 'get_title' ), 100, 2 );
add_filter( 'the_content', array( $this, 'get_content' ) );
$class = ' civicrm-shortcode-single';
}
}
$description = FALSE;
if ( isset( $data['text'] ) AND ! empty( $data['text'] ) ) {
$description = $data['text'];
}
$more_link = sprintf(
'<a href="%s">%s</a>',
$link,
/**
* Filter the CiviCRM shortcode more link text.
*
* @since 4.6
*
* @param str The existing shortcode more link text.
* @return str The modified shortcode more link text.
*/
apply_filters( 'civicrm_shortcode_more_link', __( 'Find out more...', 'civicrm' ) )
$civi = __( 'CiviCRM.org - Growing and Sustaining Relationships', 'civicrm' );
$logo = '<div class="empowered-by-logo"><span>' . __( 'CiviCRM', 'civicrm' ) . '</span></div>';
$civi_link = '<a href="http://civicrm.org/" title="' . $civi . '" target="_blank" class="empowered-by-link">' . $logo . '</a>';
$empowered = sprintf( __( 'Empowered by %s', 'civicrm' ), $civi_link );
/**
* Filter the CiviCRM shortcode footer text.
*
* @since 4.6
*
* @param str $empowered The existing shortcode footer.
* @return str $empowered The modified shortcode footer.
*/
$footer = apply_filters( 'civicrm_shortcode_footer', $empowered );
$empowered_enabled = TRUE;
}
include( CIVICRM_PLUGIN_DIR . 'assets/templates/civicrm.shortcode.php' );
/**
* Filter the computed CiviCRM shortcode markup.
*
* @since 4.6
*
* @param str $markup The computed shortcode markup.
* @param int $post_id The numeric ID of the WordPress post.
* @param string $shortcode The shortcode being parsed.
* @return str $markup The modified shortcode markup.
*/
return apply_filters( 'civicrm_shortcode_render_multiple', $markup, $post_id, $shortcode );
}
/**
* In order to hijack the page, we need to override the context.
*
* @since 4.6
*/
public function get_context() {
return 'nonpage';
}
/**
* In order to hijack the page, we need to override the content.
* @since 4.6
*
* @return string The overridden content.
*/
public function get_content( $content ) {
global $post;
if ( ! array_key_exists( $post->ID, $this->shortcode_markup ) ) {
return $content;
}
if ( count( $this->shortcode_markup[$post->ID] ) > 1 ) {
return $content;
}
return $this->shortcode_markup[$post->ID][0];
}
/**
* In order to hijack the page, we need to override the title.
*
* @since 4.6
* @param string $title The existing title.
* @param int $post_id The numeric ID of the WordPress post.
* @return string $title The overridden title.
*/
public function get_title( $title, $post_id ) {
if ( ! array_key_exists( $post_id, $this->shortcode_markup ) ) {
return $title;
}
if ( count( $this->shortcode_markup[$post_id] ) > 1 ) {
return $title;
}
if ( array_key_exists( $post_id, $this->post_titles ) ) {
$title = $this->post_titles[$post_id];
}
return $title;
}
/**
* Detect and return CiviCRM shortcodes in post content.
* @since 4.6
*
* @param str $content The content to parse.
* @return array $shortcodes Array of shortcodes.
// Attempt to discover all instances of the shortcode
$pattern = get_shortcode_regex();
if (
preg_match_all( '/' . $pattern . '/s', $content, $matches )
&& array_key_exists( 2, $matches )
&& in_array( 'civicrm', $matches[2] ) )
{
$keys = array_keys( $matches[2], 'civicrm' );
foreach( $keys AS $key ) {
$shortcodes[] = $matches[0][$key];
}
}
return $shortcodes;
}
/**
* Return attributes for a given CiviCRM shortcode.
*
* @since 4.6
* @param $shortcode The shortcode to parse.
* @return array $shortcode_atts Array of shortcode attributes.
$text = str_replace( '[civicrm ', '', $shortcode );
$text = str_replace( ']', '', $text );
$shortcode_atts = shortcode_parse_atts( $text );
return $shortcode_atts;
}
/**
* @since 4.6
*
* @param array $atts Shortcode attributes array.
* @return array $args Shortcode arguments array.
'component' => 'contribution',
'action' => NULL,
'mode' => NULL,
'id' => NULL,
'cid' => NULL,
'gid' => NULL,
'cs' => NULL,
'force' => NULL,
),
$atts,
'civicrm'
);
extract( $shortcode_atts );
$args = array(
'reset' => 1,
'id' => $id,
'force' => $force,
);
switch ( $component ) {
case 'contribution':
if ( $mode == 'preview' || $mode == 'test' ) {
$args['action'] = 'preview';
}
$args['q'] = 'civicrm/contribute/transact';
break;
case 'pcp':
if ( $mode == 'preview' || $mode == 'test' ) {
$args['action'] = 'preview';
}
$args['q'] = 'civicrm/pcp/info';
break;
case 'event':
switch ( $action ) {
case 'register':
$args['q'] = 'civicrm/event/register';
if ( $mode == 'preview' || $mode == 'test' ) {
$args['action'] = 'preview';
}
break;
case 'info':
$args['q'] = 'civicrm/event/info';
break;
default:
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
}
break;
case 'user-dashboard':
$args['q'] = 'civicrm/user';
unset( $args['id'] );
break;
case 'profile':
if ($mode == 'edit') {
$args['q'] = 'civicrm/profile/edit';
}
elseif ($mode == 'view') {
$args['q'] = 'civicrm/profile/view';
}
elseif ($mode == 'search') {
$args['q'] = 'civicrm/profile';
}
else {
$args['q'] = 'civicrm/profile/create';
}
$args['gid'] = $gid;
break;
case 'petition':
$args['q'] = 'civicrm/petition/sign';
$args['sid'] = $args['id'];
unset($args['id']);
break;
}
/**
* Filter the CiviCRM shortcode arguments.
*
* This filter allows plugins or CiviExtensions to modify the attributes
* that the 'civicrm' shortcode allows. Injected attributes and their values
* will also become available in the $_REQUEST and $_GET arrays.
*
* @since 4.7.28
*
* @param array $args Existing shortcode arguments.
* @param array $shortcode_atts Shortcode attributes.
* @return array $args Modified shortcode arguments.
$args = apply_filters( 'civicrm_shortcode_preprocess_atts', $args, $shortcode_atts );
// Sanity check for path
if ( ! isset( $args['q'] ) ) {
return FALSE;
}
return $args;
* Post-process CiviCRM-defined shortcodes.
*
* @since 4.6
*
* @param array $atts Shortcode attributes array
* @param array $args Shortcode arguments array
* @return array|bool $data The array data used to build the shortcode markup (or false on failure)
$data = array();
if (!$this->civi->initialize()) {
return FALSE;
}
/**
* Filter the base CiviCRM API parameters.
*
* This filter allows plugins or CiviExtensions to modify the API call when
* there are multiple shortcodes being rendered.
*
* @since 4.7.28
*
* @param array $params Existing API params.
* @param array $atts Shortcode attributes array.
* @param array $args Shortcode arguments array.
* @return array $params Modified API params.
*/
$params = apply_filters( 'civicrm_shortcode_api_params', array(
switch ( $atts['component'] ) {
case 'contribution':
$civi_entity = civicrm_api( 'contribution_page', 'getsingle', $params );
$data['text'] = '';
if ( isset( $civi_entity['intro_text'] ) ) {
$data['text'] = $civi_entity['intro_text'];
}
break;
case 'event':
$civi_entity = civicrm_api( 'event', 'getsingle', $params );
switch ( $atts['action'] ) {
case 'register':
$data['title'] = sprintf(
__( 'Register for %s', 'civicrm' ),
$civi_entity['title']
);
break;
case 'info':
default:
$data['title'] = $civi_entity['title'];
break;
}
$data['text'] = '';
if ( isset( $civi_entity['summary'] ) ) {
$data['text'] = $civi_entity['summary'];
}
if (
( !isset($civi_entity['summary']) OR empty($civi_entity['summary']) )
AND
isset( $civi_entity['description'] ) AND !empty( $civi_entity['description'] )
) {
$data['text'] = $civi_entity['description'];
}
break;
case 'user-dashboard':
$data['title'] = __( 'Dashboard', 'civicrm' );
break;
case 'profile':
$civi_entity = civicrm_api( 'uf_group', 'getsingle', $params );
$data['text'] = '';
break;
case 'petition':
$civi_entity = civicrm_api( 'survey', 'getsingle', $params );
$data['text'] = '';
if ( isset( $civi_entity['instructions'] ) ) {
$data['text'] = $civi_entity['instructions'];
}
break;
default:
// Do we need to protect against malformed shortcodes?
/**
* Filter the CiviCRM shortcode data array.
*
* This filter allows plugins or CiviExtensions to modify the data used to
* display the shortcode when there are multiple shortcodes being rendered.
*
* @param array $data Existing shortcode data
* @param array $atts Shortcode attributes array
* @param array $args Shortcode arguments array
* @return array $data Modified shortcode data
*/
return apply_filters( 'civicrm_shortcode_get_data', $data, $atts, $args );
} // Class CiviCRM_For_WordPress_Shortcodes ends