all-in-one-event-calendar/app/model/event/creating.php
2019-07-25 14:11:00 +02:00

512 lines
20 KiB
PHP

<?php
/**
* Handles create/update operations.
*
* @author Time.ly Network Inc.
* @since 2.0
*
* @package AI1EC
* @subpackage AI1EC.Model
*/
class Ai1ec_Event_Creating extends Ai1ec_Base {
protected function is_valid_event( $post ) {
// verify this came from the our screen and with proper authorization,
// because save_post can be triggered at other times
if (
! isset( $_POST[AI1EC_POST_TYPE] ) ||
! wp_verify_nonce( $_POST[AI1EC_POST_TYPE], 'ai1ec' )
) {
return false;
}
if (
isset( $post->post_status ) &&
'auto-draft' === $post->post_status
) {
return false;
}
// verify if this is not inline-editing
if (
isset( $_REQUEST['action'] ) &&
'inline-save' === $_REQUEST['action']
) {
return false;
}
// verify that the post_type is that of an event
if ( $post->post_type !== AI1EC_POST_TYPE ) {
return false;
}
return true;
}
private function _parse_post_to_event( $post_id ) {
/**
* =====================================================================
*
* CHANGE CODE BELOW TO HAVE FOLLOWING PROPERTIES:
* - be initializiable from model;
* - have sane defaults;
* - avoid that cluster of isset and ternary operator.
*
* =====================================================================
*/
$all_day = isset( $_POST['ai1ec_all_day_event'] ) ? 1 : 0;
$instant_event = isset( $_POST['ai1ec_instant_event'] ) ? 1 : 0;
$timezone_name = isset( $_POST['ai1ec_timezone_name'] ) ? sanitize_text_field( $_POST['ai1ec_timezone_name'] ) : 'sys.default';
$start_time = isset( $_POST['ai1ec_start_time'] ) ? sanitize_text_field( $_POST['ai1ec_start_time'] ) : '';
$end_time = isset( $_POST['ai1ec_end_time'] ) ? sanitize_text_field( $_POST['ai1ec_end_time'] ) : '';
$venue = isset( $_POST['ai1ec_venue'] ) ? sanitize_text_field( $_POST['ai1ec_venue'] ) : '';
$address = isset( $_POST['ai1ec_address'] ) ? sanitize_text_field( $_POST['ai1ec_address'] ) : '';
$city = isset( $_POST['ai1ec_city'] ) ? sanitize_text_field( $_POST['ai1ec_city'] ) : '';
$province = isset( $_POST['ai1ec_province'] ) ? sanitize_text_field( $_POST['ai1ec_province'] ) : '';
$postal_code = isset( $_POST['ai1ec_postal_code'] ) ? sanitize_text_field( $_POST['ai1ec_postal_code'] ) : '';
$country = isset( $_POST['ai1ec_country'] ) ? sanitize_text_field( $_POST['ai1ec_country'] ) : '';
$google_map = isset( $_POST['ai1ec_google_map'] ) ? 1 : 0;
$cost = isset( $_POST['ai1ec_cost'] ) ? sanitize_text_field( $_POST['ai1ec_cost'] ) : '';
$is_free = isset( $_POST['ai1ec_is_free'] ) ? (bool)$_POST['ai1ec_is_free'] : false;
$ticket_url = isset( $_POST['ai1ec_ticket_url'] ) ? sanitize_text_field( $_POST['ai1ec_ticket_url'] ) : '';
$contact_name = isset( $_POST['ai1ec_contact_name'] ) ? sanitize_text_field( $_POST['ai1ec_contact_name'] ) : '';
$contact_phone = isset( $_POST['ai1ec_contact_phone'] ) ? sanitize_text_field( $_POST['ai1ec_contact_phone'] ) : '';
$contact_email = isset( $_POST['ai1ec_contact_email'] ) ? sanitize_text_field( $_POST['ai1ec_contact_email'] ) : '';
$contact_url = isset( $_POST['ai1ec_contact_url'] ) ? sanitize_text_field( $_POST['ai1ec_contact_url'] ) : '';
$show_coordinates = isset( $_POST['ai1ec_input_coordinates'] )? 1 : 0;
$longitude = isset( $_POST['ai1ec_longitude'] ) ? sanitize_text_field( $_POST['ai1ec_longitude'] ) : '';
$latitude = isset( $_POST['ai1ec_latitude'] ) ? sanitize_text_field( $_POST['ai1ec_latitude'] ) : '';
$cost_type = isset( $_POST['ai1ec_cost_type'] ) ? sanitize_text_field( $_POST['ai1ec_cost_type'] ) : '';
$rrule = null;
$exrule = null;
$exdate = null;
$rdate = null;
if ( 'external' !== $cost_type ) {
$ticket_url = '';
}
$this->_remap_recurrence_dates();
// if rrule is set, convert it from local to UTC time
if (
isset( $_POST['ai1ec_repeat'] ) &&
! empty( $_POST['ai1ec_repeat'] )
) {
$rrule = $_POST['ai1ec_rrule'];
}
// add manual dates
if (
isset( $_POST['ai1ec_exdate'] ) &&
! empty( $_POST['ai1ec_exdate'] )
) {
$exdate = $_POST['ai1ec_exdate'];
}
if (
isset( $_POST['ai1ec_rdate'] ) &&
! empty( $_POST['ai1ec_rdate'] )
) {
$rdate = $_POST['ai1ec_rdate'];
}
// if exrule is set, convert it from local to UTC time
if (
isset( $_POST['ai1ec_exclude'] ) &&
! empty( $_POST['ai1ec_exclude'] ) &&
( null !== $rrule || null !== $rdate ) // no point for exclusion, if repetition is not set
) {
$exrule = $this->_registry->get( 'recurrence.rule' )->merge_exrule(
$_POST['ai1ec_exrule'],
$rrule
);
}
$is_new = false;
try {
$event = $this->_registry->get(
'model.event',
$post_id ? $post_id : null
);
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
// Post exists, but event data hasn't been saved yet. Create new event
// object.
$is_new = true;
$event = $this->_registry->get( 'model.event' );
}
$formatted_timezone = $this->_registry->get( 'date.timezone' )
->get_name( $timezone_name );
if ( empty( $timezone_name ) || ! $formatted_timezone ) {
$timezone_name = 'sys.default';
}
unset( $formatted_timezone );
$start_time_entry = $this->_registry
->get( 'date.time', $start_time, $timezone_name );
$end_time_entry = $this->_registry
->get( 'date.time', $end_time, $timezone_name );
$timezone_name = $start_time_entry->get_timezone();
if ( null === $timezone_name ) {
$timezone_name = $start_time_entry->get_default_format_timezone();
}
$event->set( 'post_id', $post_id );
$event->set( 'start', $start_time_entry );
if ( $instant_event ) {
$event->set_no_end_time();
} else {
$event->set( 'end', $end_time_entry );
$event->set( 'instant_event', false );
}
$event->set( 'timezone_name', $timezone_name );
$event->set( 'allday', $all_day );
$event->set( 'venue', $venue );
$event->set( 'address', $address );
$event->set( 'city', $city );
$event->set( 'province', $province );
$event->set( 'postal_code', $postal_code );
$event->set( 'country', $country );
$event->set( 'show_map', $google_map );
$event->set( 'cost', $cost );
$event->set( 'is_free', $is_free );
$event->set( 'ticket_url', $ticket_url );
$event->set( 'contact_name', $contact_name );
$event->set( 'contact_phone', $contact_phone );
$event->set( 'contact_email', $contact_email );
$event->set( 'contact_url', $contact_url );
$event->set( 'recurrence_rules', $rrule );
$event->set( 'exception_rules', $exrule );
$event->set( 'exception_dates', $exdate );
$event->set( 'recurrence_dates', $rdate );
$event->set( 'show_coordinates', $show_coordinates );
$event->set( 'longitude', trim( $longitude ) );
$event->set( 'latitude', trim( $latitude ) );
$event->set( 'ical_uid', $event->get_uid() );
return array(
'event' => $event,
'is_new' => $is_new
);
}
/**
* Saves meta post data.
*
* @wp_hook save_post
*
* @param int $post_id Post ID.
* @param object $post Post object.
* @param update
*
* @return object|null Saved Ai1ec_Event object if successful or null.
*/
public function save_post( $post_id, $post, $update ) {
if ( false === $this->is_valid_event( $post ) ) {
return null;
}
// LABEL:magicquotes
// remove WordPress `magical` slashes - we work around it ourselves
$_POST = stripslashes_deep( $_POST );
$data = $this->_parse_post_to_event( $post_id );
if ( ! $data ) {
return null;
}
$event = $data['event'];
$is_new = $data['is_new'];
$banner_image = isset( $_POST['ai1ec_banner_image'] ) ? sanitize_text_field( $_POST['ai1ec_banner_image'] ) : '';
$cost_type = isset( $_POST['ai1ec_cost_type'] ) ? sanitize_text_field( $_POST['ai1ec_cost_type'] ) : '';
update_post_meta( $post_id, 'ai1ec_banner_image', $banner_image );
if ( $cost_type ) {
update_post_meta( $post_id, '_ai1ec_cost_type', $cost_type );
}
$api = $this->_registry->get( 'model.api.api-ticketing' );
if ( $update === false ) {
//this method just creates the API event, the update action
//is treated by another hook (pre_update_event inside api )
if ( 'tickets' === $cost_type ) {
$result = $api->store_event( $event, $post, false );
if ( true !== $result ) {
$_POST['_ticket_store_event_error'] = $result;
} else {
update_post_meta(
$post_id,
'_ai1ec_timely_tickets_url',
$api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) )
);
}
}
}
if ( 'tickets' === $cost_type ) {
update_post_meta(
$post_id,
'_ai1ec_timely_tickets_url',
$api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) )
);
} else {
delete_post_meta(
$post_id,
'_ai1ec_timely_tickets_url'
);
}
// let other extensions save their fields.
do_action( 'ai1ec_save_post', $event );
$event->save( ! $is_new );
// LABEL:magicquotes
// restore `magic` WordPress quotes to maintain compatibility
$_POST = add_magic_quotes( $_POST );
$api = $this->_registry->get( 'model.api.api-registration' );
$api->check_settings();
return $event;
}
private function get_sendback_page( $post_id ) {
$sendback = wp_get_referer();
$page_base = Ai1ec_Wp_Uri_Helper::get_pagebase( $sendback ); //$_SERVER['REQUEST_URI'] );
if ( 'post.php' === $page_base ) {
return get_edit_post_link( $post_id, 'url' );
} else {
return admin_url( 'edit.php?post_type=ai1ec_event' );
}
}
/**
* Handle PRE (ticket event) update.
* Just handle the Ticket Events, other kind of post are ignored
* @wp_hook pre_post_update
*
*/
public function pre_post_update ( $post_id, $new_post_data ) {
// LABEL:magicquotes
// remove WordPress `magical` slashes - we work around it ourselves
$_POST = stripslashes_deep( $_POST );
$api = $this->_registry->get( 'model.api.api-ticketing' );
$action = $this->current_action();
switch( $action ) {
case 'inline-save': //quick edit from edit page
$fields = array();
if ( false === ai1ec_is_blank( $_REQUEST['post_title'] ) ) {
$fields['title'] = sanitize_text_field( $_REQUEST['post_title'] );
}
if ( false === ai1ec_is_blank( $_REQUEST['_status'] ) ) {
$fields['status'] = $_REQUEST['_status'];
}
if ( isset( $_REQUEST['keep_private'] ) && 'private' === $_REQUEST['keep_private'] ) {
$fields['visibility'] = 'private';
} else if ( isset( $_REQUEST['post_password'] ) && false === ai1ec_is_blank( $_REQUEST['post_password'] ) ) {
$fields['visibility'] = 'password';
}
if ( 0 < count( $fields ) ) {
$post = get_post( $post_id );
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
$message = $api->update_api_event_fields( $post, $fields, 'update', $ajax );
if ( null !== $message ) {
if ( $ajax ) {
wp_die( $message );
} else {
wp_redirect( $this->get_sendback_page( $post_id ) );
exit();
}
}
}
return;
case 'edit': //bulk edition from edit page
$fields = array();
if ( false === ai1ec_is_blank( $_REQUEST['_status'] ) ) {
$fields['status'] = $_REQUEST['_status'];
}
if ( 0 < count( $fields ) ) {
$post = get_post( $post_id );
$ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
$message = $api->update_api_event_fields( $post, $fields, 'update', $ajax );
if ( null !== $message ) {
if ( $ajax ) {
wp_die( $message );
} else {
wp_redirect( $this->get_sendback_page( $post_id ) );
exit();
}
}
}
return;
case 'editpost': //edition from post page
$new_post_data['ID'] = $post_id;
$post = new WP_Post( (object) $new_post_data );
if ( false === $this->is_valid_event( $post ) ) {
break;
}
$data = $this->_parse_post_to_event( $post_id );
if ( ! $data ) {
break;
}
$event = $data['event'];
$cost_type = isset( $_REQUEST['ai1ec_cost_type'] ) ? $_REQUEST['ai1ec_cost_type'] : '';
if ( 'tickets' === $cost_type ) {
$result = $api->store_event( $event, $post, true );
if ( true !== $result ) {
wp_redirect( $this->get_sendback_page( $post_id ) );
exit();
}
} else {
$message = $api->delete_api_event( $post_id, 'update', false );
if ( null !== $message ) {
wp_redirect( $this->get_sendback_page( $post_id ) );
exit();
}
}
break;
default:
break;
}
// LABEL:magicquotes
// restore `magic` WordPress quotes to maintain compatibility
$_POST = add_magic_quotes( $_POST );
}
protected function current_action() {
$action = '';
if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) ) {
$action = 'delete';
} else {
if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) {
$action = $_REQUEST['action'];
}
if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) {
$action = $_REQUEST['action2'];
}
}
return $action;
}
/**
* _create_duplicate_post method
*
* Create copy of event by calling {@uses wp_insert_post} function.
* Using 'post_parent' to add hierarchy.
*
* @param array $data Event instance data to copy
*
* @return int|bool New post ID or false on failure
**/
public function create_duplicate_post() {
if ( ! isset( $_POST['post_ID'] ) ) {
return false;
}
$clean_fields = array(
'ai1ec_repeat' => NULL,
'ai1ec_rrule' => '',
'ai1ec_exrule' => '',
'ai1ec_exdate' => '',
'post_ID' => NULL,
'post_name' => NULL,
'ai1ec_instance_id' => NULL,
);
$old_post_id = $_POST['post_ID'];
$instance_id = $_POST['ai1ec_instance_id'];
foreach ( $clean_fields as $field => $to_value ) {
if ( NULL === $to_value ) {
unset( $_POST[$field] );
} else {
$_POST[$field] = $to_value;
}
}
$_POST = _wp_translate_postdata( false, $_POST );
$_POST['post_parent'] = $old_post_id;
if ( isset( $_POST['post_title'] ) ) {
$_POST['post_title'] = sanitize_text_field( $_POST['post_title'] );
}
$post_id = wp_insert_post( $_POST );
$this->_registry->get( 'model.event.parent' )->event_parent(
$post_id,
$old_post_id,
$instance_id
);
return $post_id;
}
/**
* Cleans calendar shortcodes from event content.
*
* @param array $data An array of slashed post data.
* @param array $postarr An array of sanitized, but otherwise unmodified post data.
*
* @return array An array of slashed post data.
*/
public function wp_insert_post_data( $data ) {
global $shortcode_tags;
if (
! isset( $data['post_type'] ) ||
! isset( $data['post_content'] ) ||
AI1EC_POST_TYPE !== $data['post_type'] ||
empty( $shortcode_tags ) ||
! is_array( $shortcode_tags ) ||
false === strpos( $data['post_content'], '[' )
) {
return $data;
}
$pattern = get_shortcode_regex();
$data['post_content'] = preg_replace_callback(
"/$pattern/s",
array( $this, 'strip_shortcode_tag' ),
$data['post_content']
);
return $data;
}
/**
* Reutrns shortcode or stripped content for given shortcode.
* Currently regex callback function passes as $tag argument 7-element long
* array.
* First element ($tag[0]) is not modified full shortcode text.
* Third element ($tag[2]) is pure shortcode identifier.
* Sixth element ($tag[5]) contains shortcode content if any
* [ai1ec_test]content[/ai1ec].
*
* @param array $tag Incoming data.
*
* @return string Shortcode replace tag.
*/
public function strip_shortcode_tag( $tag ) {
if (
count( $tag ) < 7 ||
'ai1ec' !== substr( $tag[2], 0, 5 ) ||
! apply_filters( 'ai1ec_content_remove_shortcode_' . $tag[2], false )
) {
return $tag[0];
}
return $tag[5];
}
protected function _remap_recurrence_dates() {
if (
isset( $_POST['ai1ec_exclude'] ) &&
'EXDATE' === substr( $_POST['ai1ec_exrule'], 0, 6 )
) {
$_POST['ai1ec_exdate'] = substr( $_POST['ai1ec_exrule'], 7 );
unset( $_POST['ai1ec_exclude'], $_POST['ai1ec_exrule'] );
}
if (
isset( $_POST['ai1ec_repeat'] ) &&
'RDATE' === substr( $_POST['ai1ec_rrule'], 0, 5 )
) {
$_POST['ai1ec_rdate'] = substr( $_POST['ai1ec_rrule'], 6 );
unset( $_POST['ai1ec_repeat'], $_POST['ai1ec_rrule'] );
}
}
}