Version Description
Download this release
Release Info
Developer | borkweb |
Plugin | Event Tickets |
Version | 4.1 |
Comparing to | |
See all releases |
Code changes from version 4.0.6 to 4.1
- common/README.md +0 -2
- common/src/Tribe/Abstract_Deactivation.php +0 -0
- common/src/Tribe/Admin/Help_Page.php +2 -1
- common/src/Tribe/Admin/Notice/Archive_Slug_Conflict.php +30 -2
- common/src/Tribe/App_Shop.php +0 -0
- common/src/Tribe/Asset/Factory.php +0 -0
- common/src/Tribe/Autoloader.php +0 -0
- common/src/Tribe/Cache.php +0 -0
- common/src/Tribe/Cache_Listener.php +0 -0
- common/src/Tribe/Changelog_Reader.php +0 -0
- common/src/Tribe/Credits.php +1 -1
- common/src/Tribe/Date_Utils.php +0 -0
- common/src/Tribe/Field.php +0 -0
- common/src/Tribe/Main.php +10 -1
- common/src/Tribe/PUE/Checker.php +2 -2
- common/src/Tribe/PUE/Plugin_Info.php +0 -0
- common/src/Tribe/PUE/Utility.php +0 -0
- common/src/Tribe/Post_Transient.php +210 -0
- common/src/Tribe/Settings.php +0 -0
- common/src/Tribe/Settings_Tab.php +0 -0
- common/src/Tribe/Support.php +31 -4
- common/src/Tribe/Support/Obfuscator.php +68 -0
- common/src/Tribe/Support/Template_Checker.php +276 -0
- common/src/Tribe/Support/Template_Checker_Report.php +119 -0
- common/src/Tribe/Template_Factory.php +0 -0
- common/src/Tribe/Template_Part_Cache.php +0 -0
- common/src/Tribe/Validate.php +0 -0
- common/src/Tribe/View_Helpers.php +0 -0
- common/src/admin-views/tribe-options-display.php +0 -0
- common/src/admin-views/tribe-options-general.php +0 -0
- common/src/admin-views/tribe-options-help.php +3 -0
- common/src/admin-views/tribe-options-licenses.php +0 -0
- common/src/admin-views/tribe-options-network.php +0 -0
- common/src/functions/template-tags/date.php +0 -0
- common/src/functions/template-tags/general.php +1 -2
- common/src/resources/css/tribe-common-admin.css +9 -8
- common/src/resources/js/notice-dismiss.js +27 -0
- common/tests.md +0 -47
- common/tests/wpunit/Tribe/Events/common/Date_UtilsTest.php +0 -228
- common/tribe-autoload.php +4 -3
- common/tribe-common.php +1 -1
- common/vendor/jquery/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- common/vendor/jquery/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- common/vendor/jquery/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- common/vendor/jquery/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- common/vendor/jquery/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- common/vendor/jquery/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- common/vendor/jquery/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- common/vendor/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- common/vendor/jquery/images/ui-icons_222222_256x240.png +0 -0
- common/vendor/jquery/images/ui-icons_2e83ff_256x240.png +0 -0
- common/vendor/jquery/images/ui-icons_454545_256x240.png +0 -0
- common/vendor/jquery/images/ui-icons_888888_256x240.png +0 -0
- common/vendor/jquery/images/ui-icons_cd0a0a_256x240.png +0 -0
- common/vendor/jquery/ui.theme.css +0 -0
- event-tickets.php +1 -1
- lang/event-tickets-es_ES.mo +0 -0
- lang/event-tickets-es_ES.po +4 -4
- readme.txt +13 -3
- src/Tribe/Attendees_Table.php +79 -9
- src/Tribe/Global_Stock.php +126 -0
- src/Tribe/Google_Event_Data.php +0 -0
- src/Tribe/Main.php +37 -12
- src/Tribe/Metabox.php +4 -0
- src/Tribe/RSVP.php +99 -13
- src/Tribe/Ticket_Object.php +99 -1
- src/Tribe/Tickets.php +204 -2
- src/Tribe/Tickets_Handler.php +70 -43
- src/admin-views/attendees.php +10 -2
- src/admin-views/list.php +15 -24
- src/admin-views/meta-box.php +59 -4
- src/admin-views/rsvp-metabox-advanced.php +1 -1
- src/deprecated/TribeEventsTicketObject.php +0 -0
- src/deprecated/TribeEventsTickets.php +0 -0
- src/deprecated/TribeEventsTicketsAttendeesTable.php +0 -0
- src/deprecated/TribeEventsTicketsMetabox.php +0 -0
- src/deprecated/TribeEventsTicketsPro.php +0 -0
- src/deprecated/Tribe__Events__Tickets__Attendees_Table.php +0 -0
- src/deprecated/Tribe__Events__Tickets__Metabox.php +0 -0
- src/deprecated/Tribe__Events__Tickets__Ticket_Object.php +0 -0
- src/deprecated/Tribe__Events__Tickets__Tickets.php +0 -0
- src/deprecated/Tribe__Events__Tickets__Tickets_Pro.php +0 -0
- src/resources/css/rsvp.css +6 -2
- src/resources/css/rsvp.min.css +1 -0
- src/resources/css/tickets-attendees-print.min.css +1 -1
- src/resources/css/tickets-attendees.min.css +1 -1
- src/resources/css/tickets.css +20 -0
- src/resources/css/tickets.min.css +1 -1
- src/resources/js/frontend-ticket-form.js +290 -0
- src/resources/js/frontend-ticket-form.min.js +1 -0
- src/resources/js/rsvp.js +29 -0
- src/resources/js/rsvp.min.js +1 -1
- src/resources/js/tickets-attendees.min.js +1 -1
- src/resources/js/tickets.js +158 -19
- src/resources/js/tickets.min.js +1 -1
- src/template-tags/tickets.php +42 -13
- src/views/tickets/rsvp.php +43 -15
- tests.md +0 -47
common/README.md
DELETED
@@ -1,2 +0,0 @@
|
|
1 |
-
# tribe-common
|
2 |
-
Common classes and functions used in our plugins
|
|
|
|
common/src/Tribe/Abstract_Deactivation.php
CHANGED
File without changes
|
common/src/Tribe/Admin/Help_Page.php
CHANGED
@@ -430,7 +430,8 @@ class Tribe__Admin__Help_Page {
|
|
430 |
'i' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
431 |
'u' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
432 |
|
433 |
-
'div'
|
|
|
434 |
'p' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
435 |
'ol' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
436 |
'ul' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
430 |
'i' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
431 |
'u' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
432 |
|
433 |
+
'div' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
434 |
+
'h5' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
435 |
'p' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
436 |
'ol' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
437 |
'ul' => array( 'style' => array(), 'class' => array(), 'id' => array() ),
|
common/src/Tribe/Admin/Notice/Archive_Slug_Conflict.php
CHANGED
@@ -44,15 +44,43 @@ class Tribe__Admin__Notice__Archive_Slug_Conflict {
|
|
44 |
return;
|
45 |
}
|
46 |
$this->page = $page;
|
|
|
|
|
|
|
|
|
|
|
47 |
add_action( 'admin_notices', array( $this, 'notice' ) );
|
48 |
}
|
49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
/**
|
51 |
* Echoes the admin notice to the page
|
52 |
*/
|
53 |
public function notice() {
|
54 |
// What's happening?
|
55 |
-
$page_title = apply_filters( 'the_title', $this->page->post_title );
|
56 |
$line_1 = __( sprintf( 'The page "%1$s" uses the "/%2$s" slug: the Events Calendar plugin will show its calendar in place of the page.', $page_title, $this->archive_slug ), 'tribe-common' );
|
57 |
|
58 |
// What the user can do
|
@@ -68,6 +96,6 @@ class Tribe__Admin__Notice__Archive_Slug_Conflict {
|
|
68 |
|
69 |
$line_2 = __( sprintf( '%1$s or %2$s', $page_edit_link_string, $events_settings_link_string ), 'tribe-common' );
|
70 |
|
71 |
-
echo sprintf( '<div id="message" class="error"><p>%s</p><p>%s</p></div>', $line_1, $line_2 );
|
72 |
}
|
73 |
}
|
44 |
return;
|
45 |
}
|
46 |
$this->page = $page;
|
47 |
+
$dimissed_notices = get_user_meta( get_current_user_id(), 'tribe-dismiss-notice' );
|
48 |
+
|
49 |
+
if ( in_array( 'archive-slug-conflict', $dimissed_notices ) ) {
|
50 |
+
return;
|
51 |
+
}
|
52 |
add_action( 'admin_notices', array( $this, 'notice' ) );
|
53 |
}
|
54 |
|
55 |
+
/**
|
56 |
+
* Hooked before maybe_add_admin_notice to prevent a notice to show it has been dimissed
|
57 |
+
* @return void
|
58 |
+
*/
|
59 |
+
public function maybe_dismiss() {
|
60 |
+
if ( empty( $_GET['tribe-dismiss-notice'] ) ) {
|
61 |
+
return;
|
62 |
+
}
|
63 |
+
|
64 |
+
$notice = esc_attr( $_GET['tribe-dismiss-notice'] );
|
65 |
+
|
66 |
+
if ( 'archive-slug-conflict' !== $notice ) {
|
67 |
+
return;
|
68 |
+
}
|
69 |
+
|
70 |
+
$dimissed_notices = get_user_meta( get_current_user_id(), 'tribe-dismiss-notice' );
|
71 |
+
if ( in_array( 'archive-slug-conflict', $dimissed_notices ) ) {
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
|
75 |
+
add_user_meta( get_current_user_id(), 'tribe-dismiss-notice', 'archive-slug-conflict', false );
|
76 |
+
}
|
77 |
+
|
78 |
/**
|
79 |
* Echoes the admin notice to the page
|
80 |
*/
|
81 |
public function notice() {
|
82 |
// What's happening?
|
83 |
+
$page_title = apply_filters( 'the_title', $this->page->post_title, $this->page->ID );
|
84 |
$line_1 = __( sprintf( 'The page "%1$s" uses the "/%2$s" slug: the Events Calendar plugin will show its calendar in place of the page.', $page_title, $this->archive_slug ), 'tribe-common' );
|
85 |
|
86 |
// What the user can do
|
96 |
|
97 |
$line_2 = __( sprintf( '%1$s or %2$s', $page_edit_link_string, $events_settings_link_string ), 'tribe-common' );
|
98 |
|
99 |
+
echo sprintf( '<div id="message" class="notice error is-dismissible tribe-dismiss-notice" data-ref="archive-slug-conflict"><p>%s</p><p>%s</p></div>', $line_1, $line_2 );
|
100 |
}
|
101 |
}
|
common/src/Tribe/App_Shop.php
CHANGED
File without changes
|
common/src/Tribe/Asset/Factory.php
CHANGED
File without changes
|
common/src/Tribe/Autoloader.php
CHANGED
File without changes
|
common/src/Tribe/Cache.php
CHANGED
File without changes
|
common/src/Tribe/Cache_Listener.php
CHANGED
File without changes
|
common/src/Tribe/Changelog_Reader.php
CHANGED
File without changes
|
common/src/Tribe/Credits.php
CHANGED
@@ -23,7 +23,7 @@ class Tribe__Credits {
|
|
23 |
* @return void
|
24 |
**/
|
25 |
public function html_comment_credit( $after_html ) {
|
26 |
-
$html_credit = "\n<!--\n" . esc_html__( 'This calendar is powered by The Events Calendar.', 'tribe-common' ) . "\nhttp://
|
27 |
$after_html .= apply_filters( 'tribe_html_credit', $html_credit );
|
28 |
return $after_html;
|
29 |
}
|
23 |
* @return void
|
24 |
**/
|
25 |
public function html_comment_credit( $after_html ) {
|
26 |
+
$html_credit = "\n<!--\n" . esc_html__( 'This calendar is powered by The Events Calendar.', 'tribe-common' ) . "\nhttp://m.tri.be/18wn\n-->\n";
|
27 |
$after_html .= apply_filters( 'tribe_html_credit', $html_credit );
|
28 |
return $after_html;
|
29 |
}
|
common/src/Tribe/Date_Utils.php
CHANGED
File without changes
|
common/src/Tribe/Field.php
CHANGED
File without changes
|
common/src/Tribe/Main.php
CHANGED
@@ -17,7 +17,7 @@ class Tribe__Main {
|
|
17 |
const OPTIONNAME = 'tribe_events_calendar_options';
|
18 |
const OPTIONNAMENETWORK = 'tribe_events_calendar_network_options';
|
19 |
|
20 |
-
const VERSION = '4.
|
21 |
const FEED_URL = 'https://theeventscalendar.com/feed/';
|
22 |
|
23 |
protected $plugin_context;
|
@@ -123,6 +123,14 @@ class Tribe__Main {
|
|
123 |
apply_filters( 'tribe_events_css_version', self::VERSION ),
|
124 |
true
|
125 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
}
|
127 |
|
128 |
/**
|
@@ -173,6 +181,7 @@ class Tribe__Main {
|
|
173 |
|
174 |
public function admin_enqueue_scripts() {
|
175 |
wp_enqueue_script( 'tribe-inline-bumpdown' );
|
|
|
176 |
wp_enqueue_style( 'tribe-common-admin' );
|
177 |
|
178 |
$helper = Tribe__Admin__Helpers::instance();
|
17 |
const OPTIONNAME = 'tribe_events_calendar_options';
|
18 |
const OPTIONNAMENETWORK = 'tribe_events_calendar_network_options';
|
19 |
|
20 |
+
const VERSION = '4.1';
|
21 |
const FEED_URL = 'https://theeventscalendar.com/feed/';
|
22 |
|
23 |
protected $plugin_context;
|
123 |
apply_filters( 'tribe_events_css_version', self::VERSION ),
|
124 |
true
|
125 |
);
|
126 |
+
|
127 |
+
wp_register_script(
|
128 |
+
'tribe-notice-dismiss',
|
129 |
+
$resources_url . '/js/notice-dismiss.js',
|
130 |
+
array( 'jquery' ),
|
131 |
+
apply_filters( 'tribe_events_css_version', self::VERSION ),
|
132 |
+
true
|
133 |
+
);
|
134 |
}
|
135 |
|
136 |
/**
|
181 |
|
182 |
public function admin_enqueue_scripts() {
|
183 |
wp_enqueue_script( 'tribe-inline-bumpdown' );
|
184 |
+
wp_enqueue_script( 'tribe-notice-dismiss' );
|
185 |
wp_enqueue_style( 'tribe-common-admin' );
|
186 |
|
187 |
$helper = Tribe__Admin__Helpers::instance();
|
common/src/Tribe/PUE/Checker.php
CHANGED
@@ -430,12 +430,12 @@ if ( ! class_exists( 'Tribe__PUE__Checker' ) ) {
|
|
430 |
} elseif ( isset( $pluginInfo->api_invalid ) && $pluginInfo->api_invalid == 1 ) {
|
431 |
$response['message'] = esc_html__( 'Sorry, this key is not valid.', 'tribe-common' );
|
432 |
} else {
|
433 |
-
$api_secret_key =
|
434 |
if ( $api_secret_key && $api_secret_key === $queryArgs['pu_install_key'] ){
|
435 |
$default_success_msg = sprintf( esc_html__( 'Valid Key! Expires on %s', 'tribe-common' ), $expiration );
|
436 |
} else {
|
437 |
// Set the key
|
438 |
-
|
439 |
|
440 |
$default_success_msg = sprintf( esc_html__( 'Thanks for setting up a valid key, it will expire on %s', 'tribe-common' ), $expiration );
|
441 |
}
|
430 |
} elseif ( isset( $pluginInfo->api_invalid ) && $pluginInfo->api_invalid == 1 ) {
|
431 |
$response['message'] = esc_html__( 'Sorry, this key is not valid.', 'tribe-common' );
|
432 |
} else {
|
433 |
+
$api_secret_key = get_option( $this->pue_install_key );
|
434 |
if ( $api_secret_key && $api_secret_key === $queryArgs['pu_install_key'] ){
|
435 |
$default_success_msg = sprintf( esc_html__( 'Valid Key! Expires on %s', 'tribe-common' ), $expiration );
|
436 |
} else {
|
437 |
// Set the key
|
438 |
+
update_option( $this->pue_install_key, $queryArgs['pu_install_key'] );
|
439 |
|
440 |
$default_success_msg = sprintf( esc_html__( 'Thanks for setting up a valid key, it will expire on %s', 'tribe-common' ), $expiration );
|
441 |
}
|
common/src/Tribe/PUE/Plugin_Info.php
CHANGED
File without changes
|
common/src/Tribe/PUE/Utility.php
CHANGED
File without changes
|
common/src/Tribe/Post_Transient.php
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A Class to handle Transients for posts, useful for caching complex structures
|
5 |
+
* It uses the same logic as WordPress Transient, but instead of options it will
|
6 |
+
* use the Post Meta as the table
|
7 |
+
*
|
8 |
+
* @since 4.1
|
9 |
+
*/
|
10 |
+
class Tribe__Post_Transient {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Get (and instantiate, if necessary) the instance of the class
|
14 |
+
*
|
15 |
+
* @since 4.1
|
16 |
+
* @static
|
17 |
+
* @return self
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
public static function instance() {
|
21 |
+
static $instance;
|
22 |
+
|
23 |
+
if ( ! $instance instanceof self ) {
|
24 |
+
$instance = new self;
|
25 |
+
}
|
26 |
+
|
27 |
+
return $instance;
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Delete a post meta transient.
|
32 |
+
*
|
33 |
+
* @since 4.1
|
34 |
+
*
|
35 |
+
* @param int $post_id The Post ID, can also be a WP_Post
|
36 |
+
* @param string $transient Post Meta to Delete
|
37 |
+
* @param string $value Only delete if the value Matches
|
38 |
+
*
|
39 |
+
*/
|
40 |
+
public function delete( $post_id, $transient, $value = null ) {
|
41 |
+
global $_wp_using_ext_object_cache;
|
42 |
+
|
43 |
+
if ( is_numeric( $post_id ) ) {
|
44 |
+
$post_id = (int) $post_id;
|
45 |
+
} else {
|
46 |
+
$post = get_post( $post_id );
|
47 |
+
$post_id = $post->ID;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Use this to pre attach an action to deleting a Post Transient
|
52 |
+
*
|
53 |
+
* @since 4.1
|
54 |
+
*
|
55 |
+
* @param int $post_id Post ID
|
56 |
+
* @param string $transient The Post Meta Key
|
57 |
+
*/
|
58 |
+
do_action( 'tribe_delete_post_meta_transient_' . $transient, $post_id, $transient );
|
59 |
+
|
60 |
+
if ( $_wp_using_ext_object_cache ) {
|
61 |
+
$result = wp_cache_delete( "tribe_{$transient}-{$post_id}", "tribe_post_meta_transient-{$post_id}" );
|
62 |
+
} else {
|
63 |
+
$meta_timeout = '_transient_timeout_' . $transient;
|
64 |
+
$meta = '_transient_' . $transient;
|
65 |
+
$result = delete_post_meta( $post_id, $meta, $value );
|
66 |
+
if ( $result ) {
|
67 |
+
delete_post_meta( $post_id, $meta_timeout, $value );
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
if ( $result ) {
|
72 |
+
/**
|
73 |
+
* Use this to attach an Action to when the Transient is deleted
|
74 |
+
*
|
75 |
+
* @since 4.1
|
76 |
+
*
|
77 |
+
* @param int $post_id Post ID
|
78 |
+
* @param string $transient The Post Meta Key
|
79 |
+
*/
|
80 |
+
do_action( 'tribe_deleted_post_meta_transient', $transient, $post_id, $transient );
|
81 |
+
}
|
82 |
+
|
83 |
+
return $result;
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Fetches the Transient Data
|
88 |
+
*
|
89 |
+
* @since 4.1
|
90 |
+
*
|
91 |
+
* @param int $post_id The Post ID, can also be a WP_Post
|
92 |
+
* @param string $transient Post Meta to Fetch
|
93 |
+
*
|
94 |
+
*/
|
95 |
+
public function get( $post_id, $transient ) {
|
96 |
+
global $_wp_using_ext_object_cache;
|
97 |
+
|
98 |
+
if ( is_numeric( $post_id ) ) {
|
99 |
+
$post_id = (int) $post_id;
|
100 |
+
} else {
|
101 |
+
$post = get_post( $post_id );
|
102 |
+
$post_id = $post->ID;
|
103 |
+
}
|
104 |
+
|
105 |
+
if ( has_filter( 'tribe_pre_post_meta_transient_' . $transient ) ) {
|
106 |
+
/**
|
107 |
+
* Attach an action before getting the new Transient
|
108 |
+
*
|
109 |
+
* @since 4.1
|
110 |
+
*
|
111 |
+
* @param int $post_id Post ID
|
112 |
+
* @param string $transient The Post Meta Key
|
113 |
+
*/
|
114 |
+
$pre = apply_filters( 'tribe_pre_post_meta_transient_' . $transient, $post_id, $transient );
|
115 |
+
if ( false !== $pre ) {
|
116 |
+
return $pre;
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
if ( $_wp_using_ext_object_cache ) {
|
121 |
+
$value = wp_cache_get( "tribe_{$transient}-{$post_id}", "tribe_post_meta_transient-{$post_id}" );
|
122 |
+
} else {
|
123 |
+
$meta_timeout = '_transient_timeout_' . $transient;
|
124 |
+
$meta = '_transient_' . $transient;
|
125 |
+
$value = get_post_meta( $post_id, $meta, true );
|
126 |
+
if ( $value && ! defined( 'WP_INSTALLING' ) ) {
|
127 |
+
if ( get_post_meta( $post_id, $meta_timeout, true ) < time() ) {
|
128 |
+
$this->delete( $post_id, $transient );
|
129 |
+
return false;
|
130 |
+
}
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Attach an action after getting the new Transient
|
136 |
+
*
|
137 |
+
* @since 4.1
|
138 |
+
*
|
139 |
+
* @param int $post_id Post ID
|
140 |
+
* @param string $transient The Post Meta Key
|
141 |
+
*/
|
142 |
+
return
|
143 |
+
has_filter( 'tribe_post_meta_transient_' . $transient )
|
144 |
+
? apply_filters( 'tribe_post_meta_transient_' . $transient, $value, $post_id )
|
145 |
+
: $value;
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Sets a new value for the Transient
|
150 |
+
*
|
151 |
+
* @since 4.1
|
152 |
+
*
|
153 |
+
* @param int $post_id The Post ID, can also be a WP_Post
|
154 |
+
* @param string $transient Post Meta to set
|
155 |
+
* @param string $value Only delete if the value Matches
|
156 |
+
* @param int $expiration How long this transient will be valid, in seconds
|
157 |
+
*
|
158 |
+
*/
|
159 |
+
public function set( $post_id, $transient, $value, $expiration = 0 ) {
|
160 |
+
global $_wp_using_ext_object_cache;
|
161 |
+
|
162 |
+
if ( is_numeric( $post_id ) ) {
|
163 |
+
$post_id = (int) $post_id;
|
164 |
+
} else {
|
165 |
+
$post = get_post( $post_id );
|
166 |
+
$post_id = $post->ID;
|
167 |
+
}
|
168 |
+
|
169 |
+
$this->delete( $post_id, $transient );
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Attach an action before setting the new Transient
|
173 |
+
*
|
174 |
+
* @since 4.1
|
175 |
+
*
|
176 |
+
* @param int $post_id Post ID
|
177 |
+
* @param string $transient The Post Meta Key
|
178 |
+
*/
|
179 |
+
if ( has_filter( 'tribe_pre_set_post_meta_transient_' . $transient ) ) {
|
180 |
+
$value = apply_filters( 'tribe_pre_set_post_meta_transient_' . $transient, $value, $post_id, $transient );
|
181 |
+
}
|
182 |
+
|
183 |
+
if ( $_wp_using_ext_object_cache ) {
|
184 |
+
$result = wp_cache_set( "tribe_{$transient}-{$post_id}", $value, "tribe_post_meta_transient-{$post_id}", $expiration );
|
185 |
+
} else {
|
186 |
+
$meta_timeout = '_transient_timeout_' . $transient;
|
187 |
+
$meta = '_transient_' . $transient;
|
188 |
+
if ( $expiration ) {
|
189 |
+
add_post_meta( $post_id, $meta_timeout, time() + $expiration, true );
|
190 |
+
}
|
191 |
+
$result = add_post_meta( $post_id, $meta, $value, true );
|
192 |
+
}
|
193 |
+
|
194 |
+
if ( $result ) {
|
195 |
+
/**
|
196 |
+
* Attach an action after setting the new Transient
|
197 |
+
*
|
198 |
+
* @since 4.1
|
199 |
+
*
|
200 |
+
* @param int $post_id Post ID
|
201 |
+
* @param string $transient The Post Meta Key
|
202 |
+
*/
|
203 |
+
do_action( 'tribe_set_post_meta_transient_' . $transient, $post_id, $transient );
|
204 |
+
}
|
205 |
+
|
206 |
+
return $result;
|
207 |
+
}
|
208 |
+
|
209 |
+
|
210 |
+
}
|
common/src/Tribe/Settings.php
CHANGED
File without changes
|
common/src/Tribe/Settings_Tab.php
CHANGED
File without changes
|
common/src/Tribe/Support.php
CHANGED
@@ -15,6 +15,11 @@ if ( ! class_exists( 'Tribe__Support' ) ) {
|
|
15 |
public static $support;
|
16 |
public $rewrite_rules_purged = false;
|
17 |
|
|
|
|
|
|
|
|
|
|
|
18 |
/**
|
19 |
* Fields listed here contain HTML and should be escaped before being
|
20 |
* printed.
|
@@ -26,6 +31,15 @@ if ( ! class_exists( 'Tribe__Support' ) ) {
|
|
26 |
'tribeEventsBeforeHTML',
|
27 |
);
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
private function __construct() {
|
30 |
$this->must_escape = (array) apply_filters( 'tribe_help_must_escape_fields', $this->must_escape );
|
31 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'append_system_info' ), 10 );
|
@@ -107,7 +121,8 @@ if ( ! class_exists( 'Tribe__Support' ) ) {
|
|
107 |
$keys = apply_filters( 'tribe-pue-install-keys', array() );
|
108 |
|
109 |
$systeminfo = array(
|
110 |
-
'
|
|
|
111 |
'name' => $user->display_name,
|
112 |
'email' => $user->user_email,
|
113 |
'install keys' => $keys,
|
@@ -178,6 +193,9 @@ if ( ! class_exists( 'Tribe__Support' ) ) {
|
|
178 |
if ( in_array( $obj_key, $this->must_escape ) ) {
|
179 |
$obj_val = esc_html( $obj_val );
|
180 |
}
|
|
|
|
|
|
|
181 |
if ( is_array( $obj_val ) ) {
|
182 |
$formatted_v[] = sprintf( '<li>%s = <pre>%s</pre></li>', $obj_key, print_r( $obj_val, true ) );
|
183 |
} else {
|
@@ -200,6 +218,15 @@ if ( ! class_exists( 'Tribe__Support' ) ) {
|
|
200 |
$this->rewrite_rules_purged = true;
|
201 |
}//end log_rewrite_rule_purge
|
202 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
/****************** SINGLETON GUTS ******************/
|
204 |
|
205 |
/**
|
@@ -210,13 +237,13 @@ if ( ! class_exists( 'Tribe__Support' ) ) {
|
|
210 |
|
211 |
public static function getInstance() {
|
212 |
if ( null == self::$instance ) {
|
213 |
-
$
|
214 |
-
|
|
|
215 |
}
|
216 |
|
217 |
return self::$instance;
|
218 |
}
|
219 |
-
|
220 |
}
|
221 |
|
222 |
}
|
15 |
public static $support;
|
16 |
public $rewrite_rules_purged = false;
|
17 |
|
18 |
+
/**
|
19 |
+
* @var Tribe__Support__Obfuscator
|
20 |
+
*/
|
21 |
+
protected $obfuscator;
|
22 |
+
|
23 |
/**
|
24 |
* Fields listed here contain HTML and should be escaped before being
|
25 |
* printed.
|
31 |
'tribeEventsBeforeHTML',
|
32 |
);
|
33 |
|
34 |
+
/**
|
35 |
+
* Field prefixes here should be partially obfuscated before being printed.
|
36 |
+
*
|
37 |
+
* @var array
|
38 |
+
*/
|
39 |
+
protected $must_obfuscate_prefixes = array(
|
40 |
+
'pue_install_key_',
|
41 |
+
);
|
42 |
+
|
43 |
private function __construct() {
|
44 |
$this->must_escape = (array) apply_filters( 'tribe_help_must_escape_fields', $this->must_escape );
|
45 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'append_system_info' ), 10 );
|
121 |
$keys = apply_filters( 'tribe-pue-install-keys', array() );
|
122 |
|
123 |
$systeminfo = array(
|
124 |
+
'Home URL' => get_home_url(),
|
125 |
+
'Site URL' => get_site_url(),
|
126 |
'name' => $user->display_name,
|
127 |
'email' => $user->user_email,
|
128 |
'install keys' => $keys,
|
193 |
if ( in_array( $obj_key, $this->must_escape ) ) {
|
194 |
$obj_val = esc_html( $obj_val );
|
195 |
}
|
196 |
+
|
197 |
+
$obj_val = $this->obfuscator->obfuscate( $obj_key, $obj_val );
|
198 |
+
|
199 |
if ( is_array( $obj_val ) ) {
|
200 |
$formatted_v[] = sprintf( '<li>%s = <pre>%s</pre></li>', $obj_key, print_r( $obj_val, true ) );
|
201 |
} else {
|
218 |
$this->rewrite_rules_purged = true;
|
219 |
}//end log_rewrite_rule_purge
|
220 |
|
221 |
+
/**
|
222 |
+
* Sets the obfuscator to be used.
|
223 |
+
*
|
224 |
+
* @param Tribe__Support__Obfuscator $obfuscator
|
225 |
+
*/
|
226 |
+
public function set_obfuscator( Tribe__Support__Obfuscator $obfuscator ) {
|
227 |
+
$this->obfuscator = $obfuscator;
|
228 |
+
}
|
229 |
+
|
230 |
/****************** SINGLETON GUTS ******************/
|
231 |
|
232 |
/**
|
237 |
|
238 |
public static function getInstance() {
|
239 |
if ( null == self::$instance ) {
|
240 |
+
$instance = new self;
|
241 |
+
$instance->set_obfuscator( new Tribe__Support__Obfuscator( $instance->must_obfuscate_prefixes ) );
|
242 |
+
self::$instance = $instance;
|
243 |
}
|
244 |
|
245 |
return self::$instance;
|
246 |
}
|
|
|
247 |
}
|
248 |
|
249 |
}
|
common/src/Tribe/Support/Obfuscator.php
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
class Tribe__Support__Obfuscator {
|
5 |
+
|
6 |
+
/**
|
7 |
+
* @var array
|
8 |
+
*/
|
9 |
+
protected $prefixes = array();
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Tribe__Support__Obfuscator constructor.
|
13 |
+
*
|
14 |
+
* @param array $prefixes
|
15 |
+
*/
|
16 |
+
public function __construct( array $prefixes = array() ) {
|
17 |
+
$this->prefixes = $prefixes;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Whether a value should be obfuscated or not.
|
22 |
+
*
|
23 |
+
* @param string $key
|
24 |
+
*
|
25 |
+
* @return bool
|
26 |
+
*/
|
27 |
+
public function should_obfuscate( $key ) {
|
28 |
+
foreach ( $this->prefixes as $prefix ) {
|
29 |
+
if ( strpos( $key, $prefix ) === 0 ) {
|
30 |
+
return true;
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
return false;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Conditionally obfuscates a string value.
|
39 |
+
*
|
40 |
+
* @param string $key
|
41 |
+
* @param mixed $string_value
|
42 |
+
*
|
43 |
+
* @return mixed Either the obfuscated string or the original value if not a string.
|
44 |
+
*/
|
45 |
+
public function obfuscate( $key, $string_value ) {
|
46 |
+
if ( ! is_string( $string_value ) ) {
|
47 |
+
return $string_value;
|
48 |
+
}
|
49 |
+
if ( ! $this->should_obfuscate( $key ) ) {
|
50 |
+
return $string_value;
|
51 |
+
}
|
52 |
+
|
53 |
+
$length = strlen( $string_value );
|
54 |
+
if ( $length <= 3 ) {
|
55 |
+
return preg_replace( "/./", "#", $string_value );
|
56 |
+
} elseif ( $length > 3 && $length <= 5 ) {
|
57 |
+
return preg_replace( '/^(.{1}).*$/', '$1' . str_repeat( '#', $length - 1 ) . '$2', $string_value );
|
58 |
+
} elseif ( $length > 5 && $length <= 9 ) {
|
59 |
+
return preg_replace( '/^(.{1}).*(.{1})$/', '$1' . str_repeat( '#', $length - 2 ) . '$2', $string_value );
|
60 |
+
} elseif ( $length > 9 && $length <= 19 ) {
|
61 |
+
return preg_replace( '/^(.{2}).*(.{2})$/', '$1' . str_repeat( '#', $length - 4 ) . '$2', $string_value );
|
62 |
+
} elseif ( $length > 19 && $length <= 31 ) {
|
63 |
+
return preg_replace( '/^(.{3}).*(.{3})$/', '$1' . str_repeat( '#', $length - 6 ) . '$2', $string_value );
|
64 |
+
}
|
65 |
+
|
66 |
+
return preg_replace( '/^(.{4}).*(.{4})$/', '$1' . str_repeat( '#', $length - 8 ) . '$2', $string_value );
|
67 |
+
}
|
68 |
+
}
|
common/src/Tribe/Support/Template_Checker.php
ADDED
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Examines a plugin's views directory and builds a list of view filenames
|
4 |
+
* and their respective version numbers.
|
5 |
+
*/
|
6 |
+
class Tribe__Support__Template_Checker {
|
7 |
+
protected $plugin_name = '';
|
8 |
+
protected $plugin_version = '';
|
9 |
+
protected $plugin_views_dir = '';
|
10 |
+
protected $theme_views_dir = '';
|
11 |
+
|
12 |
+
protected $originals = array();
|
13 |
+
protected $overrides = array();
|
14 |
+
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Examine the plugin views (and optionally any theme overrides) and analyse
|
18 |
+
* the version numbers where possible.
|
19 |
+
*
|
20 |
+
* @param string $plugin_version
|
21 |
+
* @param string $plugin_views_dir
|
22 |
+
* @param string $theme_views_dir
|
23 |
+
*/
|
24 |
+
public function __construct( $plugin_version, $plugin_views_dir, $theme_views_dir = '' ) {
|
25 |
+
$this->plugin_version = $this->base_version_number( $plugin_version );
|
26 |
+
$this->plugin_views_dir = $plugin_views_dir;
|
27 |
+
$this->theme_views_dir = $theme_views_dir;
|
28 |
+
|
29 |
+
$this->scan_view_directory();
|
30 |
+
$this->scan_for_overrides();
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Given a version number with an alpha/beta type suffix, strips that suffix and
|
35 |
+
* returns the "base" version number.
|
36 |
+
*
|
37 |
+
* For example, given "9.8.2beta1" this method will return "9.8.2".
|
38 |
+
*
|
39 |
+
* The utility of this is that if the author of a template change sets the
|
40 |
+
* version tag in the template header to 9.8.2 (to continue the same example) we
|
41 |
+
* don't need to worry about updating that for each alpha, beta or RC we put out.
|
42 |
+
*
|
43 |
+
* @param string $version_number
|
44 |
+
*
|
45 |
+
* @return string
|
46 |
+
*/
|
47 |
+
protected function base_version_number( $version_number ) {
|
48 |
+
return preg_replace( '/[a-z]+[a-z0-9]*$/i', '', $version_number );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Recursively scans the plugin's view directory and examines the template headers
|
53 |
+
* of each file it finds within.
|
54 |
+
*/
|
55 |
+
protected function scan_view_directory() {
|
56 |
+
// If the provided directory is invalid flag the problem and go no further
|
57 |
+
if ( $this->bad_directory( $this->plugin_views_dir ) ) {
|
58 |
+
return;
|
59 |
+
}
|
60 |
+
|
61 |
+
$view_directory = new RecursiveDirectoryIterator( $this->plugin_views_dir );
|
62 |
+
$directory_list = new RecursiveIteratorIterator( $view_directory );
|
63 |
+
|
64 |
+
foreach ( $directory_list as $file ) {
|
65 |
+
$this->scan_view( $file );
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Scans an individual view file, adding it's version number (if found) to the
|
71 |
+
* $this->views array.
|
72 |
+
*
|
73 |
+
* @param SplFileInfo $file
|
74 |
+
*/
|
75 |
+
protected function scan_view( SplFileInfo $file ) {
|
76 |
+
if ( ! $file->isFile() || ! $file->isReadable() ) {
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
|
80 |
+
$version = $this->get_template_version( $file->getPathname() );
|
81 |
+
$this->originals[ $this->short_name( $file->getPathname() ) ] = $version;
|
82 |
+
}
|
83 |
+
|
84 |
+
protected function scan_for_overrides() {
|
85 |
+
// If the provided directory is invalid flag the problem and go no further
|
86 |
+
if ( $this->bad_directory( $this->theme_views_dir ) ) {
|
87 |
+
return;
|
88 |
+
}
|
89 |
+
|
90 |
+
foreach ( $this->originals as $view_file => $current_version ) {
|
91 |
+
$override_path = trailingslashit( $this->theme_views_dir ) . $view_file;
|
92 |
+
|
93 |
+
if ( ! is_file( $override_path ) || ! is_readable( $override_path ) ) {
|
94 |
+
continue;
|
95 |
+
}
|
96 |
+
|
97 |
+
$this->overrides[ $view_file ] = $this->get_template_version( $override_path );
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Tests to ensure the provided view directory path is invalid or unreadable.
|
103 |
+
*
|
104 |
+
* @param string $directory
|
105 |
+
* @return bool
|
106 |
+
*/
|
107 |
+
protected function bad_directory( $directory ) {
|
108 |
+
if ( is_dir( $directory ) && is_readable( $directory ) ) {
|
109 |
+
return false;
|
110 |
+
}
|
111 |
+
|
112 |
+
return true;
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Inspects the template header block within the specified file and extracts the
|
117 |
+
* version number, if one can be found.
|
118 |
+
*
|
119 |
+
* @param string $template_filepath
|
120 |
+
* @return string
|
121 |
+
*/
|
122 |
+
protected function get_template_version( $template_filepath ) {
|
123 |
+
if ( ! is_file( $template_filepath ) || ! is_readable( $template_filepath ) ) {
|
124 |
+
return '';
|
125 |
+
}
|
126 |
+
|
127 |
+
$view_content = file_get_contents( $template_filepath );
|
128 |
+
|
129 |
+
if ( ! preg_match( '/^\s*\*\s*@version\s*([0-9\.]+)/mi', $view_content, $matches ) ) {
|
130 |
+
return '';
|
131 |
+
}
|
132 |
+
|
133 |
+
return $matches[1];
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Given a full filepath (ie, to a view file), chops off the base path found
|
138 |
+
* in $this->plugin_views_dir.
|
139 |
+
*
|
140 |
+
* For example, given:
|
141 |
+
*
|
142 |
+
* $this->plugin_views_dir = '/srv/project/wp-content/plugins/my-plugin/views'
|
143 |
+
* $full_filepath = '/srv/project/wp-content/plugins/my-plugin/views/modules/icon.php'
|
144 |
+
*
|
145 |
+
* Returns:
|
146 |
+
*
|
147 |
+
* 'modules/icon.php'
|
148 |
+
*
|
149 |
+
* @param string $full_filepath
|
150 |
+
* @return string
|
151 |
+
*/
|
152 |
+
protected function short_name( $full_filepath ) {
|
153 |
+
if ( 0 === strpos( $full_filepath, $this->plugin_views_dir ) ) {
|
154 |
+
return trim( substr( $full_filepath, strlen( $this->plugin_views_dir ) ), DIRECTORY_SEPARATOR );
|
155 |
+
}
|
156 |
+
|
157 |
+
return $full_filepath;
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Returns an array of the plugin's shipped view files, where each key is the
|
162 |
+
* view filename and the value is the version it was last updated.
|
163 |
+
*
|
164 |
+
* @return array
|
165 |
+
*/
|
166 |
+
public function get_views() {
|
167 |
+
return $this->originals;
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Returns an array of any or all of the plugin's shipped view files that contain
|
172 |
+
* a version field in their header blocks.
|
173 |
+
*
|
174 |
+
* @see $this->get_views() for format of returned array
|
175 |
+
*
|
176 |
+
* @return array
|
177 |
+
*/
|
178 |
+
public function get_versioned_views() {
|
179 |
+
$versioned_views = array();
|
180 |
+
|
181 |
+
foreach ( $this->originals as $key => $version ) {
|
182 |
+
if ( ! empty( $version ) ) {
|
183 |
+
$versioned_views[ $key ] = $version;
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
return $versioned_views;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Returns an array of any shipped plugin views that were updated or introduced
|
192 |
+
* with the current release (as specified by $this->plugin_version).
|
193 |
+
*
|
194 |
+
* @see $this->get_views() for format of returned array
|
195 |
+
*
|
196 |
+
* @return array
|
197 |
+
*/
|
198 |
+
public function get_views_tagged_this_release() {
|
199 |
+
$currently_tagged_views = array();
|
200 |
+
|
201 |
+
foreach ( $this->get_versioned_views() as $key => $version ) {
|
202 |
+
if ( $version === $this->plugin_version ) {
|
203 |
+
$currently_tagged_views[ $key ] = $version;
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
return $currently_tagged_views;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Returns an array of theme overrides, where each key is the view filename and the
|
212 |
+
* value is the version it was last updated (may be empty).
|
213 |
+
*
|
214 |
+
* @return array
|
215 |
+
*/
|
216 |
+
public function get_overrides() {
|
217 |
+
return $this->overrides;
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* Returns an array of any or all theme overrides that contain a version field in their
|
222 |
+
* header blocks.
|
223 |
+
*
|
224 |
+
* @see $this->get_overrides() for format of returned array
|
225 |
+
*
|
226 |
+
* @return array
|
227 |
+
*/
|
228 |
+
public function get_versioned_overrides() {
|
229 |
+
$versioned_views = array();
|
230 |
+
|
231 |
+
foreach ( $this->overrides as $key => $version ) {
|
232 |
+
if ( ! empty( $version ) ) {
|
233 |
+
$versioned_views[ $key ] = $version;
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
return $versioned_views;
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Returns an array of any or all theme overrides that seem to be based on an earlier
|
242 |
+
* version than that which currently ships with the plugin.
|
243 |
+
*
|
244 |
+
* If optional param $include_unknown is set to true, the list will include theme
|
245 |
+
* overrides where the version could not be determined (for instance, this might result
|
246 |
+
* in theme overrides where the template header - or version tag - was removed being
|
247 |
+
* included).
|
248 |
+
*
|
249 |
+
* @see $this->get_overrides() for format of returned array
|
250 |
+
*
|
251 |
+
* @param bool $include_unknown = false
|
252 |
+
* @return array
|
253 |
+
*/
|
254 |
+
public function get_outdated_overrides( $include_unknown = false ) {
|
255 |
+
$outdated = array();
|
256 |
+
$originals = $this->get_versioned_views();
|
257 |
+
|
258 |
+
$overrides = $include_unknown
|
259 |
+
? $this->get_overrides()
|
260 |
+
: $this->get_versioned_overrides();
|
261 |
+
|
262 |
+
foreach ( $overrides as $view => $override_version ) {
|
263 |
+
if ( empty( $originals[ $view ] ) ) {
|
264 |
+
continue;
|
265 |
+
}
|
266 |
+
|
267 |
+
$shipped_version = $originals[ $view ];
|
268 |
+
|
269 |
+
if ( version_compare( $shipped_version, $override_version, '>' ) ) {
|
270 |
+
$outdated[ $view ] = $override_version;
|
271 |
+
}
|
272 |
+
}
|
273 |
+
|
274 |
+
return $outdated;
|
275 |
+
}
|
276 |
+
}
|
common/src/Tribe/Support/Template_Checker_Report.php
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Assembles a report of recently updated plugin views and template overrides in
|
4 |
+
* possible revision, for each plugin that registers itself and its template
|
5 |
+
* filepaths.
|
6 |
+
*/
|
7 |
+
class Tribe__Support__Template_Checker_Report {
|
8 |
+
const VERSION_INDEX = 0;
|
9 |
+
const INCLUDED_VIEWS_INDEX = 1;
|
10 |
+
const THEME_OVERRIDES_INDEX = 2;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Contains the individual view/template reports for each registered plugin.
|
14 |
+
*
|
15 |
+
* @var array
|
16 |
+
*/
|
17 |
+
protected static $plugin_reports = array();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Container for finished report.
|
21 |
+
*
|
22 |
+
* @var string
|
23 |
+
*/
|
24 |
+
protected static $complete_report = '';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Provides an up-to-date report concerning template changes.
|
28 |
+
*
|
29 |
+
* @return string
|
30 |
+
*/
|
31 |
+
public static function generate() {
|
32 |
+
foreach ( self::registered_plugins() as $plugin_name => $plugin_template_system ) {
|
33 |
+
self::generate_for( $plugin_name, $plugin_template_system );
|
34 |
+
}
|
35 |
+
|
36 |
+
self::wrap_report();
|
37 |
+
return self::$complete_report;
|
38 |
+
}
|
39 |
+
|
40 |
+
protected static function registered_plugins() {
|
41 |
+
/**
|
42 |
+
* Provides a mechanism for plugins to register information about their template/view
|
43 |
+
* setups.
|
44 |
+
*
|
45 |
+
* This should be done by adding an entry to $registere_template_systems where the key
|
46 |
+
* should be the plugin name and the element an array structured as follows:
|
47 |
+
*
|
48 |
+
* [
|
49 |
+
* plugin_version,
|
50 |
+
* path_to_included_views,
|
51 |
+
* path_to_theme_overrides
|
52 |
+
* ]
|
53 |
+
*
|
54 |
+
* @var array $registered_template_systems
|
55 |
+
*/
|
56 |
+
return apply_filters( 'tribe_support_registered_template_systems', array() );
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Creates a report for the specified plugin.
|
61 |
+
*
|
62 |
+
* @param string $plugin_name
|
63 |
+
* @param array $template_system
|
64 |
+
*/
|
65 |
+
protected static function generate_for( $plugin_name, array $template_system ) {
|
66 |
+
$report = '<dt>' . esc_html( $plugin_name ) . '</dt>';
|
67 |
+
|
68 |
+
$scanner = new Tribe__Support__Template_Checker(
|
69 |
+
$template_system[ self::VERSION_INDEX ],
|
70 |
+
$template_system[ self::INCLUDED_VIEWS_INDEX ],
|
71 |
+
$template_system[ self::THEME_OVERRIDES_INDEX ]
|
72 |
+
);
|
73 |
+
|
74 |
+
$newly_introduced_or_updated = $scanner->get_views_tagged_this_release();
|
75 |
+
$outdated_or_unknown = $scanner->get_outdated_overrides( true );
|
76 |
+
|
77 |
+
if ( empty( $newly_introduced_or_updated ) && empty( $outdated_or_unknown ) ) {
|
78 |
+
$report .= '<dd>' . __( 'No notable changes detected', 'tribe-common' ) . '</dd>';
|
79 |
+
}
|
80 |
+
|
81 |
+
if ( ! empty( $newly_introduced_or_updated ) ) {
|
82 |
+
$report .= '<dd><p>' . sprintf( __( 'Templates introduced or updated with this release (%s):', 'tribe-common' ), $template_system[ self::VERSION_INDEX ] ) . '</p><ul>';
|
83 |
+
|
84 |
+
foreach ( $newly_introduced_or_updated as $view_name => $version ) {
|
85 |
+
$report .= '<li>' . esc_html( $view_name ) . '</li>';
|
86 |
+
}
|
87 |
+
|
88 |
+
$report .= '</ul></dd>';
|
89 |
+
}
|
90 |
+
|
91 |
+
if ( ! empty( $outdated_or_unknown ) ) {
|
92 |
+
$report .= '<dd><p>' . __( 'Existing theme overrides that may need revision:', 'tribe-common' ) . '</p><ul>';
|
93 |
+
|
94 |
+
foreach ( $outdated_or_unknown as $view_name => $version ) {
|
95 |
+
$version_note = empty( $version )
|
96 |
+
? __( 'version data missing from override', 'tribe-common' )
|
97 |
+
: sprintf( __( 'based on %s version', 'tribe-common' ), $version );
|
98 |
+
|
99 |
+
$report .= '<li>' . esc_html( $view_name ) . ' (' . $version_note . ') </li>';
|
100 |
+
}
|
101 |
+
|
102 |
+
$report .= '</ul></dd>';
|
103 |
+
}
|
104 |
+
|
105 |
+
self::$plugin_reports[ $plugin_name ] = $report;
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Wraps the individual plugin template reports ready for display.
|
110 |
+
*/
|
111 |
+
protected static function wrap_report() {
|
112 |
+
if ( empty( self::$plugin_reports ) ) {
|
113 |
+
self::$complete_report = '<p>' . __( 'No notable template changes detected.', 'tribe-common' ) . '</p>';
|
114 |
+
} else {
|
115 |
+
self::$complete_report = '<p>' . __( 'Information about recent template changes and potentially impacted template overrides is provided below.', 'tribe-common' ) . '</p>'
|
116 |
+
. '<div class="template-updates-wrapper">' . join( ' ', self::$plugin_reports ) . '</div>';
|
117 |
+
}
|
118 |
+
}
|
119 |
+
}
|
common/src/Tribe/Template_Factory.php
CHANGED
File without changes
|
common/src/Tribe/Template_Part_Cache.php
CHANGED
File without changes
|
common/src/Tribe/Validate.php
CHANGED
File without changes
|
common/src/Tribe/View_Helpers.php
CHANGED
File without changes
|
common/src/admin-views/tribe-options-display.php
CHANGED
File without changes
|
common/src/admin-views/tribe-options-general.php
CHANGED
File without changes
|
common/src/admin-views/tribe-options-help.php
CHANGED
@@ -33,6 +33,9 @@ $help->add_section_content( 'extra-help', '<div style="text-align: right;"><a hr
|
|
33 |
// Creates the System Info section
|
34 |
$help->add_section( 'system-info', __( 'System Information', 'tribe-common' ), 30 );
|
35 |
$help->add_section_content( 'system-info', __( 'The details of your calendar plugin and settings is often needed for you or our staff to help troubleshoot an issue. We may ask you to share this information if you ask for support. If you post in one of our premium forums, please copy and paste this information into the System Information field and it will help us help you faster!', 'tribe-common' ), 0 );
|
|
|
|
|
|
|
36 |
?>
|
37 |
|
38 |
<div id="tribe-help-general">
|
33 |
// Creates the System Info section
|
34 |
$help->add_section( 'system-info', __( 'System Information', 'tribe-common' ), 30 );
|
35 |
$help->add_section_content( 'system-info', __( 'The details of your calendar plugin and settings is often needed for you or our staff to help troubleshoot an issue. We may ask you to share this information if you ask for support. If you post in one of our premium forums, please copy and paste this information into the System Information field and it will help us help you faster!', 'tribe-common' ), 0 );
|
36 |
+
|
37 |
+
$help->add_section( 'template-changes', __( 'Recent Template Changes', 'tribe-common' ), 40 );
|
38 |
+
$help->add_section_content( 'template-changes', Tribe__Support__Template_Checker_Report::generate() );
|
39 |
?>
|
40 |
|
41 |
<div id="tribe-help-general">
|
common/src/admin-views/tribe-options-licenses.php
CHANGED
File without changes
|
common/src/admin-views/tribe-options-network.php
CHANGED
File without changes
|
common/src/functions/template-tags/date.php
CHANGED
File without changes
|
common/src/functions/template-tags/general.php
CHANGED
@@ -158,8 +158,7 @@ if ( ! function_exists( 'tribe_get_date_format' ) ) {
|
|
158 |
$format = tribe_get_date_option( 'dateWithoutYearFormat', 'F j' );
|
159 |
}
|
160 |
|
161 |
-
|
162 |
-
return apply_filters( 'tribe_date_format', stripslashes( $format ) );
|
163 |
}
|
164 |
}//end if
|
165 |
|
158 |
$format = tribe_get_date_option( 'dateWithoutYearFormat', 'F j' );
|
159 |
}
|
160 |
|
161 |
+
return apply_filters( 'tribe_date_format', $format );
|
|
|
162 |
}
|
163 |
}//end if
|
164 |
|
common/src/resources/css/tribe-common-admin.css
CHANGED
@@ -210,7 +210,8 @@ table.plugins .tribe-plugin-update-message a {
|
|
210 |
list-style: circle;
|
211 |
}
|
212 |
|
213 |
-
#tribe-system-info dl.support-stats
|
|
|
214 |
background: #000;
|
215 |
color: #888;
|
216 |
padding: 10px;
|
@@ -219,7 +220,8 @@ table.plugins .tribe-plugin-update-message a {
|
|
219 |
border-radius: 2px;
|
220 |
}
|
221 |
|
222 |
-
#tribe-system-info dl.support-stats dt
|
|
|
223 |
text-transform: uppercase;
|
224 |
font-weight: bold;
|
225 |
width: 25%;
|
@@ -227,13 +229,15 @@ table.plugins .tribe-plugin-update-message a {
|
|
227 |
float: left;
|
228 |
}
|
229 |
|
230 |
-
#tribe-system-info dl.support-stats dd
|
|
|
231 |
padding-left: 10px;
|
232 |
margin-left: 25%;
|
233 |
}
|
234 |
|
235 |
-
|
236 |
-
|
|
|
237 |
|
238 |
#tribe-help-sidebar {
|
239 |
width: 32%;
|
@@ -301,9 +305,6 @@ table.plugins .tribe-plugin-update-message a {
|
|
301 |
list-style: disc inside;
|
302 |
}
|
303 |
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
/* = jQuery UI
|
308 |
=============================================*/
|
309 |
.ui-widget-overlay {background: #666666; opacity: .50;filter:Alpha(Opacity=50); }
|
210 |
list-style: circle;
|
211 |
}
|
212 |
|
213 |
+
#tribe-system-info dl.support-stats,
|
214 |
+
.template-updates-wrapper {
|
215 |
background: #000;
|
216 |
color: #888;
|
217 |
padding: 10px;
|
220 |
border-radius: 2px;
|
221 |
}
|
222 |
|
223 |
+
#tribe-system-info dl.support-stats dt,
|
224 |
+
.template-updates-wrapper dt {
|
225 |
text-transform: uppercase;
|
226 |
font-weight: bold;
|
227 |
width: 25%;
|
229 |
float: left;
|
230 |
}
|
231 |
|
232 |
+
#tribe-system-info dl.support-stats dd,
|
233 |
+
.template-updates-wrapper dd {
|
234 |
padding-left: 10px;
|
235 |
margin-left: 25%;
|
236 |
}
|
237 |
|
238 |
+
.template-updates-wrapper p {
|
239 |
+
margin-top: 0;
|
240 |
+
}
|
241 |
|
242 |
#tribe-help-sidebar {
|
243 |
width: 32%;
|
305 |
list-style: disc inside;
|
306 |
}
|
307 |
|
|
|
|
|
|
|
308 |
/* = jQuery UI
|
309 |
=============================================*/
|
310 |
.ui-widget-overlay {background: #666666; opacity: .50;filter:Alpha(Opacity=50); }
|
common/src/resources/js/notice-dismiss.js
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Notice Dismiss structure
|
3 |
+
*/
|
4 |
+
( function( $ ) {
|
5 |
+
// Add / Update a key-value pair in the URL query parameters
|
6 |
+
function update_query_string(uri, key, value) {
|
7 |
+
// remove the hash part before operating on the uri
|
8 |
+
var i = uri.indexOf( '#' );
|
9 |
+
var hash = i === -1 ? '' : uri.substr(i);
|
10 |
+
uri = i === -1 ? uri : uri.substr(0, i);
|
11 |
+
|
12 |
+
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
|
13 |
+
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
|
14 |
+
if (uri.match(re)) {
|
15 |
+
uri = uri.replace(re, '$1' + key + "=" + value + '$2');
|
16 |
+
} else {
|
17 |
+
uri = uri + separator + key + "=" + value;
|
18 |
+
}
|
19 |
+
return uri + hash; // finally append the hash as well
|
20 |
+
}
|
21 |
+
|
22 |
+
$( document ).ready( function() {
|
23 |
+
$( '.tribe-dismiss-notice.is-dismissible' ).on( 'click', '.notice-dismiss', function() {
|
24 |
+
window.location.href = update_query_string( window.location.href, 'tribe-dismiss-notice', $( this ).parents( '.tribe-dismiss-notice' ).data( 'ref' ) );
|
25 |
+
} );
|
26 |
+
} );
|
27 |
+
}( jQuery ) );
|
common/tests.md
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
# Tribe Common tests
|
2 |
-
|
3 |
-
This is a brief and quick guide that's covering the bare essentials needed to set up the tests on your local plugin copy.
|
4 |
-
Please refer to [Codeception](http://codeception.com/docs) and [WP Browser](https://github.com/lucatume/wp-browser) documentation for any issue that's not TEC related.
|
5 |
-
|
6 |
-
## Set up
|
7 |
-
After cloning the TEX repository on your local machine change directory to the plugin root folder and pull in any needed dependency using [Composer](https://getcomposer.org/):
|
8 |
-
|
9 |
-
composer update
|
10 |
-
|
11 |
-
when Composer finished the update process (might take a while) set up your own [Codeception](http://codeception.com/) installation running
|
12 |
-
|
13 |
-
vendor/bin/wpcept bootstrap
|
14 |
-
|
15 |
-
The `wpcept bootstrap` command is a modified version of the default `codecept bootstrap` command that will take care of setting up a WordPress-friendly testing environment.
|
16 |
-
To be able to run successfully on your system Codeception will need to be configured to look for the right database, the right WordPress installation and so on.
|
17 |
-
Codeception allows for "distribution" versions of its configuration to be shared among developers, what you define in your local Codeception configuration files will override the "distribution" setting; think of CSS rules.
|
18 |
-
The repository contains a `codeception.dist.yml` file that Codeception will read before reading the local to your machine `codeception.yml` file.
|
19 |
-
Copy the distribution version of the Codeception configuration file in the root folder of the plugin
|
20 |
-
|
21 |
-
cp codeception.dist.yml codeception.yml
|
22 |
-
|
23 |
-
**Edit the file `codeception.yml` file to suit your database, installation folder and web driver settings.**
|
24 |
-
|
25 |
-
**Beware**: The `WPLoader` module that's used in functional tests will **destroy** the database it's working on: **do not** point it to the same database you use for development! A good rule of thumb is to have a database for development (e.g. `tec`) and one that will be used for tests (e.g. `tec-tests`).
|
26 |
-
On the same lines the repository packs "distribution" versions of the `unit.suite.dist.yml`, `functional.suite.dist.yml` and `acceptance.suite.dist.yml` configuration files: there is usually no need to override those but it's worth mentioning they exist.
|
27 |
-
The last piece of the configuration is the bootstrap file; the repository comes with "distribution" versions of these file in the root folder of the pluging tests (`/tests/_bootstrap.dist.php`) and a bootstrap file specific to each suite (`/tests/acceptance/_bootstrap.dist.php`, `/tests/functional/_bootstrap.dist.php`, `/tests/unit/_bootstrap.dist.php`); remove the root `_bootstrap.php` file Codeception created during bootstrapping and copy the one in the root of the plugin tests (`/tests`)
|
28 |
-
|
29 |
-
rm _bootstrap.php
|
30 |
-
cp _bootstrap.dist.php _bootstrap.php
|
31 |
-
|
32 |
-
You *should* not need to edit anything in any bootstrap file to make things work. Do the same for the suite specific bootstrap files
|
33 |
-
|
34 |
-
cp acceptance/_bootstrap.dist.php acceptance/_bootstrap.php
|
35 |
-
cp functional/_bootstrap.dist.php functional/_bootstrap.php
|
36 |
-
cp unit/_bootstrap.dist.php unit/_bootstrap.php
|
37 |
-
|
38 |
-
## Running the tests
|
39 |
-
Nothing different from a default Codeception environment so this command will run all the tests
|
40 |
-
|
41 |
-
vendor/bin/codecept run
|
42 |
-
|
43 |
-
Failing tests are ok in set up terms: the system works. Errors should be reported.
|
44 |
-
Please refer to [Codeception documentation](http://codeception.com/docs) to learn about more run and configuaration options.
|
45 |
-
|
46 |
-
## Contributing to tests
|
47 |
-
Should you come up with good utility methods, worthy database configurations and "cool additions" in general for the plugin tests feel free to open a PR and submit them for review.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
common/tests/wpunit/Tribe/Events/common/Date_UtilsTest.php
DELETED
@@ -1,228 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
namespace Tribe\Events\Common;
|
3 |
-
|
4 |
-
use \Tribe__Date_Utils as Date_Utils;
|
5 |
-
|
6 |
-
class Date_UtilsTest extends \Codeception\TestCase\WPTestCase {
|
7 |
-
|
8 |
-
/**
|
9 |
-
* @var string
|
10 |
-
*/
|
11 |
-
protected static $tz_backup;
|
12 |
-
|
13 |
-
protected $backupGlobals = false;
|
14 |
-
|
15 |
-
public static function setUpBeforeClass() {
|
16 |
-
self::$tz_backup = date_default_timezone_get();
|
17 |
-
|
18 |
-
return parent::setUpBeforeClass();
|
19 |
-
}
|
20 |
-
|
21 |
-
public static function tearDownAfterClass() {
|
22 |
-
date_default_timezone_set( self::$tz_backup );
|
23 |
-
|
24 |
-
return parent::tearDownAfterClass();
|
25 |
-
}
|
26 |
-
|
27 |
-
public function setUp() {
|
28 |
-
// before
|
29 |
-
parent::setUp();
|
30 |
-
|
31 |
-
// your set up methods here
|
32 |
-
}
|
33 |
-
|
34 |
-
public function tearDown() {
|
35 |
-
// your tear down methods here
|
36 |
-
|
37 |
-
// then
|
38 |
-
parent::tearDown();
|
39 |
-
}
|
40 |
-
|
41 |
-
public function bad_argument_formats() {
|
42 |
-
return array_map( function ( $arr ) {
|
43 |
-
return [ $arr ];
|
44 |
-
},
|
45 |
-
[
|
46 |
-
[ 'day', 2, 3, 2012, 1 ],
|
47 |
-
[ 2, 'week', 3, 2012, 1 ],
|
48 |
-
[ 2, 2, 'month', 2012, 1 ],
|
49 |
-
[ 2, 2, 3, 'year', 1 ],
|
50 |
-
[ 2, 2, 3, 2012, 'direction' ],
|
51 |
-
[ 2, 2, 3, 2012, 23 ],
|
52 |
-
[ 2, 2, 3, 2012, - 2 ],
|
53 |
-
] );
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* get_weekday_timestamp returns false for wrong argument format
|
58 |
-
*
|
59 |
-
* @dataProvider bad_argument_formats
|
60 |
-
*/
|
61 |
-
public function test_get_weekday_timestamp_returns_false_if_day_of_week_is_not_int( $args ) {
|
62 |
-
$this->assertFalse( call_user_func_array( [ 'Tribe__Date_Utils', 'get_weekday_timestamp' ], $args ) );
|
63 |
-
}
|
64 |
-
|
65 |
-
public function etc_natural_direction_expected_timestamps() {
|
66 |
-
return [
|
67 |
-
[ 1420416000, [ 1, 1, 1, 2015, 1 ] ], // Mon, first week of Jan 2015
|
68 |
-
[ 1423094400, [ 4, 1, 2, 2015, 1 ] ], // Thursday, first week of Feb 2015
|
69 |
-
[ 1425081600, [ 6, 4, 2, 2015, 1 ] ], // Saturday, 4th week of Feb 2015
|
70 |
-
];
|
71 |
-
}
|
72 |
-
|
73 |
-
/**
|
74 |
-
* get_weekday_timestamp returns right timestamp etc in natural direction
|
75 |
-
*
|
76 |
-
* @dataProvider etc_natural_direction_expected_timestamps
|
77 |
-
*/
|
78 |
-
public function test_get_weekday_timestamp_returns_right_timestamp_in_etc_natural_direction( $expected, $args ) {
|
79 |
-
date_default_timezone_set( 'Etc/GMT+0' );
|
80 |
-
$this->assertEquals( $expected,
|
81 |
-
call_user_func_array( [
|
82 |
-
'Tribe__Date_Utils',
|
83 |
-
'get_weekday_timestamp'
|
84 |
-
],
|
85 |
-
$args ) );
|
86 |
-
}
|
87 |
-
|
88 |
-
/**
|
89 |
-
* get_weekday_timestamp returns right timestamp etc -9 in natural direction
|
90 |
-
*
|
91 |
-
* @dataProvider etc_natural_direction_expected_timestamps
|
92 |
-
*/
|
93 |
-
public function test_get_weekday_timestamp_returns_right_timestamp_etc_minus_9_in_natural_direction( $expected, $args ) {
|
94 |
-
date_default_timezone_set( 'Etc/GMT-9' );
|
95 |
-
$nine_hours = 60 * 60 * 9;
|
96 |
-
$this->assertEquals( $expected - $nine_hours,
|
97 |
-
call_user_func_array( [
|
98 |
-
'Tribe__Date_Utils',
|
99 |
-
'get_weekday_timestamp'
|
100 |
-
],
|
101 |
-
$args ) );
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* get_weekday_timestamp returns right timestamp etc +9 in natural direction
|
106 |
-
*
|
107 |
-
* @dataProvider etc_natural_direction_expected_timestamps
|
108 |
-
*/
|
109 |
-
public function test_get_weekday_timestamp_returns_right_timestamp_etc_plus_9_in_natural_direction( $expected, $args ) {
|
110 |
-
date_default_timezone_set( 'Etc/GMT+9' );
|
111 |
-
$nine_hours = 60 * 60 * 9;
|
112 |
-
$this->assertEquals( $expected + $nine_hours,
|
113 |
-
call_user_func_array( [
|
114 |
-
'Tribe__Date_Utils',
|
115 |
-
'get_weekday_timestamp'
|
116 |
-
],
|
117 |
-
$args ) );
|
118 |
-
}
|
119 |
-
|
120 |
-
public function etc_reverse_direction_expected_timestamps() {
|
121 |
-
return [
|
122 |
-
[ 1422230400, [ 1, 1, 1, 2015, - 1 ] ], // Mon, last week of Jan 2015
|
123 |
-
[ 1424908800, [ 4, 1, 2, 2015, - 1 ] ], // Thursday, last week of Feb 2015
|
124 |
-
[ 1424476800, [ 6, 2, 2, 2015, - 1 ] ], // Saturday, penultimate week of Feb 2015
|
125 |
-
[ 1423872000, [ 6, 3, 2, 2015, - 1 ] ], // Saturday, antepenultimate week of Feb 2015
|
126 |
-
];
|
127 |
-
}
|
128 |
-
|
129 |
-
/**
|
130 |
-
* get_weekday_timestamp returns right timestamp etc in reverse direction
|
131 |
-
*
|
132 |
-
* @dataProvider etc_reverse_direction_expected_timestamps
|
133 |
-
*/
|
134 |
-
public function test_get_weekday_timestamp_returns_right_timestamp_in_etc_reverse_direction( $expected, $args ) {
|
135 |
-
date_default_timezone_set( 'Etc/GMT+0' );
|
136 |
-
$this->assertEquals( $expected,
|
137 |
-
call_user_func_array( [
|
138 |
-
'Tribe__Date_Utils',
|
139 |
-
'get_weekday_timestamp'
|
140 |
-
],
|
141 |
-
$args ) );
|
142 |
-
}
|
143 |
-
|
144 |
-
/**
|
145 |
-
* get_weekday_timestamp returns right timestamp etc -9 in reverse direction
|
146 |
-
*
|
147 |
-
* @dataProvider etc_reverse_direction_expected_timestamps
|
148 |
-
*/
|
149 |
-
public function test_get_weekday_timestamp_returns_right_timestamp_etc_minus_9_in_reverse_direction( $expected, $args ) {
|
150 |
-
date_default_timezone_set( 'Etc/GMT-9' );
|
151 |
-
$nine_hours = 60 * 60 * 9;
|
152 |
-
$this->assertEquals( $expected - $nine_hours,
|
153 |
-
call_user_func_array( [
|
154 |
-
'Tribe__Date_Utils',
|
155 |
-
'get_weekday_timestamp'
|
156 |
-
],
|
157 |
-
$args ) );
|
158 |
-
}
|
159 |
-
|
160 |
-
/**
|
161 |
-
* get_weekday_timestamp returns right timestamp etc +9 in reverse direction
|
162 |
-
*
|
163 |
-
* @dataProvider etc_reverse_direction_expected_timestamps
|
164 |
-
*/
|
165 |
-
public function test_get_weekday_timestamp_returns_right_timestamp_etc_plus_9_in_reverse_direction( $expected, $args ) {
|
166 |
-
date_default_timezone_set( 'Etc/GMT+9' );
|
167 |
-
$nine_hours = 60 * 60 * 9;
|
168 |
-
$this->assertEquals( $expected + $nine_hours,
|
169 |
-
call_user_func_array( [
|
170 |
-
'Tribe__Date_Utils',
|
171 |
-
'get_weekday_timestamp'
|
172 |
-
],
|
173 |
-
$args ) );
|
174 |
-
}
|
175 |
-
|
176 |
-
/**
|
177 |
-
* unescape_date_format will return input if not a string
|
178 |
-
*/
|
179 |
-
public function test_unescape_date_format_will_return_input_if_not_a_string() {
|
180 |
-
$bad_input = array( 23 );
|
181 |
-
$this->assertEquals( $bad_input, Date_Utils::unescape_date_format( $bad_input ) );
|
182 |
-
}
|
183 |
-
|
184 |
-
public function date_formats_not_to_escape() {
|
185 |
-
return [
|
186 |
-
[ 'tribe', 'tribe' ],
|
187 |
-
[ 'j \d\e F', 'j \d\e F' ],
|
188 |
-
[ 'F, \e\l j' , 'F, \e\l j' ],
|
189 |
-
[ '\hH', '\hH' ],
|
190 |
-
[ 'i\m, s\s', 'i\m, s\s' ],
|
191 |
-
[ '\T\Z: T ', '\T\Z: T' ],
|
192 |
-
];
|
193 |
-
}
|
194 |
-
|
195 |
-
/**
|
196 |
-
* unescape_date_format will return same string when nothing to escape
|
197 |
-
*
|
198 |
-
* @dataProvider date_formats_not_to_escape
|
199 |
-
*/
|
200 |
-
public function test_unescape_date_format_will_return_same_string_when_nothing_to_escape( $in ) {
|
201 |
-
$out = Date_Utils::unescape_date_format( $in );
|
202 |
-
$this->assertEquals( $in, $out );
|
203 |
-
}
|
204 |
-
|
205 |
-
public function date_formats_to_escape() {
|
206 |
-
return [
|
207 |
-
[ 'j \\d\\e F', 'j \d\e F' ],
|
208 |
-
[ 'F, \\e\\l j' , 'F, \e\l j' ],
|
209 |
-
[ '\\hH', '\hH' ],
|
210 |
-
[ 'i\\m, s\\s', 'i\m, s\s' ],
|
211 |
-
[ '\\T\\Z: T', '\T\Z: T' ],
|
212 |
-
[ 'j \d\\e F', 'j \d\e F' ],
|
213 |
-
[ 'F, \e\\l j' , 'F, \e\l j' ],
|
214 |
-
[ 'i\m, s\\s', 'i\m, s\s' ],
|
215 |
-
[ '\T\\Z: T' , '\T\Z: T' ],
|
216 |
-
];
|
217 |
-
}
|
218 |
-
|
219 |
-
/**
|
220 |
-
* unescape_date_format will return escaped date format
|
221 |
-
*
|
222 |
-
* @dataProvider date_formats_to_escape
|
223 |
-
*/
|
224 |
-
public function test_unescape_date_format_will_return_escaped_date_format( $in, $expected_out ) {
|
225 |
-
$out = Date_Utils::unescape_date_format( $in );
|
226 |
-
$this->assertEquals( $expected_out, $out );
|
227 |
-
}
|
228 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
common/tribe-autoload.php
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
<?php
|
2 |
-
$
|
3 |
-
|
|
|
4 |
|
5 |
$autoloader = Tribe__Autoloader::instance();
|
6 |
-
$autoloader->register_prefix('Tribe__'
|
7 |
$autoloader->register_autoloader();
|
1 |
<?php
|
2 |
+
$common = dirname( __FILE__ ) . '/src';
|
3 |
+
|
4 |
+
require_once $common . '/Tribe/Autoloader.php';
|
5 |
|
6 |
$autoloader = Tribe__Autoloader::instance();
|
7 |
+
$autoloader->register_prefix( 'Tribe__', $common . '/Tribe' );
|
8 |
$autoloader->register_autoloader();
|
common/tribe-common.php
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?php
|
2 |
/*
|
3 |
Description: An event settings framework for managing shared options
|
4 |
-
Version: 4.
|
5 |
Author: Modern Tribe, Inc.
|
6 |
Author URI: http://m.tri.be/1x
|
7 |
Text Domain: tribe-common
|
1 |
<?php
|
2 |
/*
|
3 |
Description: An event settings framework for managing shared options
|
4 |
+
Version: 4.1
|
5 |
Author: Modern Tribe, Inc.
|
6 |
Author URI: http://m.tri.be/1x
|
7 |
Text Domain: tribe-common
|
common/vendor/jquery/images/ui-bg_flat_0_aaaaaa_40x100.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-bg_flat_75_ffffff_40x100.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-bg_glass_55_fbf9ee_1x400.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-bg_glass_65_ffffff_1x400.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-bg_glass_75_dadada_1x400.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-bg_glass_75_e6e6e6_1x400.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-bg_glass_95_fef1ec_1x400.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-icons_222222_256x240.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-icons_2e83ff_256x240.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-icons_454545_256x240.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-icons_888888_256x240.png
CHANGED
File without changes
|
common/vendor/jquery/images/ui-icons_cd0a0a_256x240.png
CHANGED
File without changes
|
common/vendor/jquery/ui.theme.css
CHANGED
File without changes
|
event-tickets.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
/*
|
3 |
Plugin Name: Event Tickets
|
4 |
Description: Event Tickets allows you to sell tickets to events
|
5 |
-
Version: 4.
|
6 |
Author: Modern Tribe, Inc.
|
7 |
Author URI: http://m.tri.be/28
|
8 |
License: GPLv2 or later
|
2 |
/*
|
3 |
Plugin Name: Event Tickets
|
4 |
Description: Event Tickets allows you to sell tickets to events
|
5 |
+
Version: 4.1
|
6 |
Author: Modern Tribe, Inc.
|
7 |
Author URI: http://m.tri.be/28
|
8 |
License: GPLv2 or later
|
lang/event-tickets-es_ES.mo
CHANGED
Binary file
|
lang/event-tickets-es_ES.po
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
# This file is distributed under the same license as the Event Tickets package.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
-
"PO-Revision-Date:
|
6 |
"MIME-Version: 1.0\n"
|
7 |
"Content-Type: text/plain; charset=UTF-8\n"
|
8 |
"Content-Transfer-Encoding: 8bit\n"
|
@@ -760,7 +760,7 @@ msgstr "Maldivas"
|
|
760 |
|
761 |
#: src/Tribe/RSVP.php:349
|
762 |
msgid "Your tickets from %s"
|
763 |
-
msgstr ""
|
764 |
|
765 |
#: common/src/Tribe/View_Helpers.php:179
|
766 |
msgid "Mali"
|
@@ -1193,7 +1193,7 @@ msgstr "Senegal"
|
|
1193 |
|
1194 |
#: src/admin-views/rsvp-metabox-advanced.php:6
|
1195 |
msgid "(Total available # of this ticket type. Once they're gone, ticket type is sold out.)"
|
1196 |
-
msgstr ""
|
1197 |
|
1198 |
#: common/src/Tribe/View_Helpers.php:235
|
1199 |
msgid "Serbia"
|
@@ -1201,7 +1201,7 @@ msgstr "Serbia"
|
|
1201 |
|
1202 |
#: src/admin-views/rsvp-metabox-advanced.php:16
|
1203 |
msgid "Selling tickets for recurring events"
|
1204 |
-
msgstr ""
|
1205 |
|
1206 |
#: common/src/Tribe/View_Helpers.php:236
|
1207 |
msgid "Seychelles"
|
2 |
# This file is distributed under the same license as the Event Tickets package.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
+
"PO-Revision-Date: 2016-03-11 22:36:31+0000\n"
|
6 |
"MIME-Version: 1.0\n"
|
7 |
"Content-Type: text/plain; charset=UTF-8\n"
|
8 |
"Content-Transfer-Encoding: 8bit\n"
|
760 |
|
761 |
#: src/Tribe/RSVP.php:349
|
762 |
msgid "Your tickets from %s"
|
763 |
+
msgstr "Tus tickets de parte de %s"
|
764 |
|
765 |
#: common/src/Tribe/View_Helpers.php:179
|
766 |
msgid "Mali"
|
1193 |
|
1194 |
#: src/admin-views/rsvp-metabox-advanced.php:6
|
1195 |
msgid "(Total available # of this ticket type. Once they're gone, ticket type is sold out.)"
|
1196 |
+
msgstr "(# Total disponible para este categoría de boleto. Una vez vendidos, esta categoría está agotada)"
|
1197 |
|
1198 |
#: common/src/Tribe/View_Helpers.php:235
|
1199 |
msgid "Serbia"
|
1201 |
|
1202 |
#: src/admin-views/rsvp-metabox-advanced.php:16
|
1203 |
msgid "Selling tickets for recurring events"
|
1204 |
+
msgstr "Vender tickets para eventos recurrentes"
|
1205 |
|
1206 |
#: common/src/Tribe/View_Helpers.php:236
|
1207 |
msgid "Seychelles"
|
readme.txt
CHANGED
@@ -3,8 +3,8 @@
|
|
3 |
Contributors: ModernTribe, borkweb, zbtirrell, barry.hughes, bordoni, brianjessee, brook-tribe, faction23, geoffgraham, ggwicz, jazbek, jbrinley, joshlimecuda, leahkoerper, lucatume, mastromktg, neillmcshea, nicosantos, peterchester, reid.peifer, roblagatta, shane.pearlman, thatdudebutch
|
4 |
Tags: events, add-on, ticket sales, tickets, calendar, community, registration, api, dates, date, posts, workshop, conference, meeting, seminar, concert, summit, The Events Calendar, Events Calendar PRO, ticket integration, event ticketing, RSVP, Event Tickets, Event Tickets Plus
|
5 |
Requires at least: 3.9
|
6 |
-
Tested up to: 4.4
|
7 |
-
Stable tag: 4.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
@@ -179,8 +179,15 @@ Our Premium Plugins:
|
|
179 |
|
180 |
== Changelog ==
|
181 |
|
182 |
-
= [4.
|
183 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
* Fix - Prevent notices to enqueue method when moving form hooks
|
185 |
|
186 |
= [4.0.5] 2016-02-17 =
|
@@ -189,6 +196,9 @@ Our Premium Plugins:
|
|
189 |
|
190 |
= [4.0.4] 2015-12-23 =
|
191 |
|
|
|
|
|
|
|
192 |
* Fix - Resolved issue with stock calculations on the Attendees report
|
193 |
|
194 |
= [4.0.3] 2015-12-22 =
|
3 |
Contributors: ModernTribe, borkweb, zbtirrell, barry.hughes, bordoni, brianjessee, brook-tribe, faction23, geoffgraham, ggwicz, jazbek, jbrinley, joshlimecuda, leahkoerper, lucatume, mastromktg, neillmcshea, nicosantos, peterchester, reid.peifer, roblagatta, shane.pearlman, thatdudebutch
|
4 |
Tags: events, add-on, ticket sales, tickets, calendar, community, registration, api, dates, date, posts, workshop, conference, meeting, seminar, concert, summit, The Events Calendar, Events Calendar PRO, ticket integration, event ticketing, RSVP, Event Tickets, Event Tickets Plus
|
5 |
Requires at least: 3.9
|
6 |
+
Tested up to: 4.4.2
|
7 |
+
Stable tag: 4.1
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
179 |
|
180 |
== Changelog ==
|
181 |
|
182 |
+
= [4.1] 2016-03-15 =
|
183 |
|
184 |
+
* Feature - Implemented global stock per event allowing multiple tickets to pull from the same pool of available tickets on an event (Heck yeah to all those who voted on this feature!)
|
185 |
+
* Feature - Added filters for RSVP ticket generation: event_tickets_rsvp_tickets_created, event_tickets_rsvp_tickets_generated_for_product, and event_tickets_rsvp_tickets_generated (props to 75ninteen for this pull request!)
|
186 |
+
* Tweak - Conditionally show attendees link on Event listing in the WordPress administration
|
187 |
+
* Tweak - Obfuscated license keys Events > Help > System Information
|
188 |
+
* Tweak - Allowed the "same slug" notice to be dismissed and fix some text in that message
|
189 |
+
* Fix - Fixed issue where some characters were not escaped appropriately for month and year formats
|
190 |
+
* Fix - Resolved issue where the RSVP confirmation error message displayed when it shouldn't
|
191 |
* Fix - Prevent notices to enqueue method when moving form hooks
|
192 |
|
193 |
= [4.0.5] 2016-02-17 =
|
196 |
|
197 |
= [4.0.4] 2015-12-23 =
|
198 |
|
199 |
+
* Feature - Add support for global ticket stock so multiple tickets can optionally reduce from a single ticket total for a given event
|
200 |
+
* Tweak - Ignore alpha/beta/rc suffixes on version numbers when checking template versions
|
201 |
+
* Tweak - Add HTML id attribute to ticket area on the single-event page so plugin/theme authors can use anchor tags to jump to that section of the page
|
202 |
* Fix - Resolved issue with stock calculations on the Attendees report
|
203 |
|
204 |
= [4.0.3] 2015-12-22 =
|
src/Tribe/Attendees_Table.php
CHANGED
@@ -75,8 +75,6 @@ class Tribe__Tickets__Attendees_Table extends WP_List_Table {
|
|
75 |
'cb' => '<input type="checkbox" />',
|
76 |
'order_id' => esc_html__( 'Order #', 'event-tickets' ),
|
77 |
'order_status' => esc_html__( 'Order Status', 'event-tickets' ),
|
78 |
-
'purchaser_name' => esc_html__( 'Purchaser name', 'event-tickets' ),
|
79 |
-
'purchaser_email' => esc_html__( 'Purchaser email', 'event-tickets' ),
|
80 |
'ticket' => esc_html__( 'Ticket type', 'event-tickets' ),
|
81 |
'attendee_id' => esc_html__( 'Ticket #', 'event-tickets' ),
|
82 |
'security' => esc_html__( 'Security Code', 'event-tickets' ),
|
@@ -86,7 +84,6 @@ class Tribe__Tickets__Attendees_Table extends WP_List_Table {
|
|
86 |
return $columns;
|
87 |
}
|
88 |
|
89 |
-
|
90 |
/**
|
91 |
* Handler for the columns that don't have a specific column_{name} handler function.
|
92 |
*
|
@@ -147,12 +144,9 @@ class Tribe__Tickets__Attendees_Table extends WP_List_Table {
|
|
147 |
|
148 |
// If the warning flag is set, add the appropriate icon
|
149 |
if ( $warning ) {
|
150 |
-
$
|
151 |
-
|
152 |
-
$icon = sprintf( "<span class='warning'><img src='%s'/></span> ", $resources_url . '/images/warning.png' );
|
153 |
}
|
154 |
|
155 |
-
|
156 |
// Look for an order_status_label, fall back on the actual order_status string @todo remove fallback in 3.4.3
|
157 |
if ( empty( $item['order_status'] ) ) {
|
158 |
$item['order_status'] = '';
|
@@ -162,6 +156,41 @@ class Tribe__Tickets__Attendees_Table extends WP_List_Table {
|
|
162 |
return $icon . $label;
|
163 |
}
|
164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
/**
|
166 |
* Handler for the check in column
|
167 |
*
|
@@ -170,6 +199,42 @@ class Tribe__Tickets__Attendees_Table extends WP_List_Table {
|
|
170 |
* @return string
|
171 |
*/
|
172 |
public function column_check_in( $item ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
$checkin = sprintf( '<a href="#" data-attendee-id="%d" data-provider="%s" class="button-secondary tickets_checkin">%s</a>', esc_attr( $item['attendee_id'] ), esc_attr( $item['provider'] ), esc_html__( 'Check in', 'event-tickets' ) );
|
174 |
$uncheckin = sprintf( '<span class="delete"><a href="#" data-attendee-id="%d" data-provider="%s" class="tickets_uncheckin">%s</a></span>', esc_attr( $item['attendee_id'] ), esc_attr( $item['provider'] ), esc_html__( 'Undo Check in', 'event-tickets' ) );
|
175 |
|
@@ -193,8 +258,14 @@ class Tribe__Tickets__Attendees_Table extends WP_List_Table {
|
|
193 |
echo '<tr class="' . sanitize_html_class( $row_class ) . esc_attr( $checked ) . '">';
|
194 |
$this->single_row_columns( $item );
|
195 |
echo '</tr>';
|
196 |
-
}
|
197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
|
199 |
/**
|
200 |
* Extra controls to be displayed between bulk actions and pagination.
|
@@ -259,7 +330,6 @@ class Tribe__Tickets__Attendees_Table extends WP_List_Table {
|
|
259 |
return (array) apply_filters( 'tribe_events_tickets_attendees_table_bulk_actions', $actions );
|
260 |
}
|
261 |
|
262 |
-
|
263 |
/**
|
264 |
* Handler for the different bulk actions
|
265 |
*/
|
75 |
'cb' => '<input type="checkbox" />',
|
76 |
'order_id' => esc_html__( 'Order #', 'event-tickets' ),
|
77 |
'order_status' => esc_html__( 'Order Status', 'event-tickets' ),
|
|
|
|
|
78 |
'ticket' => esc_html__( 'Ticket type', 'event-tickets' ),
|
79 |
'attendee_id' => esc_html__( 'Ticket #', 'event-tickets' ),
|
80 |
'security' => esc_html__( 'Security Code', 'event-tickets' ),
|
84 |
return $columns;
|
85 |
}
|
86 |
|
|
|
87 |
/**
|
88 |
* Handler for the columns that don't have a specific column_{name} handler function.
|
89 |
*
|
144 |
|
145 |
// If the warning flag is set, add the appropriate icon
|
146 |
if ( $warning ) {
|
147 |
+
$icon = sprintf( "<span class='warning'><img src='%s'/></span> ", esc_url( Tribe__Tickets__Main::instance()->plugin_url . 'src/resources/images/warning.png' ) );
|
|
|
|
|
148 |
}
|
149 |
|
|
|
150 |
// Look for an order_status_label, fall back on the actual order_status string @todo remove fallback in 3.4.3
|
151 |
if ( empty( $item['order_status'] ) ) {
|
152 |
$item['order_status'] = '';
|
156 |
return $icon . $label;
|
157 |
}
|
158 |
|
159 |
+
/**
|
160 |
+
* Handler for the ticket column
|
161 |
+
*
|
162 |
+
* @since 4.1
|
163 |
+
*
|
164 |
+
* @param array $item Item whose ticket data should be output
|
165 |
+
*
|
166 |
+
* @return string
|
167 |
+
*/
|
168 |
+
public function column_ticket( $item ) {
|
169 |
+
ob_start();
|
170 |
+
|
171 |
+
$acquired_by_label = 'Tribe__Tickets__RSVP' === $item['provider'] ? __( 'Reserved by:', 'event-tickets' ) : __( 'Purchased by:', 'event-tickets' );
|
172 |
+
|
173 |
+
?>
|
174 |
+
<div class="event-tickets-ticket-name">
|
175 |
+
<?php echo esc_html( $item['ticket'] ); ?>
|
176 |
+
</div>
|
177 |
+
<div class="event-tickets-ticket-purchaser">
|
178 |
+
<?php echo esc_html( $acquired_by_label ); ?> <?php echo esc_html( $item['purchaser_name'] ); ?> (<?php echo esc_html( $item['purchaser_email'] ); ?>)
|
179 |
+
</div>
|
180 |
+
<?php
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Hook to allow for the insertion of additional content in the ticket table cell
|
184 |
+
*
|
185 |
+
* @var $item Attendee row item
|
186 |
+
*/
|
187 |
+
do_action( 'event_tickets_attendees_table_ticket_column', $item );
|
188 |
+
|
189 |
+
$output = ob_get_clean();
|
190 |
+
|
191 |
+
return $output;
|
192 |
+
}
|
193 |
+
|
194 |
/**
|
195 |
* Handler for the check in column
|
196 |
*
|
199 |
* @return string
|
200 |
*/
|
201 |
public function column_check_in( $item ) {
|
202 |
+
$default_checkin_stati = array();
|
203 |
+
$provider = $item['provider_slug'];
|
204 |
+
$order_id = $item['order_id'];
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Filters the order stati that will allow for a ticket to be checked in for all commerce providers.
|
208 |
+
*
|
209 |
+
* @since 4.1
|
210 |
+
*
|
211 |
+
* @param array $default_checkin_stati An array of default order stati that will make a ticket eligible for check-in.
|
212 |
+
* @param string $provider The ticket provider slug.
|
213 |
+
* @param int $order_id The order post ID.
|
214 |
+
*/
|
215 |
+
$check_in_stati = apply_filters( 'event_tickets_attendees_checkin_stati', $default_checkin_stati, $provider, $order_id );
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Filters the order stati that will allow for a ticket to be checked in for a specific commerce provider.
|
219 |
+
*
|
220 |
+
* @since 4.1
|
221 |
+
*
|
222 |
+
* @param array $default_checkin_stati An array of default order stati that will make a ticket eligible for check-in.
|
223 |
+
* @param int $order_id The order post ID.
|
224 |
+
*/
|
225 |
+
$check_in_stati = apply_filters( "event_tickets_attendees_{$provider}_checkin_stati", $check_in_stati, $order_id );
|
226 |
+
|
227 |
+
if (
|
228 |
+
! empty( $item['order_status'] )
|
229 |
+
&& ! empty( $item['order_id_link_src'] )
|
230 |
+
&& is_array( $check_in_stati )
|
231 |
+
&& ! in_array( $item['order_status'], $check_in_stati )
|
232 |
+
) {
|
233 |
+
$button_template = '<a href="%s" class="button-secondary tickets-checkin">%s</a>';
|
234 |
+
|
235 |
+
return sprintf( $button_template, $item['order_id_link_src'], __( 'View order', 'event-tickets' ) );
|
236 |
+
}
|
237 |
+
|
238 |
$checkin = sprintf( '<a href="#" data-attendee-id="%d" data-provider="%s" class="button-secondary tickets_checkin">%s</a>', esc_attr( $item['attendee_id'] ), esc_attr( $item['provider'] ), esc_html__( 'Check in', 'event-tickets' ) );
|
239 |
$uncheckin = sprintf( '<span class="delete"><a href="#" data-attendee-id="%d" data-provider="%s" class="tickets_uncheckin">%s</a></span>', esc_attr( $item['attendee_id'] ), esc_attr( $item['provider'] ), esc_html__( 'Undo Check in', 'event-tickets' ) );
|
240 |
|
258 |
echo '<tr class="' . sanitize_html_class( $row_class ) . esc_attr( $checked ) . '">';
|
259 |
$this->single_row_columns( $item );
|
260 |
echo '</tr>';
|
|
|
261 |
|
262 |
+
/**
|
263 |
+
* Hook to allow for the insertion of data after an attendee table row
|
264 |
+
*
|
265 |
+
* @var $item Attendee data
|
266 |
+
*/
|
267 |
+
do_action( 'event_tickets_attendees_table_after_row', $item );
|
268 |
+
}
|
269 |
|
270 |
/**
|
271 |
* Extra controls to be displayed between bulk actions and pagination.
|
330 |
return (array) apply_filters( 'tribe_events_tickets_attendees_table_bulk_actions', $actions );
|
331 |
}
|
332 |
|
|
|
333 |
/**
|
334 |
* Handler for the different bulk actions
|
335 |
*/
|
src/Tribe/Global_Stock.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Tribe__Tickets__Global_Stock {
|
3 |
+
/**
|
4 |
+
* Post meta key used to store the global stock flag.
|
5 |
+
*/
|
6 |
+
const GLOBAL_STOCK_ENABLED = '_tribe_ticket_use_global_stock';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Post meta key used to store the actual global stock level.
|
10 |
+
*/
|
11 |
+
const GLOBAL_STOCK_LEVEL = '_tribe_ticket_global_stock_level';
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Flag used to indicate that a ticket will use the global stock.
|
15 |
+
*/
|
16 |
+
const GLOBAL_STOCK_MODE = 'global';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Flag used to indicate that a ticket will use the global stock,
|
20 |
+
* but that a cap has been placed on the total number of sales for
|
21 |
+
* this ticket type.
|
22 |
+
*/
|
23 |
+
const CAPPED_STOCK_MODE = 'capped';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Flag used to indicate that, if global stock is in effect for
|
27 |
+
* an event, the specific ticket this flag is applied to will
|
28 |
+
* maintain it's own inventory rather than draw from the global
|
29 |
+
* pool.
|
30 |
+
*/
|
31 |
+
const OWN_STOCK_MODE = 'own';
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @var int $post_id
|
35 |
+
*/
|
36 |
+
protected $post_id;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @param int $post_id
|
40 |
+
*/
|
41 |
+
public function __construct( $post_id ) {
|
42 |
+
$this->post_id = absint( $post_id );
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Enables global stock control for the current post.
|
47 |
+
*
|
48 |
+
* As a convenience, false can be passed to this method to disable rather
|
49 |
+
* than enable global stock.
|
50 |
+
*
|
51 |
+
* @param bool $yes
|
52 |
+
*/
|
53 |
+
public function enable( $yes = true ) {
|
54 |
+
update_post_meta( $this->post_id, self::GLOBAL_STOCK_ENABLED, (bool) $yes );
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Disables global stock control for the current post.
|
59 |
+
*
|
60 |
+
* As a convenience, false can be passed to this method to enable rather
|
61 |
+
* than disable global stock.
|
62 |
+
*
|
63 |
+
* @var bool $yes
|
64 |
+
*/
|
65 |
+
public function disable( $yes = true ) {
|
66 |
+
update_post_meta( $this->post_id, self::GLOBAL_STOCK_ENABLED, ! (bool) $yes );
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Indicates if global stock is enabled for this post.
|
71 |
+
*
|
72 |
+
* @return bool
|
73 |
+
*/
|
74 |
+
public function is_enabled() {
|
75 |
+
return (bool) get_post_meta( $this->post_id, self::GLOBAL_STOCK_ENABLED, true );
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Sets the global stock level for the current post.
|
80 |
+
*
|
81 |
+
* @param int $quantity
|
82 |
+
*/
|
83 |
+
public function set_stock_level( $quantity ) {
|
84 |
+
update_post_meta( $this->post_id, self::GLOBAL_STOCK_LEVEL, (int) $quantity );
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Fires when the global stock level is set/changed.
|
88 |
+
*
|
89 |
+
* @param int $post_id
|
90 |
+
* @param int $quantity
|
91 |
+
*/
|
92 |
+
do_action( 'tribe_tickets_global_stock_level_changed', $this->post_id, $quantity );
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Returns the post's global stock.
|
97 |
+
*
|
98 |
+
* @return int
|
99 |
+
*/
|
100 |
+
public function get_stock_level() {
|
101 |
+
return (int) get_post_meta( $this->post_id, self::GLOBAL_STOCK_LEVEL, true );
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Returns a count of the number of global ticket sales for this event.
|
106 |
+
*
|
107 |
+
* @return int
|
108 |
+
*/
|
109 |
+
public function tickets_sold() {
|
110 |
+
$sales = 0;
|
111 |
+
|
112 |
+
foreach ( Tribe__Tickets__Tickets::get_all_event_tickets( $this->post_id ) as $ticket ) {
|
113 |
+
/**
|
114 |
+
* @var Tribe__Tickets__Ticket_Object $ticket
|
115 |
+
*/
|
116 |
+
switch ( $ticket->global_stock_mode() ) {
|
117 |
+
case self::CAPPED_STOCK_MODE:
|
118 |
+
case self::GLOBAL_STOCK_MODE:
|
119 |
+
$sales += (int) $ticket->qty_sold();
|
120 |
+
break;
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
return $sales;
|
125 |
+
}
|
126 |
+
}
|
src/Tribe/Google_Event_Data.php
CHANGED
File without changes
|
src/Tribe/Main.php
CHANGED
@@ -9,12 +9,12 @@ class Tribe__Tickets__Main {
|
|
9 |
/**
|
10 |
* Current version of this plugin
|
11 |
*/
|
12 |
-
const VERSION = '4.
|
13 |
|
14 |
/**
|
15 |
* Min required The Events Calendar version
|
16 |
*/
|
17 |
-
const MIN_TEC_VERSION = '
|
18 |
|
19 |
/**
|
20 |
* Name of the provider
|
@@ -110,7 +110,11 @@ class Tribe__Tickets__Main {
|
|
110 |
load_plugin_textdomain( 'event-tickets', false, $this->plugin_dir . 'lang/' );
|
111 |
|
112 |
$this->hooks();
|
|
|
113 |
$this->has_initialized = true;
|
|
|
|
|
|
|
114 |
}
|
115 |
|
116 |
/**
|
@@ -223,7 +227,20 @@ class Tribe__Tickets__Main {
|
|
223 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_support_content' ) );
|
224 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_featured_content' ) );
|
225 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_extra_content' ) );
|
|
|
226 |
add_action( 'plugins_loaded', array( 'Tribe__Support', 'getInstance' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
}
|
228 |
|
229 |
/**
|
@@ -295,13 +312,27 @@ class Tribe__Tickets__Main {
|
|
295 |
}
|
296 |
}
|
297 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
/**
|
299 |
* Hooked to the init action
|
300 |
*/
|
301 |
public function init() {
|
302 |
-
// set up the RSVP object
|
303 |
-
$this->rsvp();
|
304 |
-
|
305 |
// Provide continued support for legacy ticketing modules
|
306 |
$this->legacy_provider_support = new Tribe__Tickets__Legacy_Provider_Support;
|
307 |
|
@@ -312,13 +343,7 @@ class Tribe__Tickets__Main {
|
|
312 |
* rsvp ticket object accessor
|
313 |
*/
|
314 |
public function rsvp() {
|
315 |
-
|
316 |
-
|
317 |
-
if ( ! $rsvp ) {
|
318 |
-
$rsvp = Tribe__Tickets__RSVP::get_instance();
|
319 |
-
}
|
320 |
-
|
321 |
-
return $rsvp;
|
322 |
}
|
323 |
|
324 |
/**
|
9 |
/**
|
10 |
* Current version of this plugin
|
11 |
*/
|
12 |
+
const VERSION = '4.1';
|
13 |
|
14 |
/**
|
15 |
* Min required The Events Calendar version
|
16 |
*/
|
17 |
+
const MIN_TEC_VERSION = '3.12.4';
|
18 |
|
19 |
/**
|
20 |
* Name of the provider
|
110 |
load_plugin_textdomain( 'event-tickets', false, $this->plugin_dir . 'lang/' );
|
111 |
|
112 |
$this->hooks();
|
113 |
+
|
114 |
$this->has_initialized = true;
|
115 |
+
|
116 |
+
// set up the RSVP object
|
117 |
+
$this->rsvp();
|
118 |
}
|
119 |
|
120 |
/**
|
227 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_support_content' ) );
|
228 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_featured_content' ) );
|
229 |
add_action( 'tribe_help_pre_get_sections', array( $this, 'add_help_section_extra_content' ) );
|
230 |
+
add_filter( 'tribe_support_registered_template_systems', array( $this, 'add_template_updates_check' ) );
|
231 |
add_action( 'plugins_loaded', array( 'Tribe__Support', 'getInstance' ) );
|
232 |
+
add_action( 'tribe_events_single_event_after_the_meta', array( $this, 'add_linking_archor' ), 5 );
|
233 |
+
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Add an Anchor for users to be able to link to
|
238 |
+
* The height is to make sure it links on all browsers
|
239 |
+
*
|
240 |
+
* @return void
|
241 |
+
*/
|
242 |
+
public function add_linking_archor() {
|
243 |
+
echo '<div id="buy-tickets" style="height: 1px;"></div>';
|
244 |
}
|
245 |
|
246 |
/**
|
312 |
}
|
313 |
}
|
314 |
|
315 |
+
/**
|
316 |
+
* Register Event Tickets with the template update checker.
|
317 |
+
*
|
318 |
+
* @param array $plugins
|
319 |
+
*
|
320 |
+
* @return array
|
321 |
+
*/
|
322 |
+
public function add_template_updates_check( $plugins ) {
|
323 |
+
$plugins[ __( 'Event Tickets', 'event-tickets' ) ] = array(
|
324 |
+
self::VERSION,
|
325 |
+
$this->plugin_path . 'src/views/tickets',
|
326 |
+
trailingslashit( get_stylesheet_directory() ) . 'tribe-events/tickets'
|
327 |
+
);
|
328 |
+
|
329 |
+
return $plugins;
|
330 |
+
}
|
331 |
+
|
332 |
/**
|
333 |
* Hooked to the init action
|
334 |
*/
|
335 |
public function init() {
|
|
|
|
|
|
|
336 |
// Provide continued support for legacy ticketing modules
|
337 |
$this->legacy_provider_support = new Tribe__Tickets__Legacy_Provider_Support;
|
338 |
|
343 |
* rsvp ticket object accessor
|
344 |
*/
|
345 |
public function rsvp() {
|
346 |
+
return Tribe__Tickets__RSVP::get_instance();
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
}
|
348 |
|
349 |
/**
|
src/Tribe/Metabox.php
CHANGED
@@ -81,7 +81,11 @@ class Tribe__Tickets__Metabox {
|
|
81 |
'title' => esc_html__( 'Ticket header image', 'event-tickets' ),
|
82 |
'button' => esc_html__( 'Set as ticket header', 'event-tickets' ),
|
83 |
);
|
|
|
84 |
wp_localize_script( 'event-tickets', 'HeaderImageData', $upload_header_data );
|
|
|
|
|
|
|
85 |
|
86 |
|
87 |
$nonces = array(
|
81 |
'title' => esc_html__( 'Ticket header image', 'event-tickets' ),
|
82 |
'button' => esc_html__( 'Set as ticket header', 'event-tickets' ),
|
83 |
);
|
84 |
+
|
85 |
wp_localize_script( 'event-tickets', 'HeaderImageData', $upload_header_data );
|
86 |
+
wp_localize_script( 'event-tickets', 'tribe_global_stock_admin_ui', array(
|
87 |
+
'nav_away_msg' => __( 'It looks like you have modified your global stock settings but have not saved or updated the post.', 'event-tickets' ),
|
88 |
+
) );
|
89 |
|
90 |
|
91 |
$nonces = array(
|
src/Tribe/RSVP.php
CHANGED
@@ -60,6 +60,13 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
60 |
*/
|
61 |
public $security_code = '_tribe_rsvp_security_code';
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
/**
|
64 |
* Meta key that holds the full name of the tickets RSVP "buyer"
|
65 |
*
|
@@ -103,8 +110,8 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
103 |
* @return Tribe__Tickets__RSVP
|
104 |
*/
|
105 |
public static function get_instance() {
|
106 |
-
if ( !
|
107 |
-
self::$instance = new self
|
108 |
}
|
109 |
|
110 |
return self::$instance;
|
@@ -123,8 +130,7 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
123 |
|
124 |
parent::__construct();
|
125 |
|
126 |
-
$this
|
127 |
-
$this->hooks();
|
128 |
}
|
129 |
|
130 |
/**
|
@@ -242,7 +248,6 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
242 |
* Generate and store all the attendees information for a new order.
|
243 |
*/
|
244 |
public function generate_tickets( ) {
|
245 |
-
|
246 |
if ( empty( $_POST['tickets_process'] ) || empty( $_POST['attendee'] ) || empty( $_POST['product_id'] ) ) {
|
247 |
return;
|
248 |
}
|
@@ -254,6 +259,7 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
254 |
$attendee_email = empty( $_POST['attendee']['email'] ) ? null : sanitize_email( $_POST['attendee']['email'] );
|
255 |
$attendee_email = is_email( $attendee_email ) ? $attendee_email : null;
|
256 |
$attendee_full_name = empty( $_POST['attendee']['full_name'] ) ? null : sanitize_text_field( $_POST['attendee']['full_name'] );
|
|
|
257 |
|
258 |
if ( ! $attendee_email || ! $attendee_full_name ) {
|
259 |
$url = get_permalink( $event_id );
|
@@ -264,6 +270,7 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
264 |
|
265 |
// Iterate over each product
|
266 |
foreach ( (array) $_POST['product_id'] as $product_id ) {
|
|
|
267 |
|
268 |
// Get the event this tickets is for
|
269 |
$event_id = get_post_meta( $product_id, $this->event_key, true );
|
@@ -310,10 +317,40 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
310 |
update_post_meta( $attendee_id, self::ATTENDEE_EVENT_KEY, $event_id );
|
311 |
update_post_meta( $attendee_id, $this->security_code, $this->generate_security_code( $attendee_id ) );
|
312 |
update_post_meta( $attendee_id, $this->order_key, $order_id );
|
|
|
313 |
update_post_meta( $attendee_id, $this->full_name, $attendee_full_name );
|
314 |
update_post_meta( $attendee_id, $this->email, $attendee_email );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
315 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
316 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
317 |
if ( $has_tickets ) {
|
318 |
$this->send_tickets_email( $order_id ) ;
|
319 |
}
|
@@ -361,14 +398,18 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
361 |
) );
|
362 |
|
363 |
foreach ( $query->posts as $post ) {
|
|
|
|
|
364 |
$attendees[] = array(
|
365 |
'event_id' => get_post_meta( $post->ID, self::ATTENDEE_EVENT_KEY, true ),
|
366 |
-
'
|
|
|
367 |
'holder_name' => get_post_meta( $post->ID, $this->full_name, true ),
|
368 |
'holder_email' => get_post_meta( $post->ID, $this->email, true ),
|
369 |
'order_id' => $order_id,
|
370 |
'ticket_id' => $post->ID,
|
371 |
'security_code' => get_post_meta( $post->ID, $this->security_code, true ),
|
|
|
372 |
);
|
373 |
}
|
374 |
|
@@ -397,8 +438,12 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
397 |
* @return bool
|
398 |
*/
|
399 |
public function save_ticket( $event_id, $ticket, $raw_data = array() ) {
|
|
|
|
|
400 |
|
401 |
if ( empty( $ticket->ID ) ) {
|
|
|
|
|
402 |
/* Create main product post */
|
403 |
$args = array(
|
404 |
'post_status' => 'publish',
|
@@ -450,6 +495,26 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
450 |
delete_post_meta( $ticket->ID, '_ticket_end_date' );
|
451 |
}
|
452 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
453 |
return true;
|
454 |
}
|
455 |
|
@@ -620,14 +685,14 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
620 |
return false;
|
621 |
}
|
622 |
|
623 |
-
$
|
624 |
|
625 |
-
if ( ! $
|
626 |
return false;
|
627 |
}
|
628 |
|
629 |
-
if ( in_array( get_post_type( $
|
630 |
-
return get_post( $
|
631 |
}
|
632 |
|
633 |
return false;
|
@@ -641,6 +706,7 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
641 |
* order_status
|
642 |
* purchaser_name
|
643 |
* purchaser_email
|
|
|
644 |
* ticket
|
645 |
* attendee_id
|
646 |
* security
|
@@ -674,6 +740,7 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
674 |
$product_id = get_post_meta( $attendee->ID, self::ATTENDEE_PRODUCT_KEY, true );
|
675 |
$name = get_post_meta( $attendee->ID, $this->full_name, true );
|
676 |
$email = get_post_meta( $attendee->ID, $this->email, true );
|
|
|
677 |
|
678 |
if ( empty( $product_id ) ) {
|
679 |
continue;
|
@@ -687,12 +754,14 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
687 |
'order_id' => $attendee->ID,
|
688 |
'purchaser_name' => $name,
|
689 |
'purchaser_email' => $email,
|
|
|
690 |
'ticket' => $product_title,
|
691 |
'attendee_id' => $attendee->ID,
|
692 |
'security' => $security,
|
693 |
'product_id' => $product_id,
|
694 |
'check_in' => $checkin,
|
695 |
'provider' => __CLASS__,
|
|
|
696 |
);
|
697 |
}
|
698 |
|
@@ -702,16 +771,33 @@ class Tribe__Tickets__RSVP extends Tribe__Tickets__Tickets {
|
|
702 |
/**
|
703 |
* Marks an attendee as checked in for an event
|
704 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
705 |
* @param $attendee_id
|
706 |
-
* @param $qr true if from QR checkin process
|
707 |
*
|
708 |
* @return bool
|
709 |
*/
|
710 |
-
public function checkin( $attendee_id
|
|
|
|
|
711 |
update_post_meta( $attendee_id, $this->checkin_key, 1 );
|
712 |
-
|
|
|
713 |
update_post_meta( $attendee_id, '_tribe_qr_status', 1 );
|
714 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
715 |
do_action( 'rsvp_checkin', $attendee_id, $qr );
|
716 |
|
717 |
return true;
|
60 |
*/
|
61 |
public $security_code = '_tribe_rsvp_security_code';
|
62 |
|
63 |
+
/**
|
64 |
+
* Meta key that if this attendee wants to show on the attendee list
|
65 |
+
*
|
66 |
+
* @var string
|
67 |
+
*/
|
68 |
+
const ATTENDEE_OPTOUT_KEY = '_tribe_rsvp_attendee_optout';
|
69 |
+
|
70 |
/**
|
71 |
* Meta key that holds the full name of the tickets RSVP "buyer"
|
72 |
*
|
110 |
* @return Tribe__Tickets__RSVP
|
111 |
*/
|
112 |
public static function get_instance() {
|
113 |
+
if ( ! self::$instance ) {
|
114 |
+
self::$instance = new self;
|
115 |
}
|
116 |
|
117 |
return self::$instance;
|
130 |
|
131 |
parent::__construct();
|
132 |
|
133 |
+
add_action( 'init', array( $this, 'init' ) );
|
|
|
134 |
}
|
135 |
|
136 |
/**
|
248 |
* Generate and store all the attendees information for a new order.
|
249 |
*/
|
250 |
public function generate_tickets( ) {
|
|
|
251 |
if ( empty( $_POST['tickets_process'] ) || empty( $_POST['attendee'] ) || empty( $_POST['product_id'] ) ) {
|
252 |
return;
|
253 |
}
|
259 |
$attendee_email = empty( $_POST['attendee']['email'] ) ? null : sanitize_email( $_POST['attendee']['email'] );
|
260 |
$attendee_email = is_email( $attendee_email ) ? $attendee_email : null;
|
261 |
$attendee_full_name = empty( $_POST['attendee']['full_name'] ) ? null : sanitize_text_field( $_POST['attendee']['full_name'] );
|
262 |
+
$attendee_optout = empty( $_POST['attendee']['optout'] ) ? false : (bool) $_POST['attendee']['optout'];
|
263 |
|
264 |
if ( ! $attendee_email || ! $attendee_full_name ) {
|
265 |
$url = get_permalink( $event_id );
|
270 |
|
271 |
// Iterate over each product
|
272 |
foreach ( (array) $_POST['product_id'] as $product_id ) {
|
273 |
+
$order_attendee_id = 0;
|
274 |
|
275 |
// Get the event this tickets is for
|
276 |
$event_id = get_post_meta( $product_id, $this->event_key, true );
|
317 |
update_post_meta( $attendee_id, self::ATTENDEE_EVENT_KEY, $event_id );
|
318 |
update_post_meta( $attendee_id, $this->security_code, $this->generate_security_code( $attendee_id ) );
|
319 |
update_post_meta( $attendee_id, $this->order_key, $order_id );
|
320 |
+
update_post_meta( $attendee_id, self::ATTENDEE_OPTOUT_KEY, (bool) $attendee_optout );
|
321 |
update_post_meta( $attendee_id, $this->full_name, $attendee_full_name );
|
322 |
update_post_meta( $attendee_id, $this->email, $attendee_email );
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Action fired when an RSVP attendee ticket is created
|
326 |
+
*
|
327 |
+
* @var $attendee_id ID of the attendee post
|
328 |
+
* @var $event_id Event post ID
|
329 |
+
* @var $product_id RSVP ticket post ID
|
330 |
+
* @var $order_attendee_id Attendee # for order
|
331 |
+
*/
|
332 |
+
do_action( 'event_tickets_rsvp_ticket_created', $attendee_id, $event_id, $product_id, $order_attendee_id );
|
333 |
+
|
334 |
+
$order_attendee_id++;
|
335 |
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Action fired when an RSVP has had attendee tickets generated for it
|
339 |
+
*
|
340 |
+
* @var $product_id RSVP ticket post ID
|
341 |
+
* @var $order_id ID of the RSVP order
|
342 |
+
* @var $qty Quantity ordered
|
343 |
+
*/
|
344 |
+
do_action( 'event_tickets_rsvp_tickets_generated_for_product', $product_id, $order_id, $qty );
|
345 |
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Action fired when an RSVP attendee tickets have been generated
|
349 |
+
*
|
350 |
+
* @var $order_id ID of the RSVP order
|
351 |
+
*/
|
352 |
+
do_action( 'event_tickets_rsvp_tickets_generated', $order_id );
|
353 |
+
|
354 |
if ( $has_tickets ) {
|
355 |
$this->send_tickets_email( $order_id ) ;
|
356 |
}
|
398 |
) );
|
399 |
|
400 |
foreach ( $query->posts as $post ) {
|
401 |
+
$product = get_post( get_post_meta( $post->ID, self::ATTENDEE_PRODUCT_KEY, true ) );
|
402 |
+
|
403 |
$attendees[] = array(
|
404 |
'event_id' => get_post_meta( $post->ID, self::ATTENDEE_EVENT_KEY, true ),
|
405 |
+
'product_id' => $product->ID,
|
406 |
+
'ticket_name' => $product->post_title,
|
407 |
'holder_name' => get_post_meta( $post->ID, $this->full_name, true ),
|
408 |
'holder_email' => get_post_meta( $post->ID, $this->email, true ),
|
409 |
'order_id' => $order_id,
|
410 |
'ticket_id' => $post->ID,
|
411 |
'security_code' => get_post_meta( $post->ID, $this->security_code, true ),
|
412 |
+
'optout' => (bool) get_post_meta( $post->ID, self::ATTENDEE_OPTOUT_KEY, true ),
|
413 |
);
|
414 |
}
|
415 |
|
438 |
* @return bool
|
439 |
*/
|
440 |
public function save_ticket( $event_id, $ticket, $raw_data = array() ) {
|
441 |
+
// assume we are updating until we find out otherwise
|
442 |
+
$save_type = 'update';
|
443 |
|
444 |
if ( empty( $ticket->ID ) ) {
|
445 |
+
$save_type = 'create';
|
446 |
+
|
447 |
/* Create main product post */
|
448 |
$args = array(
|
449 |
'post_status' => 'publish',
|
495 |
delete_post_meta( $ticket->ID, '_ticket_end_date' );
|
496 |
}
|
497 |
|
498 |
+
/**
|
499 |
+
* Generic action fired after saving a ticket (by type)
|
500 |
+
*
|
501 |
+
* @var int Post ID of post the ticket is tied to
|
502 |
+
* @var Tribe__Tickets__Ticket_Object Ticket that was just saved
|
503 |
+
* @var array Ticket data
|
504 |
+
* @var string Commerce engine class
|
505 |
+
*/
|
506 |
+
do_action( 'event_tickets_after_' . $save_type . '_ticket', $event_id, $ticket, $raw_data, __CLASS__ );
|
507 |
+
|
508 |
+
/**
|
509 |
+
* Generic action fired after saving a ticket
|
510 |
+
*
|
511 |
+
* @var int Post ID of post the ticket is tied to
|
512 |
+
* @var Tribe__Tickets__Ticket_Object Ticket that was just saved
|
513 |
+
* @var array Ticket data
|
514 |
+
* @var string Commerce engine class
|
515 |
+
*/
|
516 |
+
do_action( 'event_tickets_after_save_ticket', $event_id, $ticket, $raw_data, __CLASS__ );
|
517 |
+
|
518 |
return true;
|
519 |
}
|
520 |
|
685 |
return false;
|
686 |
}
|
687 |
|
688 |
+
$event_id = get_post_meta( $ticket_product, $this->event_key, true );
|
689 |
|
690 |
+
if ( ! $event_id && '' === ( $event_id = get_post_meta( $ticket_product, self::ATTENDEE_EVENT_KEY, true ) ) ) {
|
691 |
return false;
|
692 |
}
|
693 |
|
694 |
+
if ( in_array( get_post_type( $event_id ), Tribe__Tickets__Main::instance()->post_types() ) ) {
|
695 |
+
return get_post( $event_id );
|
696 |
}
|
697 |
|
698 |
return false;
|
706 |
* order_status
|
707 |
* purchaser_name
|
708 |
* purchaser_email
|
709 |
+
* optout
|
710 |
* ticket
|
711 |
* attendee_id
|
712 |
* security
|
740 |
$product_id = get_post_meta( $attendee->ID, self::ATTENDEE_PRODUCT_KEY, true );
|
741 |
$name = get_post_meta( $attendee->ID, $this->full_name, true );
|
742 |
$email = get_post_meta( $attendee->ID, $this->email, true );
|
743 |
+
$optout = (bool) get_post_meta( $attendee->ID, self::ATTENDEE_OPTOUT_KEY, true );
|
744 |
|
745 |
if ( empty( $product_id ) ) {
|
746 |
continue;
|
754 |
'order_id' => $attendee->ID,
|
755 |
'purchaser_name' => $name,
|
756 |
'purchaser_email' => $email,
|
757 |
+
'optout' => $optout,
|
758 |
'ticket' => $product_title,
|
759 |
'attendee_id' => $attendee->ID,
|
760 |
'security' => $security,
|
761 |
'product_id' => $product_id,
|
762 |
'check_in' => $checkin,
|
763 |
'provider' => __CLASS__,
|
764 |
+
'provider_slug' => 'rsvp',
|
765 |
);
|
766 |
}
|
767 |
|
771 |
/**
|
772 |
* Marks an attendee as checked in for an event
|
773 |
*
|
774 |
+
* Because we must still support our legacy ticket plugins, we cannot change the abstract
|
775 |
+
* checkin() method's signature. However, the QR checkin process needs to move forward
|
776 |
+
* so we get around that problem by leveraging func_get_arg() to pass a second argument.
|
777 |
+
*
|
778 |
+
* It is hacky, but we'll aim to resolve this issue when we end-of-life our legacy ticket plugins
|
779 |
+
* OR write around it in a future major release
|
780 |
+
*
|
781 |
* @param $attendee_id
|
782 |
+
* @param $qr true if from QR checkin process (NOTE: this is a param-less parameter for backward compatibility)
|
783 |
*
|
784 |
* @return bool
|
785 |
*/
|
786 |
+
public function checkin( $attendee_id ) {
|
787 |
+
$qr = null;
|
788 |
+
|
789 |
update_post_meta( $attendee_id, $this->checkin_key, 1 );
|
790 |
+
|
791 |
+
if ( func_num_args() > 1 && $qr = func_get_arg( 1 ) ) {
|
792 |
update_post_meta( $attendee_id, '_tribe_qr_status', 1 );
|
793 |
}
|
794 |
+
|
795 |
+
/**
|
796 |
+
* Fires a checkin action
|
797 |
+
*
|
798 |
+
* @var int $attendee_id
|
799 |
+
* @var bool|null $qr
|
800 |
+
*/
|
801 |
do_action( 'rsvp_checkin', $attendee_id, $qr );
|
802 |
|
803 |
return true;
|
src/Tribe/Ticket_Object.php
CHANGED
@@ -71,6 +71,11 @@ if ( ! class_exists( 'Tribe__Tickets__Ticket_Object' ) ) {
|
|
71 |
*/
|
72 |
public $provider_class;
|
73 |
|
|
|
|
|
|
|
|
|
|
|
74 |
/**
|
75 |
* Amount of tickets of this kind in stock
|
76 |
* Use $this->stock( value ) to set manage and get the value
|
@@ -79,6 +84,22 @@ if ( ! class_exists( 'Tribe__Tickets__Ticket_Object' ) ) {
|
|
79 |
*/
|
80 |
protected $stock = 0;
|
81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
/**
|
83 |
* Amount of tickets of this kind sold
|
84 |
* Use $this->qty_sold( value ) to set manage and get the value
|
@@ -227,6 +248,11 @@ if ( ! class_exists( 'Tribe__Tickets__Ticket_Object' ) ) {
|
|
227 |
// Do the math!
|
228 |
$remaining = $this->original_stock() - $this->qty_sold() - $this->qty_pending();
|
229 |
|
|
|
|
|
|
|
|
|
|
|
230 |
// Prevents Negative
|
231 |
return max( $remaining, 0 );
|
232 |
}
|
@@ -271,6 +297,43 @@ if ( ! class_exists( 'Tribe__Tickets__Ticket_Object' ) ) {
|
|
271 |
return $this->stock;
|
272 |
}
|
273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
/**
|
275 |
* Method to manage the protected `qty_sold` propriety of the Object
|
276 |
* Prevents setting `qty_sold` lower then zero
|
@@ -380,6 +443,41 @@ if ( ! class_exists( 'Tribe__Tickets__Ticket_Object' ) ) {
|
|
380 |
// return the new Qty Cancelled
|
381 |
return $this->qty_cancelled;
|
382 |
}
|
383 |
-
}
|
384 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
}
|
71 |
*/
|
72 |
public $provider_class;
|
73 |
|
74 |
+
/**
|
75 |
+
* @var Tribe__Tickets__Tickets
|
76 |
+
*/
|
77 |
+
protected $provider;
|
78 |
+
|
79 |
/**
|
80 |
* Amount of tickets of this kind in stock
|
81 |
* Use $this->stock( value ) to set manage and get the value
|
84 |
*/
|
85 |
protected $stock = 0;
|
86 |
|
87 |
+
/**
|
88 |
+
* The mode of stock handling to be used for the ticket when global stock
|
89 |
+
* is enabled for the event.
|
90 |
+
*
|
91 |
+
* @var string
|
92 |
+
*/
|
93 |
+
protected $global_stock_mode = Tribe__Tickets__Global_Stock::OWN_STOCK_MODE;
|
94 |
+
|
95 |
+
/**
|
96 |
+
* The maximum permitted number of sales for this ticket when global stock
|
97 |
+
* is enabled for the event and CAPPED_STOCK_MODE is in effect.
|
98 |
+
*
|
99 |
+
* @var int
|
100 |
+
*/
|
101 |
+
protected $global_stock_cap = 0;
|
102 |
+
|
103 |
/**
|
104 |
* Amount of tickets of this kind sold
|
105 |
* Use $this->qty_sold( value ) to set manage and get the value
|
248 |
// Do the math!
|
249 |
$remaining = $this->original_stock() - $this->qty_sold() - $this->qty_pending();
|
250 |
|
251 |
+
// Adjust if using global stock with a sales cap
|
252 |
+
if ( Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE === $this->global_stock_mode() ) {
|
253 |
+
$remaining = min( $remaining, $this->global_stock_cap() );
|
254 |
+
}
|
255 |
+
|
256 |
// Prevents Negative
|
257 |
return max( $remaining, 0 );
|
258 |
}
|
297 |
return $this->stock;
|
298 |
}
|
299 |
|
300 |
+
/**
|
301 |
+
* Sets or gets the current global stock mode in effect for the ticket.
|
302 |
+
*
|
303 |
+
* Typically this is one of the constants provided by Tribe__Tickets__Global_Stock:
|
304 |
+
*
|
305 |
+
* GLOBAL_STOCK_MODE if it should draw on the global stock
|
306 |
+
* CAPPED_STOCK_MODE as above but with a limit on the total number of allowed sales
|
307 |
+
* OWN_STOCK_MODE if it should behave as if global stock is not in effect
|
308 |
+
*
|
309 |
+
* @param string $mode
|
310 |
+
*
|
311 |
+
* @return string
|
312 |
+
*/
|
313 |
+
public function global_stock_mode( $mode = null ) {
|
314 |
+
if ( is_string( $mode ) ) {
|
315 |
+
$this->global_stock_mode = $mode;
|
316 |
+
}
|
317 |
+
|
318 |
+
return $this->global_stock_mode;
|
319 |
+
}
|
320 |
+
|
321 |
+
/**
|
322 |
+
* Sets or gets any cap on sales that might be in effect for this ticket when global stock
|
323 |
+
* mode is in effect.
|
324 |
+
*
|
325 |
+
* @param int $cap
|
326 |
+
*
|
327 |
+
* @return int
|
328 |
+
*/
|
329 |
+
public function global_stock_cap( $cap = null ) {
|
330 |
+
if ( is_numeric( $cap ) ) {
|
331 |
+
$this->global_stock_cap = (int) $cap;
|
332 |
+
}
|
333 |
+
|
334 |
+
return (int) $this->global_stock_cap;
|
335 |
+
}
|
336 |
+
|
337 |
/**
|
338 |
* Method to manage the protected `qty_sold` propriety of the Object
|
339 |
* Prevents setting `qty_sold` lower then zero
|
443 |
// return the new Qty Cancelled
|
444 |
return $this->qty_cancelled;
|
445 |
}
|
|
|
446 |
|
447 |
+
/**
|
448 |
+
* Returns an instance of the provider class.
|
449 |
+
*
|
450 |
+
* @return Tribe__Tickets__Tickets|null
|
451 |
+
*/
|
452 |
+
public function get_provider() {
|
453 |
+
if ( empty( $this->provider ) ) {
|
454 |
+
if ( empty( $this->provider_class ) || ! class_exists( $this->provider_class ) ) {
|
455 |
+
return null;
|
456 |
+
}
|
457 |
+
|
458 |
+
if ( method_exists( $this->provider_class, 'get_instance' ) ) {
|
459 |
+
$this->provider = call_user_func( array( $this->provider_class, 'get_instance' ) );
|
460 |
+
} else {
|
461 |
+
$this->provider = new $this->provider_class;
|
462 |
+
}
|
463 |
+
}
|
464 |
+
|
465 |
+
return $this->provider;
|
466 |
+
}
|
467 |
+
|
468 |
+
/**
|
469 |
+
* Returns the ID of the event post this ticket belongs to.
|
470 |
+
*
|
471 |
+
* @return WP_Post|null
|
472 |
+
*/
|
473 |
+
public function get_event() {
|
474 |
+
$provider = $this->get_provider();
|
475 |
+
|
476 |
+
if ( null !== $provider ) {
|
477 |
+
return $provider->get_event_for_ticket( $this->ID );
|
478 |
+
}
|
479 |
+
|
480 |
+
return null;
|
481 |
+
}
|
482 |
+
}
|
483 |
}
|
src/Tribe/Tickets.php
CHANGED
@@ -30,6 +30,21 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
30 |
*/
|
31 |
protected static $active_modules = array();
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
/**
|
34 |
* Name of this class. Note that it refers to the child class.
|
35 |
* @var string
|
@@ -69,6 +84,11 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
69 |
*/
|
70 |
protected $pluginUrl;
|
71 |
|
|
|
|
|
|
|
|
|
|
|
72 |
/**
|
73 |
* Returns link to the report interface for sales for an event or
|
74 |
* null if the provider doesn't have reporting capabilities.
|
@@ -181,7 +201,7 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
181 |
*
|
182 |
* @return mixed
|
183 |
*/
|
184 |
-
abstract public function checkin( $attendee_id
|
185 |
|
186 |
/**
|
187 |
* Mark an attendee as not checked in
|
@@ -232,6 +252,18 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
232 |
return '';
|
233 |
}
|
234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
/**
|
236 |
* Returns instance of the child class (singleton)
|
237 |
*
|
@@ -344,6 +376,15 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
344 |
do_action( 'tribe_tickets_ticket_added', $post_id );
|
345 |
}
|
346 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
$this->ajax_ok( $return );
|
348 |
}
|
349 |
|
@@ -381,6 +422,15 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
381 |
|
382 |
$ticket->provider_class = $this->className;
|
383 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
384 |
// Pass the control to the child object
|
385 |
return $this->save_ticket( $post_id, $ticket, $data );
|
386 |
}
|
@@ -540,7 +590,13 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
540 |
$return['description'] = htmlspecialchars_decode( $return['description'] );
|
541 |
|
542 |
ob_start();
|
543 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
544 |
$extra = ob_get_contents();
|
545 |
ob_end_clean();
|
546 |
|
@@ -586,15 +642,44 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
586 |
*/
|
587 |
public static function get_event_attendees( $event_id ) {
|
588 |
$attendees = array();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
589 |
|
590 |
foreach ( self::$active_modules as $class => $module ) {
|
591 |
$obj = call_user_func( array( $class, 'get_instance' ) );
|
592 |
$attendees = array_merge( $attendees, $obj->get_attendees( $event_id ) );
|
593 |
}
|
594 |
|
|
|
|
|
|
|
|
|
|
|
595 |
return $attendees;
|
596 |
}
|
597 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
598 |
/**
|
599 |
* Returns all tickets for an event (all providers are queried for this information).
|
600 |
*
|
@@ -671,6 +756,23 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
671 |
|
672 |
// start Helpers
|
673 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
674 |
/**
|
675 |
* Returns whether a class name is a valid active module/provider.
|
676 |
*
|
@@ -689,6 +791,106 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
|
|
689 |
echo 'ticket_advanced ticket_advanced_' . $this->className;
|
690 |
}
|
691 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
692 |
/**
|
693 |
* Returns the array of active modules/providers.
|
694 |
*
|
30 |
*/
|
31 |
protected static $active_modules = array();
|
32 |
|
33 |
+
/**
|
34 |
+
* Indicates if the frontend ticket form script has already been enqueued (or not).
|
35 |
+
*
|
36 |
+
* @var bool
|
37 |
+
*/
|
38 |
+
protected static $frontend_script_enqueued = false;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Collection of ticket objects for which we wish to make global stock data available
|
42 |
+
* on the frontend.
|
43 |
+
*
|
44 |
+
* @var array
|
45 |
+
*/
|
46 |
+
protected static $frontend_ticket_data = array();
|
47 |
+
|
48 |
/**
|
49 |
* Name of this class. Note that it refers to the child class.
|
50 |
* @var string
|
84 |
*/
|
85 |
protected $pluginUrl;
|
86 |
|
87 |
+
/**
|
88 |
+
* Constant with the Transient Key for Attendees Cache
|
89 |
+
*/
|
90 |
+
const ATTENDEES_CACHE = 'tribe_attendees';
|
91 |
+
|
92 |
/**
|
93 |
* Returns link to the report interface for sales for an event or
|
94 |
* null if the provider doesn't have reporting capabilities.
|
201 |
*
|
202 |
* @return mixed
|
203 |
*/
|
204 |
+
abstract public function checkin( $attendee_id );
|
205 |
|
206 |
/**
|
207 |
* Mark an attendee as not checked in
|
252 |
return '';
|
253 |
}
|
254 |
|
255 |
+
/**
|
256 |
+
* Indicates if the module/ticket provider supports a concept of global stock.
|
257 |
+
*
|
258 |
+
* For backward compatibility reasons this method has not been declared abstract but
|
259 |
+
* implementaions are still expected to override it.
|
260 |
+
*
|
261 |
+
* @return bool
|
262 |
+
*/
|
263 |
+
public function supports_global_stock() {
|
264 |
+
return false;
|
265 |
+
}
|
266 |
+
|
267 |
/**
|
268 |
* Returns instance of the child class (singleton)
|
269 |
*
|
376 |
do_action( 'tribe_tickets_ticket_added', $post_id );
|
377 |
}
|
378 |
|
379 |
+
$return = array( 'html' => $return );
|
380 |
+
|
381 |
+
/**
|
382 |
+
* Filters the return data for ticket add
|
383 |
+
*
|
384 |
+
* @var array Array of data to return to the ajax call
|
385 |
+
*/
|
386 |
+
$return = apply_filters( 'event_tickets_ajax_ticket_add_data', $return, $post_id );
|
387 |
+
|
388 |
$this->ajax_ok( $return );
|
389 |
}
|
390 |
|
422 |
|
423 |
$ticket->provider_class = $this->className;
|
424 |
|
425 |
+
/**
|
426 |
+
* Fired once a ticket has been created and added to a post
|
427 |
+
*
|
428 |
+
* @var $post_id Post ID
|
429 |
+
* @var $ticket Ticket object
|
430 |
+
* @var $data Submitted post data
|
431 |
+
*/
|
432 |
+
do_action( 'tribe_tickets_ticket_add', $post_id, $ticket, $data );
|
433 |
+
|
434 |
// Pass the control to the child object
|
435 |
return $this->save_ticket( $post_id, $ticket, $data );
|
436 |
}
|
590 |
$return['description'] = htmlspecialchars_decode( $return['description'] );
|
591 |
|
592 |
ob_start();
|
593 |
+
/**
|
594 |
+
* Fired to allow for the insertion of extra form data in the ticket admin form
|
595 |
+
*
|
596 |
+
* @var $post_id Post ID
|
597 |
+
* @var $ticket_id Ticket ID
|
598 |
+
*/
|
599 |
+
do_action( 'tribe_events_tickets_metabox_advanced', $post_id, $ticket_id );
|
600 |
$extra = ob_get_contents();
|
601 |
ob_end_clean();
|
602 |
|
642 |
*/
|
643 |
public static function get_event_attendees( $event_id ) {
|
644 |
$attendees = array();
|
645 |
+
if ( ! is_admin() ) {
|
646 |
+
$post_transient = Tribe__Post_Transient::instance();
|
647 |
+
|
648 |
+
$attendees = $post_transient->get( $event_id, self::ATTENDEES_CACHE );
|
649 |
+
if ( ! $attendees ) {
|
650 |
+
$attendees = array();
|
651 |
+
}
|
652 |
+
|
653 |
+
if ( is_array( $attendees ) && count( $attendees ) > 0 ) {
|
654 |
+
return $attendees;
|
655 |
+
}
|
656 |
+
}
|
657 |
|
658 |
foreach ( self::$active_modules as $class => $module ) {
|
659 |
$obj = call_user_func( array( $class, 'get_instance' ) );
|
660 |
$attendees = array_merge( $attendees, $obj->get_attendees( $event_id ) );
|
661 |
}
|
662 |
|
663 |
+
if ( ! is_admin() ) {
|
664 |
+
$expire = apply_filters( 'tribe_tickets_attendees_expire', HOUR_IN_SECONDS );
|
665 |
+
$post_transient->set( $event_id, self::ATTENDEES_CACHE, $attendees, $expire );
|
666 |
+
}
|
667 |
+
|
668 |
return $attendees;
|
669 |
}
|
670 |
|
671 |
+
/**
|
672 |
+
* Returns the total number of attendees for an event (regardless of provider).
|
673 |
+
*
|
674 |
+
* @param int $event_id
|
675 |
+
*
|
676 |
+
* @return int
|
677 |
+
*/
|
678 |
+
public static function get_event_attendees_count( $event_id ) {
|
679 |
+
$attendees = self::get_event_attendees( $event_id );
|
680 |
+
return count( $attendees );
|
681 |
+
}
|
682 |
+
|
683 |
/**
|
684 |
* Returns all tickets for an event (all providers are queried for this information).
|
685 |
*
|
756 |
|
757 |
// start Helpers
|
758 |
|
759 |
+
/**
|
760 |
+
* Indicates if any of the currently available providers support global stock.
|
761 |
+
*
|
762 |
+
* @return bool
|
763 |
+
*/
|
764 |
+
public static function global_stock_available() {
|
765 |
+
foreach ( self::$active_modules as $class => $module ) {
|
766 |
+
$provider = call_user_func( array( $class, 'get_instance' ) );
|
767 |
+
|
768 |
+
if ( method_exists( $provider, 'supports_global_stock' ) && $provider->supports_global_stock() ) {
|
769 |
+
return true;
|
770 |
+
}
|
771 |
+
}
|
772 |
+
|
773 |
+
return false;
|
774 |
+
}
|
775 |
+
|
776 |
/**
|
777 |
* Returns whether a class name is a valid active module/provider.
|
778 |
*
|
791 |
echo 'ticket_advanced ticket_advanced_' . $this->className;
|
792 |
}
|
793 |
|
794 |
+
/**
|
795 |
+
* Generates a select element listing the available global stock mode options.
|
796 |
+
*
|
797 |
+
* @param string $current_option
|
798 |
+
*
|
799 |
+
* @return string
|
800 |
+
*/
|
801 |
+
protected function global_stock_mode_selector( $current_option = '' ) {
|
802 |
+
$output = "<select id='ticket_global_stock' name='ticket_global_stock' class='ticket_field'>\n";
|
803 |
+
|
804 |
+
// Default to using own stock unless the user explicitly specifies otherwise (important
|
805 |
+
// to avoid assuming global stock mode if global stock is enabled/disabled accidentally etc)
|
806 |
+
if ( empty( $current_option ) ) {
|
807 |
+
$current_option = Tribe__Tickets__Global_Stock::OWN_STOCK_MODE;
|
808 |
+
}
|
809 |
+
|
810 |
+
foreach ( $this->global_stock_mode_options() as $identifier => $name ) {
|
811 |
+
$identifier = esc_html( $identifier );
|
812 |
+
$name = esc_html( $name );
|
813 |
+
$selected = selected( $identifier === $current_option, true, false );
|
814 |
+
$output .= "\t<option value='$identifier' $selected> $name </option>\n";
|
815 |
+
}
|
816 |
+
|
817 |
+
return "$output</select>";
|
818 |
+
}
|
819 |
+
|
820 |
+
/**
|
821 |
+
* Returns an array of standard global stock mode options that can be
|
822 |
+
* reused by implementations.
|
823 |
+
*
|
824 |
+
* Format is: [ 'identifier' => 'Localized name', ... ]
|
825 |
+
*
|
826 |
+
* @return array
|
827 |
+
*/
|
828 |
+
protected function global_stock_mode_options() {
|
829 |
+
return array(
|
830 |
+
Tribe__Tickets__Global_Stock::GLOBAL_STOCK_MODE => __( 'Use global stock', 'event-tickets' ),
|
831 |
+
Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE => __( 'Use global stock but cap sales', 'event-tickets' ),
|
832 |
+
Tribe__Tickets__Global_Stock::OWN_STOCK_MODE => __( 'Independent (do not use global stock)', 'event-tickets' ),
|
833 |
+
);
|
834 |
+
}
|
835 |
+
|
836 |
+
/**
|
837 |
+
* Tries to make data about global stock levels and global stock-enabled ticket objects
|
838 |
+
* available to frontend scripts.
|
839 |
+
*
|
840 |
+
* @param array $tickets
|
841 |
+
*/
|
842 |
+
public static function add_frontend_stock_data( array $tickets ) {
|
843 |
+
// Add the frontend ticket form script as needed (we do this lazily since right now
|
844 |
+
// it's only required for certain combinations of event/ticket
|
845 |
+
if ( ! self::$frontend_script_enqueued ) {
|
846 |
+
$url = Tribe__Tickets__Main::instance()->plugin_url . 'src/resources/js/frontend-ticket-form.js';
|
847 |
+
$url = Tribe__Template_Factory::getMinFile( $url, true );
|
848 |
+
|
849 |
+
wp_enqueue_script( 'tribe_tickets_frontend_tickets', $url, array( 'jquery' ), Tribe__Tickets__Main::VERSION, true );
|
850 |
+
add_action( 'wp_footer', array( __CLASS__, 'enqueue_frontend_stock_data' ), 1 );
|
851 |
+
}
|
852 |
+
|
853 |
+
self::$frontend_ticket_data += $tickets;
|
854 |
+
}
|
855 |
+
|
856 |
+
/**
|
857 |
+
* Takes any global stock data and makes it available via a wp_localize_script() call.
|
858 |
+
*/
|
859 |
+
public static function enqueue_frontend_stock_data() {
|
860 |
+
$data = array(
|
861 |
+
'tickets' => array(),
|
862 |
+
'events' => array(),
|
863 |
+
);
|
864 |
+
|
865 |
+
foreach ( self::$frontend_ticket_data as $ticket ) {
|
866 |
+
/**
|
867 |
+
* @var Tribe__Tickets__Ticket_Object $ticket
|
868 |
+
*/
|
869 |
+
$event_id = $ticket->get_event()->ID;
|
870 |
+
$global_stock = new Tribe__Tickets__Global_Stock( $event_id );
|
871 |
+
$stock_mode = $ticket->global_stock_mode();
|
872 |
+
|
873 |
+
$data[ 'tickets' ][ $ticket->ID ] = array(
|
874 |
+
'event_id' => $event_id,
|
875 |
+
'mode' => $stock_mode,
|
876 |
+
);
|
877 |
+
|
878 |
+
if ( Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE === $stock_mode ) {
|
879 |
+
$data[ 'tickets' ][ $ticket->ID ][ 'cap' ] = $ticket->global_stock_cap();
|
880 |
+
}
|
881 |
+
|
882 |
+
if ( Tribe__Tickets__Global_Stock::OWN_STOCK_MODE === $stock_mode ) {
|
883 |
+
$data[ 'tickets' ][ $ticket->ID ][ 'stock' ] = $ticket->stock();
|
884 |
+
}
|
885 |
+
|
886 |
+
$data[ 'events' ][ $event_id ] = array(
|
887 |
+
'stock' => $global_stock->get_stock_level()
|
888 |
+
);
|
889 |
+
}
|
890 |
+
|
891 |
+
wp_localize_script( 'tribe_tickets_frontend_tickets', 'tribe_tickets_stock_data', $data );
|
892 |
+
}
|
893 |
+
|
894 |
/**
|
895 |
* Returns the array of active modules/providers.
|
896 |
*
|
src/Tribe/Tickets_Handler.php
CHANGED
@@ -51,7 +51,8 @@ class Tribe__Tickets__Tickets_Handler {
|
|
51 |
$main = Tribe__Tickets__Main::instance();
|
52 |
|
53 |
foreach ( $main->post_types() as $post_type ) {
|
54 |
-
add_action( 'save_post_' . $post_type, array( $this, 'save_image_header' )
|
|
|
55 |
}
|
56 |
|
57 |
add_action( 'wp_ajax_tribe-ticket-email-attendee-list', array( $this, 'ajax_handler_attendee_mail_list' ) );
|
@@ -71,8 +72,9 @@ class Tribe__Tickets__Tickets_Handler {
|
|
71 |
*/
|
72 |
public function attendees_row_action( $actions ) {
|
73 |
global $post;
|
|
|
74 |
|
75 |
-
if ( in_array( $post->post_type, Tribe__Tickets__Main::instance()->post_types() ) ) {
|
76 |
$url = add_query_arg( array(
|
77 |
'post_type' => $post->post_type,
|
78 |
'page' => self::$attendees_slug,
|
@@ -226,52 +228,50 @@ class Tribe__Tickets__Tickets_Handler {
|
|
226 |
*
|
227 |
* @return array
|
228 |
*/
|
229 |
-
private function
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
|
231 |
if ( empty( $this->attendees_page ) ) {
|
232 |
$this->attendees_page = 'tribe_events_page_tickets-attendees';
|
233 |
}
|
234 |
|
235 |
-
$
|
|
|
236 |
$hidden = get_hidden_columns( $this->attendees_page );
|
237 |
|
238 |
// We dont want to export html inputs or private data
|
239 |
$hidden[] = 'cb';
|
240 |
$hidden[] = 'provider';
|
241 |
|
242 |
-
// Get the data
|
243 |
-
$items = Tribe__Tickets__Tickets::get_event_attendees( $event_id );
|
244 |
-
|
245 |
-
// if there are attendees, hide any column that the attendee array doesn't contain
|
246 |
-
if ( count( $items ) ) {
|
247 |
-
$hidden = array_merge(
|
248 |
-
$hidden,
|
249 |
-
array_diff(
|
250 |
-
array_keys( $columns ),
|
251 |
-
array_keys( $items[0] )
|
252 |
-
)
|
253 |
-
);
|
254 |
-
}
|
255 |
-
|
256 |
-
// remove the hidden fields from the final list of columns
|
257 |
-
$hidden = array_filter( $hidden );
|
258 |
$hidden = array_flip( $hidden );
|
259 |
$export_columns = array_diff_key( $columns, $hidden );
|
260 |
-
$columns_names = array_filter( array_values( $export_columns ) );
|
261 |
-
$export_columns = array_filter( array_keys( $export_columns ) );
|
262 |
|
263 |
-
|
264 |
-
|
265 |
-
|
|
|
|
|
|
|
|
|
266 |
$row = array();
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
|
|
|
|
|
|
|
|
273 |
}
|
274 |
}
|
|
|
275 |
$rows[] = array_values( $row );
|
276 |
}
|
277 |
|
@@ -279,11 +279,10 @@ class Tribe__Tickets__Tickets_Handler {
|
|
279 |
}
|
280 |
|
281 |
/**
|
282 |
-
*
|
283 |
-
*
|
284 |
*/
|
285 |
public function maybe_generate_attendees_csv() {
|
286 |
-
|
287 |
if ( empty( $_GET['attendees_csv'] ) || empty( $_GET['attendees_csv_nonce'] ) || empty( $_GET['event_id'] ) ) {
|
288 |
return;
|
289 |
}
|
@@ -292,8 +291,7 @@ class Tribe__Tickets__Tickets_Handler {
|
|
292 |
return;
|
293 |
}
|
294 |
|
295 |
-
|
296 |
-
$items = apply_filters( 'tribe_events_tickets_attendees_csv_items', $this->_generate_filtered_attendees_list( $_GET['event_id'] ) );;
|
297 |
$event = get_post( $_GET['event_id'] );
|
298 |
|
299 |
if ( ! empty( $items ) ) {
|
@@ -381,7 +379,7 @@ class Tribe__Tickets__Tickets_Handler {
|
|
381 |
|
382 |
$this->attendees_table = new Tribe__Tickets__Attendees_Table();
|
383 |
|
384 |
-
$items = $this->
|
385 |
|
386 |
$event = get_post( $_GET['event_id'] );
|
387 |
|
@@ -447,9 +445,9 @@ class Tribe__Tickets__Tickets_Handler {
|
|
447 |
/**
|
448 |
* Includes the tickets metabox inside the Event edit screen
|
449 |
*
|
450 |
-
* @param $
|
451 |
*/
|
452 |
-
public function do_meta_box( $
|
453 |
|
454 |
$startMinuteOptions = Tribe__View_Helpers::getMinuteOptions( null );
|
455 |
$endMinuteOptions = Tribe__View_Helpers::getMinuteOptions( null );
|
@@ -458,7 +456,10 @@ class Tribe__Tickets__Tickets_Handler {
|
|
458 |
$startMeridianOptions = Tribe__View_Helpers::getMeridianOptions( null, true );
|
459 |
$endMeridianOptions = Tribe__View_Helpers::getMeridianOptions( null );
|
460 |
|
461 |
-
$
|
|
|
|
|
|
|
462 |
include $this->path . 'src/admin-views/meta-box.php';
|
463 |
}
|
464 |
|
@@ -504,10 +505,13 @@ class Tribe__Tickets__Tickets_Handler {
|
|
504 |
/**
|
505 |
* Save or delete the image header for tickets on an event
|
506 |
*
|
507 |
-
* @param $post_id
|
508 |
-
* @param $post
|
509 |
*/
|
510 |
-
public function save_image_header( $post_id
|
|
|
|
|
|
|
|
|
511 |
// don't do anything on autosave or auto-draft either or massupdates
|
512 |
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
|
513 |
return;
|
@@ -522,6 +526,29 @@ class Tribe__Tickets__Tickets_Handler {
|
|
522 |
return;
|
523 |
}
|
524 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
525 |
/**
|
526 |
* Static Singleton Factory Method
|
527 |
*
|
51 |
$main = Tribe__Tickets__Main::instance();
|
52 |
|
53 |
foreach ( $main->post_types() as $post_type ) {
|
54 |
+
add_action( 'save_post_' . $post_type, array( $this, 'save_image_header' ) );
|
55 |
+
add_action( 'save_post_' . $post_type, array( $this, 'save_global_stock' ) );
|
56 |
}
|
57 |
|
58 |
add_action( 'wp_ajax_tribe-ticket-email-attendee-list', array( $this, 'ajax_handler_attendee_mail_list' ) );
|
72 |
*/
|
73 |
public function attendees_row_action( $actions ) {
|
74 |
global $post;
|
75 |
+
$tickets = Tribe__Tickets__Tickets::get_event_tickets( $post->ID );
|
76 |
|
77 |
+
if ( in_array( $post->post_type, Tribe__Tickets__Main::instance()->post_types() ) && ! empty( $tickets ) ) {
|
78 |
$url = add_query_arg( array(
|
79 |
'post_type' => $post->post_type,
|
80 |
'page' => self::$attendees_slug,
|
228 |
*
|
229 |
* @return array
|
230 |
*/
|
231 |
+
private function generate_filtered_attendees_list( $event_id ) {
|
232 |
+
/**
|
233 |
+
* Fire immediately prior to the generation of a filtered (exportable) attendee list.
|
234 |
+
*
|
235 |
+
* @param int $event_id
|
236 |
+
*/
|
237 |
+
do_action( 'tribe_events_tickets_generate_filtered_attendees_list', $event_id );
|
238 |
|
239 |
if ( empty( $this->attendees_page ) ) {
|
240 |
$this->attendees_page = 'tribe_events_page_tickets-attendees';
|
241 |
}
|
242 |
|
243 |
+
$items = Tribe__Tickets__Tickets::get_event_attendees( $event_id );
|
244 |
+
$columns = get_column_headers( get_current_screen() );
|
245 |
$hidden = get_hidden_columns( $this->attendees_page );
|
246 |
|
247 |
// We dont want to export html inputs or private data
|
248 |
$hidden[] = 'cb';
|
249 |
$hidden[] = 'provider';
|
250 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
$hidden = array_flip( $hidden );
|
252 |
$export_columns = array_diff_key( $columns, $hidden );
|
|
|
|
|
253 |
|
254 |
+
// Add the export column headers as the first row
|
255 |
+
$rows = array(
|
256 |
+
array_values( $export_columns ),
|
257 |
+
);
|
258 |
+
|
259 |
+
foreach ( $items as $single_item ) {
|
260 |
+
// Fresh row!
|
261 |
$row = array();
|
262 |
+
|
263 |
+
foreach ( $export_columns as $column_id => $column_name ) {
|
264 |
+
// If additional columns have been added to the attendee list table we can obtain the
|
265 |
+
// values by calling the table object's column_default() method - any other values
|
266 |
+
// should simply be passed back unmodified
|
267 |
+
$row[ $column_id ] = $this->attendees_table->column_default( $single_item, $column_id );
|
268 |
+
|
269 |
+
// Special handling for the check_in column
|
270 |
+
if ( 'check_in' === $column_id && 1 == $single_item[ $column_id ] ) {
|
271 |
+
$row[ $column_id ] = esc_html__( 'Yes', 'event-tickets' );
|
272 |
}
|
273 |
}
|
274 |
+
|
275 |
$rows[] = array_values( $row );
|
276 |
}
|
277 |
|
279 |
}
|
280 |
|
281 |
/**
|
282 |
+
* Checks if the user requested a CSV export from the attendees list.
|
283 |
+
* If so, generates the download and finishes the execution.
|
284 |
*/
|
285 |
public function maybe_generate_attendees_csv() {
|
|
|
286 |
if ( empty( $_GET['attendees_csv'] ) || empty( $_GET['attendees_csv_nonce'] ) || empty( $_GET['event_id'] ) ) {
|
287 |
return;
|
288 |
}
|
291 |
return;
|
292 |
}
|
293 |
|
294 |
+
$items = apply_filters( 'tribe_events_tickets_attendees_csv_items', $this->generate_filtered_attendees_list( $_GET['event_id'] ) );;
|
|
|
295 |
$event = get_post( $_GET['event_id'] );
|
296 |
|
297 |
if ( ! empty( $items ) ) {
|
379 |
|
380 |
$this->attendees_table = new Tribe__Tickets__Attendees_Table();
|
381 |
|
382 |
+
$items = $this->generate_filtered_attendees_list( $_GET['event_id'] );
|
383 |
|
384 |
$event = get_post( $_GET['event_id'] );
|
385 |
|
445 |
/**
|
446 |
* Includes the tickets metabox inside the Event edit screen
|
447 |
*
|
448 |
+
* @param WP_Post $post
|
449 |
*/
|
450 |
+
public function do_meta_box( $post ) {
|
451 |
|
452 |
$startMinuteOptions = Tribe__View_Helpers::getMinuteOptions( null );
|
453 |
$endMinuteOptions = Tribe__View_Helpers::getMinuteOptions( null );
|
456 |
$startMeridianOptions = Tribe__View_Helpers::getMeridianOptions( null, true );
|
457 |
$endMeridianOptions = Tribe__View_Helpers::getMeridianOptions( null );
|
458 |
|
459 |
+
$show_global_stock = Tribe__Tickets__Tickets::global_stock_available();
|
460 |
+
$tickets = Tribe__Tickets__Tickets::get_event_tickets( $post->ID );
|
461 |
+
$global_stock = new Tribe__Tickets__Global_Stock( $post->ID );
|
462 |
+
|
463 |
include $this->path . 'src/admin-views/meta-box.php';
|
464 |
}
|
465 |
|
505 |
/**
|
506 |
* Save or delete the image header for tickets on an event
|
507 |
*
|
508 |
+
* @param int $post_id
|
|
|
509 |
*/
|
510 |
+
public function save_image_header( $post_id ) {
|
511 |
+
if ( ! ( isset($_POST[ 'tribe-tickets-post-settings' ]) && wp_verify_nonce( $_POST[ 'tribe-tickets-post-settings' ], 'tribe-tickets-meta-box' ) ) ) {
|
512 |
+
return;
|
513 |
+
}
|
514 |
+
|
515 |
// don't do anything on autosave or auto-draft either or massupdates
|
516 |
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
|
517 |
return;
|
526 |
return;
|
527 |
}
|
528 |
|
529 |
+
/**
|
530 |
+
* Save the current global stock properties for this event.
|
531 |
+
*
|
532 |
+
* @param int $post_id
|
533 |
+
*/
|
534 |
+
public function save_global_stock( $post_id ) {
|
535 |
+
if ( ! ( isset( $_POST[ 'tribe-tickets-post-settings' ] ) && wp_verify_nonce( $_POST[ 'tribe-tickets-post-settings' ], 'tribe-tickets-meta-box' ) ) ) {
|
536 |
+
return;
|
537 |
+
}
|
538 |
+
|
539 |
+
// Bail on autosaves/bulk updates
|
540 |
+
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
|
541 |
+
return;
|
542 |
+
}
|
543 |
+
|
544 |
+
$enable = ! empty( $_POST[ 'tribe-tickets-enable-global-stock' ] );
|
545 |
+
$stock = (int) @$_POST[ 'tribe-tickets-global-stock' ];
|
546 |
+
|
547 |
+
$post_global_stock = new Tribe__Tickets__Global_Stock( $post_id );
|
548 |
+
$post_global_stock->enable( $enable );
|
549 |
+
$post_global_stock->set_stock_level( $stock );
|
550 |
+
}
|
551 |
+
|
552 |
/**
|
553 |
* Static Singleton Factory Method
|
554 |
*
|
src/admin-views/attendees.php
CHANGED
@@ -15,8 +15,9 @@ foreach ( $tickets as $ticket ) {
|
|
15 |
$total_sold += $ticket->qty_sold() + $ticket->qty_pending();
|
16 |
$total_pending += $ticket->qty_pending();
|
17 |
}
|
18 |
-
$total_completed
|
19 |
-
|
|
|
20 |
?>
|
21 |
|
22 |
<div class="wrap tribe-attendees-page">
|
@@ -91,6 +92,13 @@ $total_completed = $total_sold - $total_pending;
|
|
91 |
<strong><?php esc_html_e( 'Checked in:', 'event-tickets' ); ?></strong>
|
92 |
<span id="total_checkedin"><?php echo esc_html( $checkedin ); ?></span>
|
93 |
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
</ul>
|
95 |
<?php do_action( 'tribe_events_tickets_attendees_totals_bottom', $event_id ); ?>
|
96 |
</div>
|
15 |
$total_sold += $ticket->qty_sold() + $ticket->qty_pending();
|
16 |
$total_pending += $ticket->qty_pending();
|
17 |
}
|
18 |
+
$total_completed = $total_sold - $total_pending;
|
19 |
+
$total_attendees = Tribe__Tickets__Tickets::get_event_attendees_count( $event_id );
|
20 |
+
$deleted_attendees = $total_sold - $total_attendees;
|
21 |
?>
|
22 |
|
23 |
<div class="wrap tribe-attendees-page">
|
92 |
<strong><?php esc_html_e( 'Checked in:', 'event-tickets' ); ?></strong>
|
93 |
<span id="total_checkedin"><?php echo esc_html( $checkedin ); ?></span>
|
94 |
</li>
|
95 |
+
|
96 |
+
<?php if ( $deleted_attendees > 0 ): ?>
|
97 |
+
<li>
|
98 |
+
<strong><?php esc_html_e( 'Deleted:', 'event-tickets' ); ?></strong>
|
99 |
+
<span id="total_deleted"><?php echo esc_html( $deleted_attendees ); ?></span>
|
100 |
+
</li>
|
101 |
+
<?php endif; ?>
|
102 |
</ul>
|
103 |
<?php do_action( 'tribe_events_tickets_attendees_totals_bottom', $event_id ); ?>
|
104 |
</div>
|
src/admin-views/list.php
CHANGED
@@ -23,6 +23,9 @@
|
|
23 |
$modules = Tribe__Tickets__Tickets::modules();
|
24 |
|
25 |
foreach ( $tickets as $ticket ) {
|
|
|
|
|
|
|
26 |
$controls = array();
|
27 |
$provider = $ticket->provider_class;
|
28 |
$provider_obj = call_user_func( array( $provider, 'get_instance' ) );
|
@@ -75,9 +78,17 @@
|
|
75 |
<?php endif; ?>
|
76 |
<tr>
|
77 |
<td>
|
78 |
-
<p class="ticket_name"
|
79 |
-
|
80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
<div class="ticket_controls">
|
83 |
<?php echo join( ' | ', $controls ); ?>
|
@@ -90,27 +101,7 @@
|
|
90 |
</td>
|
91 |
|
92 |
<td nowrap="nowrap">
|
93 |
-
<?php
|
94 |
-
$stock = $ticket->original_stock();
|
95 |
-
$sold = $ticket->qty_sold();
|
96 |
-
$cancelled = $ticket->qty_cancelled();
|
97 |
-
|
98 |
-
if ( empty( $stock ) && $stock !== 0 ) : ?>
|
99 |
-
<?php echo sprintf( esc_html__( 'Sold %d', 'event-tickets' ), esc_html( $sold ) ); ?>
|
100 |
-
<?php else : ?>
|
101 |
-
<?php
|
102 |
-
$cancelled_entry = empty( $cancelled ) ? '' : esc_html(sprintf(
|
103 |
-
__( ' (%1$d %2$s)' ), $cancelled,
|
104 |
-
_n( 'unit cancelled', 'units cancelled', $cancelled, 'event-tickets' )
|
105 |
-
));
|
106 |
-
$line = sprintf(
|
107 |
-
esc_html__( 'Sold %1$d of %2$d%3$s', 'event-tickets' ), esc_html( $sold ),
|
108 |
-
esc_html( $stock ), $cancelled_entry
|
109 |
-
);
|
110 |
-
|
111 |
-
echo $line;
|
112 |
-
?>
|
113 |
-
<?php endif; ?>
|
114 |
</td>
|
115 |
<td width="40%" valign="top">
|
116 |
<?php echo esc_html( $ticket->description ); ?>
|
23 |
$modules = Tribe__Tickets__Tickets::modules();
|
24 |
|
25 |
foreach ( $tickets as $ticket ) {
|
26 |
+
/**
|
27 |
+
* @var Tribe__Tickets__Ticket_Object $ticket
|
28 |
+
*/
|
29 |
$controls = array();
|
30 |
$provider = $ticket->provider_class;
|
31 |
$provider_obj = call_user_func( array( $provider, 'get_instance' ) );
|
78 |
<?php endif; ?>
|
79 |
<tr>
|
80 |
<td>
|
81 |
+
<p class="ticket_name">
|
82 |
+
<?php
|
83 |
+
printf(
|
84 |
+
"<a href='#' attr-provider='%s' attr-ticket-id='%s' class='ticket_edit'>%s</a>",
|
85 |
+
esc_attr( $ticket->provider_class ),
|
86 |
+
esc_attr( $ticket->ID ),
|
87 |
+
esc_html( $ticket->name )
|
88 |
+
);
|
89 |
+
do_action( 'event_tickets_ticket_list_after_ticket_name', $ticket );
|
90 |
+
?>
|
91 |
+
</p>
|
92 |
|
93 |
<div class="ticket_controls">
|
94 |
<?php echo join( ' | ', $controls ); ?>
|
101 |
</td>
|
102 |
|
103 |
<td nowrap="nowrap">
|
104 |
+
<?php echo tribe_tickets_get_ticket_stock_message( $ticket ); ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
</td>
|
106 |
<td width="40%" valign="top">
|
107 |
<?php echo esc_html( $ticket->description ); ?>
|
src/admin-views/meta-box.php
CHANGED
@@ -1,4 +1,10 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
// Don't load directly
|
3 |
if ( ! defined( 'ABSPATH' ) ) {
|
4 |
die( '-1' );
|
@@ -16,6 +22,8 @@ $modules = Tribe__Tickets__Tickets::modules();
|
|
16 |
|
17 |
<table id="event_tickets" class="eventtable">
|
18 |
<?php
|
|
|
|
|
19 |
if ( get_post_meta( get_the_ID(), '_EventOrigin', true ) === 'community-events' ) {
|
20 |
?>
|
21 |
<tr>
|
@@ -26,7 +34,7 @@ $modules = Tribe__Tickets__Tickets::modules();
|
|
26 |
<?php
|
27 |
}
|
28 |
?>
|
29 |
-
<tr>
|
30 |
<td colspan="2" class="tribe_sectionheader updated">
|
31 |
<table class="eventtable ticket_list eventForm">
|
32 |
<tr class="tribe-tickets-image-upload">
|
@@ -43,7 +51,7 @@ $modules = Tribe__Tickets__Tickets::modules();
|
|
43 |
<div class="tribe_preview" id="tribe_ticket_header_preview">
|
44 |
<?php echo $header_img; ?>
|
45 |
</div>
|
46 |
-
<p class="description"><a href="#" id="tribe_ticket_header_remove"><?php esc_html_e( 'Remove' ); ?></a></p>
|
47 |
|
48 |
<input type="hidden" id="tribe_ticket_header_image_id" name="tribe_ticket_header_image_id" value="<?php echo esc_attr( $header_id ); ?>" />
|
49 |
</td>
|
@@ -51,6 +59,46 @@ $modules = Tribe__Tickets__Tickets::modules();
|
|
51 |
</table>
|
52 |
</td>
|
53 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
<tr>
|
55 |
<td colspan="2" class="tribe_sectionheader ticket_list_container">
|
56 |
|
@@ -160,7 +208,7 @@ $modules = Tribe__Tickets__Tickets::modules();
|
|
160 |
<?php esc_html_e( 'When will ticket sales occur?', 'event-tickets' ); ?>
|
161 |
<?php
|
162 |
// Why break in and out of PHP? because I want the space between the phrases without including them in the translations
|
163 |
-
if ( class_exists( 'Tribe__Events__Main' ) && Tribe__Events__Main::POSTTYPE === get_post_type( $
|
164 |
esc_html_e( "If you don't set a start/end date for sales, tickets will be available from now until the event ends.", 'event-tickets' );
|
165 |
}
|
166 |
?>
|
@@ -168,7 +216,14 @@ $modules = Tribe__Tickets__Tickets::modules();
|
|
168 |
</td>
|
169 |
</tr>
|
170 |
|
171 |
-
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
|
173 |
<tr class="ticket bottom">
|
174 |
<td></td>
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* @var WP_Post $post
|
4 |
+
* @var bool $show_global_stock
|
5 |
+
* @var Tribe__Tickets__Global_Stock $global_stock
|
6 |
+
*/
|
7 |
+
|
8 |
// Don't load directly
|
9 |
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
die( '-1' );
|
22 |
|
23 |
<table id="event_tickets" class="eventtable">
|
24 |
<?php
|
25 |
+
wp_nonce_field( 'tribe-tickets-meta-box', 'tribe-tickets-post-settings' );
|
26 |
+
|
27 |
if ( get_post_meta( get_the_ID(), '_EventOrigin', true ) === 'community-events' ) {
|
28 |
?>
|
29 |
<tr>
|
34 |
<?php
|
35 |
}
|
36 |
?>
|
37 |
+
<tr class="event-wide-settings">
|
38 |
<td colspan="2" class="tribe_sectionheader updated">
|
39 |
<table class="eventtable ticket_list eventForm">
|
40 |
<tr class="tribe-tickets-image-upload">
|
51 |
<div class="tribe_preview" id="tribe_ticket_header_preview">
|
52 |
<?php echo $header_img; ?>
|
53 |
</div>
|
54 |
+
<p class="description"><a href="#" id="tribe_ticket_header_remove"><?php esc_html_e( 'Remove', 'event-tickets' ); ?></a></p>
|
55 |
|
56 |
<input type="hidden" id="tribe_ticket_header_image_id" name="tribe_ticket_header_image_id" value="<?php echo esc_attr( $header_id ); ?>" />
|
57 |
</td>
|
59 |
</table>
|
60 |
</td>
|
61 |
</tr>
|
62 |
+
<?php if ( $show_global_stock ): ?>
|
63 |
+
<tr id="tribe-global-stock-settings" class="event-wide-settings">
|
64 |
+
<td colspan="2">
|
65 |
+
<table class="eventtable ticket_list eventForm">
|
66 |
+
<tr>
|
67 |
+
<td>
|
68 |
+
<label for="tribe-tickets-enable-global-stock">
|
69 |
+
<?php esc_html_e( 'Enable global stock', 'event-tickets' ); ?>
|
70 |
+
</label>
|
71 |
+
</td>
|
72 |
+
<td>
|
73 |
+
<input type="checkbox" name="tribe-tickets-enable-global-stock" id="tribe-tickets-enable-global-stock" value="1" <?php checked( $global_stock->is_enabled() ); ?> />
|
74 |
+
</td>
|
75 |
+
</tr>
|
76 |
+
<tr id="tribe-tickets-global-stock-level">
|
77 |
+
<td>
|
78 |
+
<label for="tribe-tickets-global-stock">
|
79 |
+
<?php esc_html_e( 'Global stock level', 'event-tickets' ); ?>
|
80 |
+
</label>
|
81 |
+
</td>
|
82 |
+
<td>
|
83 |
+
<input type="number" name="tribe-tickets-global-stock" id="tribe-tickets-global-stock" value="<?php echo esc_attr( $global_stock->get_stock_level() ); ?>" />
|
84 |
+
<span class="tribe-tickets-global-sales">
|
85 |
+
<?php echo esc_html( sprintf( _n( '(%s sold)', '(%s sold)', $global_stock->tickets_sold(), 'event-tickets' ), $global_stock->tickets_sold() ) ); ?>
|
86 |
+
</span>
|
87 |
+
</td>
|
88 |
+
</tr>
|
89 |
+
</table>
|
90 |
+
</td>
|
91 |
+
</tr>
|
92 |
+
<?php endif; ?>
|
93 |
+
|
94 |
+
<?php
|
95 |
+
/**
|
96 |
+
* Fired to allow for the insertion of additional content into the ticket admin form before the tickets listing
|
97 |
+
*
|
98 |
+
* @param Post ID
|
99 |
+
*/
|
100 |
+
do_action( 'tribe_events_tickets_metabox_pre', get_the_ID() ); ?>
|
101 |
+
|
102 |
<tr>
|
103 |
<td colspan="2" class="tribe_sectionheader ticket_list_container">
|
104 |
|
208 |
<?php esc_html_e( 'When will ticket sales occur?', 'event-tickets' ); ?>
|
209 |
<?php
|
210 |
// Why break in and out of PHP? because I want the space between the phrases without including them in the translations
|
211 |
+
if ( class_exists( 'Tribe__Events__Main' ) && Tribe__Events__Main::POSTTYPE === get_post_type( $post ) ) {
|
212 |
esc_html_e( "If you don't set a start/end date for sales, tickets will be available from now until the event ends.", 'event-tickets' );
|
213 |
}
|
214 |
?>
|
216 |
</td>
|
217 |
</tr>
|
218 |
|
219 |
+
<?php
|
220 |
+
/**
|
221 |
+
* Fired to allow for the insertion of additional content into the ticket admin form
|
222 |
+
*
|
223 |
+
* @var Post ID
|
224 |
+
* @var null Ticket ID
|
225 |
+
*/
|
226 |
+
do_action( 'tribe_events_tickets_metabox_advanced', get_the_ID(), null ); ?>
|
227 |
|
228 |
<tr class="ticket bottom">
|
229 |
<td></td>
|
src/admin-views/rsvp-metabox-advanced.php
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<tr class="<?php $this->tr_class(); ?>">
|
2 |
-
<td><label for="
|
3 |
<td>
|
4 |
<input type='text' id='ticket_rsvp_stock' name='ticket_rsvp_stock' class="ticket_field" size='7' value='<?php echo esc_attr( $stock ); ?>'/>
|
5 |
|
1 |
<tr class="<?php $this->tr_class(); ?>">
|
2 |
+
<td><label for="ticket_rsvp_stock"><?php esc_html_e( 'Stock:', 'event-tickets' ); ?></label></td>
|
3 |
<td>
|
4 |
<input type='text' id='ticket_rsvp_stock' name='ticket_rsvp_stock' class="ticket_field" size='7' value='<?php echo esc_attr( $stock ); ?>'/>
|
5 |
|
src/deprecated/TribeEventsTicketObject.php
CHANGED
File without changes
|
src/deprecated/TribeEventsTickets.php
CHANGED
File without changes
|
src/deprecated/TribeEventsTicketsAttendeesTable.php
CHANGED
File without changes
|
src/deprecated/TribeEventsTicketsMetabox.php
CHANGED
File without changes
|
src/deprecated/TribeEventsTicketsPro.php
CHANGED
File without changes
|
src/deprecated/Tribe__Events__Tickets__Attendees_Table.php
CHANGED
File without changes
|
src/deprecated/Tribe__Events__Tickets__Metabox.php
CHANGED
File without changes
|
src/deprecated/Tribe__Events__Tickets__Ticket_Object.php
CHANGED
File without changes
|
src/deprecated/Tribe__Events__Tickets__Tickets.php
CHANGED
File without changes
|
src/deprecated/Tribe__Events__Tickets__Tickets_Pro.php
CHANGED
File without changes
|
src/resources/css/rsvp.css
CHANGED
@@ -23,12 +23,16 @@ table.tribe-events-tickets td {
|
|
23 |
border: 0;
|
24 |
}
|
25 |
|
|
|
|
|
|
|
|
|
26 |
.tribe-rsvp-messages {
|
|
|
27 |
padding: 10px 10px 5px;
|
28 |
}
|
29 |
|
30 |
.tribe-rsvp-message {
|
31 |
-
margin-bottom: 5px;
|
32 |
-khtml-border-radius: 3px;
|
33 |
-moz-border-radius: 3px;
|
34 |
-webkit-border-radius: 3px;
|
@@ -54,4 +58,4 @@ table.tribe-events-tickets td {
|
|
54 |
|
55 |
.tribe-ticket-quantity {
|
56 |
width: 100%;
|
57 |
-
}
|
23 |
border: 0;
|
24 |
}
|
25 |
|
26 |
+
.tribe-rsvp-message-display .tribe-rsvp-messages {
|
27 |
+
display: block;
|
28 |
+
}
|
29 |
+
|
30 |
.tribe-rsvp-messages {
|
31 |
+
display: none;
|
32 |
padding: 10px 10px 5px;
|
33 |
}
|
34 |
|
35 |
.tribe-rsvp-message {
|
|
|
36 |
-khtml-border-radius: 3px;
|
37 |
-moz-border-radius: 3px;
|
38 |
-webkit-border-radius: 3px;
|
58 |
|
59 |
.tribe-ticket-quantity {
|
60 |
width: 100%;
|
61 |
+
}
|
src/resources/css/rsvp.min.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.tribe-tickets-meta-row{display:none}.tribe-tickets-has-rsvp .tribe-tickets-meta-row{display:table-row}.tribe-tickets-attendee{padding:10px}table.tribe-events-tickets td{padding:8px 10px}.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee table,.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee td,.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee tr,.tribe-events-tickets .tribe-tickets-attendee table,.tribe-events-tickets .tribe-tickets-attendee td,.tribe-events-tickets .tribe-tickets-attendee tr{border:0}.tribe-rsvp-message-display .tribe-rsvp-messages{display:block}.tribe-rsvp-messages{display:none;padding:10px 10px 5px}.tribe-rsvp-message{border-radius:3px;border-style:solid;border-width:1px;font-family:Helvetica,Arial,sans;font-size:12px;margin:0 0 5px;padding:0 .6em}.tribe-rsvp-message-success{background-color:#ffffe0;border-color:#e6db55}.tribe-rsvp-message-error{background-color:#ffebe8;border-color:#c00}.tribe-ticket-quantity{width:100%}
|
src/resources/css/tickets-attendees-print.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
@media print{#adminmenuback,#adminmenuwrap,#icon-edit,#show-settings-link,#total_checkedin_wrapper,#wpfooter,.check-column,.column-check_in,.screen-meta-toggle,.tablenav,h2{display:none}.wrap h2+h2{display:block}#wpcontent,#wpfooter{margin-left:20px}#the-list tr{background:#fff;border:0;border-bottom:1px solid #333}a.row-title{color:#000}.widefat tfoot tr th,.widefat thead tr th{background:
|
1 |
+
@media print{#adminmenuback,#adminmenuwrap,#icon-edit,#show-settings-link,#total_checkedin_wrapper,#wpfooter,.check-column,.column-check_in,.screen-meta-toggle,.tablenav,h2{display:none}.wrap h2+h2{display:block}#wpcontent,#wpfooter{margin-left:20px}#the-list tr{background:#fff;border:0;border-bottom:1px solid #333}a.row-title{color:#000}.widefat tfoot tr th,.widefat thead tr th{background:none;text-shadow:none}.postbox h3{text-shadow:none}#total_tickets_sold{display:block}.ticket_list h4{font-size:13px}.ticket_list tr td{font-size:11px;line-height:15px}.ticket_list tr td .totals{width:75%;height:100px;padding-top:40px;line-height:30px}table{page-break-inside:auto}tr{page-break-inside:avoid;page-break-after:auto}thead{display:table-header-group}tfoot{display:table-footer-group}}
|
src/resources/css/tickets-attendees.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
|
1 |
+
#tribe-attendees-summary{padding-bottom:10px;position:relative}#tribe-attendees-summary .welcome-panel-column-container{position:initial}#tribe-attendees-summary .about-description,#tribe-attendees-summary h3{width:66%}#tribe-attendees-summary .about-description a{color:inherit}#tribe-attendees-summary .welcome-panel-column li{line-height:1.4em;margin-bottom:2px}#tribe-attendees-summary .welcome-panel-last{position:absolute;top:0;bottom:0;right:0;border-left:1px solid #eee;padding:10px 20px 5px;width:200px}#tribe-attendees-summary .welcome-panel-last h4{font-size:1.5em;text-align:center}#tribe-attendees-summary .welcome-panel-last li{font-size:1.2em}@media screen and (max-width:870px){#tribe-attendees-summary .about-description,#tribe-attendees-summary h3{width:100%}#tribe-attendees-summary .welcome-panel-column li{display:list-item}#tribe-attendees-summary .welcome-panel-column-container{margin-bottom:115px}#tribe-attendees-summary .welcome-panel-last{top:initial;bottom:0;left:0;right:0;border-top:1px solid #eee;border-left:0;width:100%}#tribe-attendees-summary .welcome-panel-last ul{float:left;width:50%}}@media screen and (min-width:870px){#tribe-attendees-summary .welcome-panel-last ul:first-child{margin-bottom:0}#tribe-attendees-summary .welcome-panel-last ul:last-child{margin-top:0}}.tribe-attendees-page .tickets_checked td{opacity:.7;text-decoration:line-through}.tribe-attendees-page .tickets_checked a.tickets_checkin{display:none}.tribe-attendees-page .tickets_checked td.column-check_in{text-decoration:none!important}.tribe-attendees-page a.tickets_uncheckin{display:none}.tribe-attendees-page .tickets_checked a.tickets_uncheckin{display:block}.tribe-attendees-page .column-attendee_id,.tribe-attendees-page .column-order_id{width:70px}.tribe-attendees-page .email,.tribe-attendees-page .export,.tribe-attendees-page .print{margin:1px 8px 0 0}@media screen and (max-width:782px){.tribe-attendees-email-message .notice-dismiss{padding:9px}}.tribe-attendees-email .button-primary{margin-top:3px}.tribe-attendees-email .tribe-attendees-email-message{float:left;margin:0}.tribe-attendees-email-message ul{margin:.5em 0;padding:2px;font-size:13px;line-height:1.5}.tribe-attendees-email-message ul li:last-child{margin-bottom:0}#attendees_email_wrapper{margin-top:10px;padding:20px;overflow:hidden}#attendees_email_wrapper label{display:block}#attendees_email_wrapper label span{display:inline-block;width:105px}#attendees_email_wrapper .attendees_or{text-align:center;display:block;font-size:20px;margin:20px 0}#attendees_email_wrapper input[type=text],#attendees_email_wrapper select{width:285px}
|
src/resources/css/tickets.css
CHANGED
@@ -47,6 +47,10 @@ p.ticket_name {
|
|
47 |
display : inline;
|
48 |
}
|
49 |
|
|
|
|
|
|
|
|
|
50 |
.ticket_form h4.ticket_form_title_edit {
|
51 |
display : none;
|
52 |
}
|
@@ -66,3 +70,19 @@ p.ticket_name {
|
|
66 |
.tribe-tickets-remaining {
|
67 |
font-size: 10px;
|
68 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
display : inline;
|
48 |
}
|
49 |
|
50 |
+
.ticket_form p.description.detailed-description {
|
51 |
+
display : block;
|
52 |
+
}
|
53 |
+
|
54 |
.ticket_form h4.ticket_form_title_edit {
|
55 |
display : none;
|
56 |
}
|
70 |
.tribe-tickets-remaining {
|
71 |
font-size: 10px;
|
72 |
}
|
73 |
+
|
74 |
+
.eventtable {
|
75 |
+
margin : 0;
|
76 |
+
padding-top : 0;
|
77 |
+
width : 100%;
|
78 |
+
}
|
79 |
+
|
80 |
+
#event_tickets, .eventtable.ticket_list.eventForm {
|
81 |
+
table-layout : fixed;
|
82 |
+
}
|
83 |
+
|
84 |
+
/* Specific goal of this rule is to prevent the number input busting the ticket form layout under Twenty Fifteen */
|
85 |
+
.tribe-theme-twentyfifteen .tribe-events-tickets input[type="number"] {
|
86 |
+
padding: 0.375em;
|
87 |
+
width: 100%;
|
88 |
+
}
|
src/resources/css/tickets.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
#ticket_form{display:none}#ticket_form input[type=radio]{margin-right:5px}#ticket_form span{margin-right:10px}.ticket_list tr td{padding:4px 7px 2px;vertical-align:top}.ticket_list tr td div.ticket_controls{visibility:hidden}.ticket_list tr:hover td div.ticket_controls{visibility:visible}.ticket_list h4{text-transform:uppercase;border-bottom:1px solid #e5e5e5;padding-bottom:6px}.ticket_list h4 a{font-weight:400;font-size:11px;text-transform:none}p.ticket_name{font-size:13px;font-weight:700}.ticket_form p.description{display:inline}.ticket_form h4.ticket_form_title_edit{display:none}#tribe_ticket_header_preview img{max-width:95%!important;height:auto!important}#tribe_ticket_header_remove,.ticket_time{display:none}.tribe-tickets-remaining
|
1 |
+
#ticket_form{display:none}#ticket_form input[type=radio]{margin-right:5px}#ticket_form span{margin-right:10px}.ticket_list tr td{padding:4px 7px 2px;vertical-align:top}.ticket_list tr td div.ticket_controls{visibility:hidden}.ticket_list tr:hover td div.ticket_controls{visibility:visible}.ticket_list h4{text-transform:uppercase;border-bottom:1px solid #e5e5e5;padding-bottom:6px}.ticket_list h4 a{font-weight:400;font-size:11px;text-transform:none}p.ticket_name{font-size:13px;font-weight:700}.ticket_form p.description{display:inline}.ticket_form p.description.detailed-description{display:block}.ticket_form h4.ticket_form_title_edit{display:none}#tribe_ticket_header_preview img{max-width:95%!important;height:auto!important}#tribe_ticket_header_remove,.ticket_time{display:none}.tribe-tickets-remaining{font-size:10px}.eventtable{margin:0;padding-top:0;width:100%}#event_tickets,.eventtable.ticket_list.eventForm{table-layout:fixed}.tribe-theme-twentyfifteen .tribe-events-tickets input[type=number]{padding:.375em;width:100%}
|
src/resources/js/frontend-ticket-form.js
ADDED
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
var tribe_tickets_ticket_form = {};
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Provides global stock handling for frontend ticket forms.
|
5 |
+
*
|
6 |
+
* @var object tribe_tickets_stock_data
|
7 |
+
*/
|
8 |
+
( function( $, my ) {
|
9 |
+
var $tickets_lists;
|
10 |
+
var $quantity_fields;
|
11 |
+
|
12 |
+
my.init = function() {
|
13 |
+
$tickets_lists = $( '.tribe-events-tickets' );
|
14 |
+
$quantity_fields = $tickets_lists.find( '.quantity' ).find( 'input' );
|
15 |
+
$quantity_fields.on( 'change', my.on_quantity_change );
|
16 |
+
};
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Every time a ticket quantity field is changed we should evaluate
|
20 |
+
* the new quantity and ensure it is still "in bounds" with relation
|
21 |
+
* to global stock.
|
22 |
+
*/
|
23 |
+
my.on_quantity_change = function() {
|
24 |
+
var $this = $( this );
|
25 |
+
var ticket_id = my.get_matching_ticket_id( this );
|
26 |
+
|
27 |
+
if ( my.ticket_uses_global_stock( ticket_id ) ) {
|
28 |
+
my.global_stock_quantity_changed( $this, ticket_id );
|
29 |
+
} else {
|
30 |
+
my.normal_stock_quantity_changed( $this, ticket_id );
|
31 |
+
}
|
32 |
+
};
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Handle updates and checks where the modified quantity selector belongs to
|
36 |
+
* a ticket that uses global stock.
|
37 |
+
*
|
38 |
+
* @param $input
|
39 |
+
* @param ticket_id
|
40 |
+
*/
|
41 |
+
my.global_stock_quantity_changed = function( $input, ticket_id ) {
|
42 |
+
var new_quantity = $input.val();
|
43 |
+
var event_id = my.get_event_id( ticket_id );
|
44 |
+
var ticket_cap = my.get_cap( ticket_id );
|
45 |
+
var event_stock = my.get_global_stock( event_id );
|
46 |
+
var total_requested = my.currently_requested_global_event_stock( event_id );
|
47 |
+
|
48 |
+
// If the total stock requested across all inputs now exceeds what's available, adjust this one
|
49 |
+
if ( total_requested > event_stock ) {
|
50 |
+
new_quantity -= total_requested - event_stock;
|
51 |
+
}
|
52 |
+
|
53 |
+
// If sales for this input have been capped, adjust if necessary to stay within the cap
|
54 |
+
if ( my.stock_mode_is_capped( ticket_id ) && new_quantity > ticket_cap ) {
|
55 |
+
new_quantity = ticket_cap;
|
56 |
+
}
|
57 |
+
|
58 |
+
// Do not let our adjustments take the new quantity below zero, however
|
59 |
+
if ( 0 >= new_quantity ) {
|
60 |
+
new_quantity = 0;
|
61 |
+
}
|
62 |
+
|
63 |
+
$input.val( new_quantity );
|
64 |
+
my.update_available_stock_counts( event_id );
|
65 |
+
};
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Handle updates and checks where the modified quantity selector belongs to
|
69 |
+
* a ticket that does not use global stock.
|
70 |
+
*
|
71 |
+
* @param $input
|
72 |
+
* @param ticket_id
|
73 |
+
*/
|
74 |
+
my.normal_stock_quantity_changed = function( $input, ticket_id ) {
|
75 |
+
var new_quantity = $input.val();
|
76 |
+
var available_stock = my.get_single_stock( ticket_id );
|
77 |
+
var remaining;
|
78 |
+
|
79 |
+
// Keep in check (should be handled for us by numeric inputs in most browsers, but let's be safe)
|
80 |
+
if ( new_quantity > available_stock ) {
|
81 |
+
new_quantity = available_stock;
|
82 |
+
}
|
83 |
+
|
84 |
+
// Update
|
85 |
+
$input.val( new_quantity );
|
86 |
+
remaining = available_stock - new_quantity;
|
87 |
+
$tickets_lists.find( '.available-stock[data-product-id=' + ticket_id + ']').html( remaining );
|
88 |
+
};
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Each ticket list typically shows the remaining inventory next to each
|
92 |
+
* quantity input. This method updates those counts appropriately.
|
93 |
+
*
|
94 |
+
* @param event_id
|
95 |
+
*/
|
96 |
+
my.update_available_stock_counts = function( event_id ) {
|
97 |
+
var tickets = my.get_tickets_of( event_id );
|
98 |
+
var remaining = my.get_global_stock( event_id ) - my.currently_requested_global_event_stock( event_id );
|
99 |
+
|
100 |
+
for ( var ticket_id in tickets ) {
|
101 |
+
if ( ! tickets.hasOwnProperty( ticket_id ) ) {
|
102 |
+
continue;
|
103 |
+
}
|
104 |
+
|
105 |
+
// Do not allow a sub-zero tickets remaining count
|
106 |
+
if ( remaining < 0 ) {
|
107 |
+
remaining = 0;
|
108 |
+
}
|
109 |
+
|
110 |
+
var ticket = tickets[ ticket_id ];
|
111 |
+
|
112 |
+
if ( 'global' === ticket.mode ) {
|
113 |
+
$tickets_lists.find( '.available-stock[data-product-id=' + ticket_id + ']').html( remaining );
|
114 |
+
}
|
115 |
+
|
116 |
+
if ( 'capped' === ticket.mode ) {
|
117 |
+
// If x units of global stock have been requested, the effective cap is the actual cap less value x
|
118 |
+
var effective_cap = Math.min( remaining, ticket.cap );
|
119 |
+
var requested_stock = parseInt( $( '[data-product-id=' + ticket_id + ']' ).find( 'input' ).val(), 10 );
|
120 |
+
var remaining_under_cap = ticket.cap - requested_stock;
|
121 |
+
|
122 |
+
// As with all other ticket types, capped tickets should not have a sub-zero count either
|
123 |
+
if ( remaining_under_cap < 0 ) {
|
124 |
+
remaining_under_cap = 0;
|
125 |
+
}
|
126 |
+
// Nor can their count exceed the effective cap
|
127 |
+
else if ( remaining_under_cap > effective_cap ) {
|
128 |
+
remaining_under_cap = effective_cap;
|
129 |
+
}
|
130 |
+
|
131 |
+
$tickets_lists.find( '.available-stock[data-product-id=' + ticket_id + ']').html( remaining_under_cap );
|
132 |
+
}
|
133 |
+
}
|
134 |
+
};
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Attempts to determine the product ID associated with the passed
|
138 |
+
* element.
|
139 |
+
*
|
140 |
+
* @param element
|
141 |
+
*
|
142 |
+
* @returns null|string
|
143 |
+
*/
|
144 |
+
my.get_matching_ticket_id = function( element ) {
|
145 |
+
// There should be an element close by (parent or grandparent) from which we can
|
146 |
+
// obtain the ticket ID
|
147 |
+
var $closest_identifier = $( element ).closest( '[data-product-id]' );
|
148 |
+
|
149 |
+
// Custom or legacy templates may mean this isn't possible - safely bail if necessary
|
150 |
+
if ( ! $closest_identifier.length ) {
|
151 |
+
return;
|
152 |
+
}
|
153 |
+
|
154 |
+
return $closest_identifier.data( 'product-id' );
|
155 |
+
};
|
156 |
+
|
157 |
+
/**
|
158 |
+
* If possible, returns the value of the specified ticket's property or
|
159 |
+
* false if it does not exist.
|
160 |
+
*
|
161 |
+
* @param ticket_id
|
162 |
+
* @param property
|
163 |
+
*
|
164 |
+
* @returns boolean|string
|
165 |
+
*/
|
166 |
+
my.get_ticket_property = function( ticket_id, property ) {
|
167 |
+
// Don't trigger errors if tribe_tickets_stock_data is not available
|
168 |
+
if ( "object" !== typeof tribe_tickets_stock_data ) {
|
169 |
+
return false;
|
170 |
+
}
|
171 |
+
|
172 |
+
var ticket = tribe_tickets_stock_data.tickets[ ticket_id ];
|
173 |
+
|
174 |
+
// If we don't have any data for this ticket we can assume it doesn't use global stock
|
175 |
+
if ( "undefined" === tribe_tickets_stock_data.tickets[ ticket_id ] ) {
|
176 |
+
return false;
|
177 |
+
}
|
178 |
+
|
179 |
+
return ticket[property];
|
180 |
+
};
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Provides an array of ticket objects that all belong to the specified
|
184 |
+
* event.
|
185 |
+
*
|
186 |
+
* @param event_id
|
187 |
+
*
|
188 |
+
* @returns Array
|
189 |
+
*/
|
190 |
+
my.get_tickets_of = function( event_id ) {
|
191 |
+
// Don't trigger errors if tribe_tickets_stock_data is not available
|
192 |
+
if ( "object" !== typeof tribe_tickets_stock_data ) {
|
193 |
+
return false;
|
194 |
+
}
|
195 |
+
|
196 |
+
var set_of_tickets = [];
|
197 |
+
|
198 |
+
for ( var ticket_id in tribe_tickets_stock_data.tickets ) {
|
199 |
+
var ticket = tribe_tickets_stock_data.tickets[ ticket_id ];
|
200 |
+
if ( event_id === ticket.event_id ) {
|
201 |
+
set_of_tickets[ ticket_id ] = ticket;
|
202 |
+
}
|
203 |
+
}
|
204 |
+
|
205 |
+
return set_of_tickets;
|
206 |
+
};
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Sum of all quantity inputs that have tickets drawing on the event's global stock.
|
210 |
+
*
|
211 |
+
* @param event_id
|
212 |
+
* @returns {number}
|
213 |
+
*/
|
214 |
+
my.currently_requested_global_event_stock = function( event_id ) {
|
215 |
+
var total = 0;
|
216 |
+
var tickets = my.get_tickets_of( event_id );
|
217 |
+
|
218 |
+
for ( var ticket_id in tickets ) {
|
219 |
+
switch ( tribe_tickets_stock_data.tickets[ticket_id].mode ) {
|
220 |
+
case 'global':
|
221 |
+
case 'capped':
|
222 |
+
total += parseInt( $tickets_lists.find( '[data-product-id=' + ticket_id + ']').find( 'input').val(), 10 );
|
223 |
+
break;
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
return total;
|
228 |
+
};
|
229 |
+
|
230 |
+
/**
|
231 |
+
* If possible, returns the value of the specified event's property or
|
232 |
+
* false if it does not exist.
|
233 |
+
*
|
234 |
+
* @param event_id
|
235 |
+
* @param property
|
236 |
+
*
|
237 |
+
* @returns boolean|string
|
238 |
+
*/
|
239 |
+
my.get_event_property = function( event_id, property ) {
|
240 |
+
// Don't trigger errors if tribe_tickets_stock_data is not available
|
241 |
+
if ( "object" !== typeof tribe_tickets_stock_data ) {
|
242 |
+
return false;
|
243 |
+
}
|
244 |
+
|
245 |
+
var event = tribe_tickets_stock_data.events[ event_id ];
|
246 |
+
|
247 |
+
// If we don't have any data for this ticket we can assume it doesn't use global stock
|
248 |
+
if ( "undefined" === tribe_tickets_stock_data.events[ event_id ] ) {
|
249 |
+
return false;
|
250 |
+
}
|
251 |
+
|
252 |
+
return event[property];
|
253 |
+
};
|
254 |
+
|
255 |
+
my.stock_mode_is_global = function( ticket_id ) {
|
256 |
+
return "global" === my.get_mode( ticket_id );
|
257 |
+
};
|
258 |
+
|
259 |
+
my.stock_mode_is_capped = function( ticket_id ) {
|
260 |
+
return "capped" === my.get_mode( ticket_id );
|
261 |
+
};
|
262 |
+
|
263 |
+
my.ticket_uses_global_stock = function( ticket_id ) {
|
264 |
+
return my.stock_mode_is_capped( ticket_id ) || my.stock_mode_is_global( ticket_id );
|
265 |
+
};
|
266 |
+
|
267 |
+
my.get_mode = function( ticket_id ) {
|
268 |
+
return my.get_ticket_property( ticket_id, 'mode' );
|
269 |
+
};
|
270 |
+
|
271 |
+
my.get_event_id = function( ticket_id ) {
|
272 |
+
return my.get_ticket_property( ticket_id, 'event_id' );
|
273 |
+
};
|
274 |
+
|
275 |
+
my.get_cap = function( ticket_id ) {
|
276 |
+
return my.get_ticket_property( ticket_id, 'cap' );
|
277 |
+
};
|
278 |
+
|
279 |
+
my.get_global_stock = function( event_id ) {
|
280 |
+
return my.get_event_property( event_id, 'stock' );
|
281 |
+
};
|
282 |
+
|
283 |
+
my.get_single_stock = function( ticket_id ) {
|
284 |
+
return my.get_ticket_property( ticket_id, 'stock' );
|
285 |
+
};
|
286 |
+
|
287 |
+
$( function() {
|
288 |
+
my.init();
|
289 |
+
} );
|
290 |
+
} )( jQuery, tribe_tickets_ticket_form );
|
src/resources/js/frontend-ticket-form.min.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
var tribe_tickets_ticket_form={};!function(t,e){var _,i;e.init=function(){_=t(".tribe-events-tickets"),i=_.find(".quantity").find("input"),i.on("change",e.on_quantity_change)},e.on_quantity_change=function(){var _=t(this),i=e.get_matching_ticket_id(this);e.ticket_uses_global_stock(i)?e.global_stock_quantity_changed(_,i):e.normal_stock_quantity_changed(_,i)},e.global_stock_quantity_changed=function(t,_){var i=t.val(),c=e.get_event_id(_),a=e.get_cap(_),n=e.get_global_stock(c),o=e.currently_requested_global_event_stock(c);o>n&&(i-=o-n),e.stock_mode_is_capped(_)&&i>a&&(i=a),0>=i&&(i=0),t.val(i),e.update_available_stock_counts(c)},e.normal_stock_quantity_changed=function(t,i){var c,a=t.val(),n=e.get_single_stock(i);a>n&&(a=n),t.val(a),c=n-a,_.find(".available-stock[data-product-id="+i+"]").html(c)},e.update_available_stock_counts=function(i){var c=e.get_tickets_of(i),a=e.get_global_stock(i)-e.currently_requested_global_event_stock(i);for(var n in c)if(c.hasOwnProperty(n)){0>a&&(a=0);var o=c[n];if("global"===o.mode&&_.find(".available-stock[data-product-id="+n+"]").html(a),"capped"===o.mode){var r=Math.min(a,o.cap),s=parseInt(t("[data-product-id="+n+"]").find("input").val(),10),d=o.cap-s;0>d?d=0:d>r&&(d=r),_.find(".available-stock[data-product-id="+n+"]").html(d)}}},e.get_matching_ticket_id=function(e){var _=t(e).closest("[data-product-id]");if(_.length)return _.data("product-id")},e.get_ticket_property=function(t,e){if("object"!=typeof tribe_tickets_stock_data)return!1;var _=tribe_tickets_stock_data.tickets[t];return"undefined"===tribe_tickets_stock_data.tickets[t]?!1:_[e]},e.get_tickets_of=function(t){if("object"!=typeof tribe_tickets_stock_data)return!1;var e=[];for(var _ in tribe_tickets_stock_data.tickets){var i=tribe_tickets_stock_data.tickets[_];t===i.event_id&&(e[_]=i)}return e},e.currently_requested_global_event_stock=function(t){var i=0,c=e.get_tickets_of(t);for(var a in c)switch(tribe_tickets_stock_data.tickets[a].mode){case"global":case"capped":i+=parseInt(_.find("[data-product-id="+a+"]").find("input").val(),10)}return i},e.get_event_property=function(t,e){if("object"!=typeof tribe_tickets_stock_data)return!1;var _=tribe_tickets_stock_data.events[t];return"undefined"===tribe_tickets_stock_data.events[t]?!1:_[e]},e.stock_mode_is_global=function(t){return"global"===e.get_mode(t)},e.stock_mode_is_capped=function(t){return"capped"===e.get_mode(t)},e.ticket_uses_global_stock=function(t){return e.stock_mode_is_capped(t)||e.stock_mode_is_global(t)},e.get_mode=function(t){return e.get_ticket_property(t,"mode")},e.get_event_id=function(t){return e.get_ticket_property(t,"event_id")},e.get_cap=function(t){return e.get_ticket_property(t,"cap")},e.get_global_stock=function(t){return e.get_event_property(t,"stock")},e.get_single_stock=function(t){return e.get_ticket_property(t,"stock")},t(function(){e.init()})}(jQuery,tribe_tickets_ticket_form);
|
src/resources/js/rsvp.js
CHANGED
@@ -11,6 +11,9 @@ var tribe_tickets_rsvp = {
|
|
11 |
this.attendee_template = $( document.getElementById( 'tribe-tickets-rsvp-tmpl' ) ).html();
|
12 |
|
13 |
this.$rsvp.on( 'change', '.tribe-ticket-quantity', this.event.quantity_changed );
|
|
|
|
|
|
|
14 |
};
|
15 |
|
16 |
my.quantity_changed = function( $quantity ) {
|
@@ -25,10 +28,36 @@ var tribe_tickets_rsvp = {
|
|
25 |
}
|
26 |
};
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
my.event.quantity_changed = function() {
|
29 |
my.quantity_changed( $( this ) );
|
30 |
};
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
$( function() {
|
33 |
my.init();
|
34 |
} );
|
11 |
this.attendee_template = $( document.getElementById( 'tribe-tickets-rsvp-tmpl' ) ).html();
|
12 |
|
13 |
this.$rsvp.on( 'change', '.tribe-ticket-quantity', this.event.quantity_changed );
|
14 |
+
|
15 |
+
this.$rsvp.closest( '.cart' )
|
16 |
+
.on( 'submit', this.event.handle_submission );
|
17 |
};
|
18 |
|
19 |
my.quantity_changed = function( $quantity ) {
|
28 |
}
|
29 |
};
|
30 |
|
31 |
+
my.validate_submission = function() {
|
32 |
+
var $name = $( document.getElementById( 'tribe-tickets-full-name' ) );
|
33 |
+
var $email = $( document.getElementById( 'tribe-tickets-email' ) );
|
34 |
+
|
35 |
+
if ( ! $.trim( $name.val() ).length || ! $.trim( $email.val() ).length ) {
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
|
39 |
+
return true;
|
40 |
+
};
|
41 |
+
|
42 |
my.event.quantity_changed = function() {
|
43 |
my.quantity_changed( $( this ) );
|
44 |
};
|
45 |
|
46 |
+
my.event.handle_submission = function( e ) {
|
47 |
+
if ( ! my.validate_submission() ) {
|
48 |
+
e.preventDefault();
|
49 |
+
var $form = $( this ).closest( 'form' );
|
50 |
+
|
51 |
+
$form.addClass( 'tribe-rsvp-message-display' );
|
52 |
+
$form.find( '.tribe-rsvp-message-confirmation-error' ).show();
|
53 |
+
|
54 |
+
$( 'html, body').animate({
|
55 |
+
scrollTop: $form.offset().top
|
56 |
+
}, 300 );
|
57 |
+
return false;
|
58 |
+
}
|
59 |
+
};
|
60 |
+
|
61 |
$( function() {
|
62 |
my.init();
|
63 |
} );
|
src/resources/js/rsvp.min.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
var tribe_tickets_rsvp={num_attendees:0,event:{}};!function(
|
1 |
+
var tribe_tickets_rsvp={num_attendees:0,event:{}};!function(t,e){"use strict";e.init=function(){this.$rsvp=t(".tribe-events-tickets-rsvp"),this.attendee_template=t(document.getElementById("tribe-tickets-rsvp-tmpl")).html(),this.$rsvp.on("change",".tribe-ticket-quantity",this.event.quantity_changed),this.$rsvp.closest(".cart").on("submit",this.event.handle_submission)},e.quantity_changed=function(t){var e=t.closest(".tribe-events-tickets-rsvp"),s=parseInt(t.val(),10);s?e.addClass("tribe-tickets-has-rsvp"):e.removeClass("tribe-tickets-has-rsvp")},e.validate_submission=function(){var e=t(document.getElementById("tribe-tickets-full-name")),s=t(document.getElementById("tribe-tickets-email"));return!(!t.trim(e.val()).length||!t.trim(s.val()).length)},e.event.quantity_changed=function(){e.quantity_changed(t(this))},e.event.handle_submission=function(s){if(!e.validate_submission()){s.preventDefault();var i=t(this).closest("form");return i.addClass("tribe-rsvp-message-display"),i.find(".tribe-rsvp-message-confirmation-error").show(),t("html, body").animate({scrollTop:i.offset().top},300),!1}},t(function(){e.init()})}(jQuery,tribe_tickets_rsvp);
|
src/resources/js/tickets-attendees.min.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
jQuery(document).ready(function(
|
1 |
+
jQuery(document).ready(function(e){if(AttendeesPointer){options=e.extend(AttendeesPointer.options,{close:function(){e.post(ajaxurl,{pointer:AttendeesPointer.pointer_id,action:"dismiss-wp-pointer"})},open:function(e,t){t.pointer.css({top:parseInt(t.pointer.css("top").replace("px",""),10)+5}).find(".wp-pointer-arrow").css({right:"50px",left:"auto"}),t.element.on({click:function(){t.element.pointer("close")}})}});e(AttendeesPointer.target).pointer(options).pointer("open").pointer("widget")}e("input.print").on("click",function(e){window.print()});var t=e(document.getElementById("filter_attendee"));t.on("keydown",function(e){return 13===e.keyCode?!1:void 0}),t.on("keyup paste",function(){var t=jQuery(this).val().toLowerCase();e("#the-list").find("tr").each(function(n,i){var r=e(i),o=r.children("td.order_id").children("a").text(),c=r.children("td.attendee_id").text(),d=r.children("td.security").text(),a=0===c.indexOf(t)||0===o.indexOf(t)||0===d.indexOf(t),s=r.children("td.purchaser_name").text().toLowerCase(),p=0===s.indexOf(t)||s.indexOf(" "+t)>1;a||p?r.show():r.hide()})}),e(".tribe-attendees-email").on({submit:function(t){e(".tribe-attendees-email").hide(),e(document.getElementById("tribe-loading")).show()}}),e(".tickets_checkin").click(function(t){var n=jQuery(this),i={action:"tribe-ticket-checkin-"+n.attr("data-provider"),provider:n.attr("data-provider"),order_ID:n.attr("data-attendee-id"),nonce:Attendees.checkin_nonce};e.post(ajaxurl,i,function(t){t.success&&(n.parent("td").parent("tr").addClass("tickets_checked"),e("#total_checkedin").text(parseInt(e("#total_checkedin").text())+1))},"json"),t.preventDefault()}),e(".tickets_uncheckin").click(function(t){var n=jQuery(this),i={action:"tribe-ticket-uncheckin-"+n.attr("data-provider"),provider:n.attr("data-provider"),order_ID:n.attr("data-attendee-id"),nonce:Attendees.uncheckin_nonce};e.post(ajaxurl,i,function(t){t.success&&(n.parent("span").parent("td").parent("tr").removeClass("tickets_checked"),e("#total_checkedin").text(parseInt(e("#total_checkedin").text())-1))},"json"),t.preventDefault()})});
|
src/resources/js/tickets.js
CHANGED
@@ -47,6 +47,9 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
47 |
var $event_pickers = $( '#tribe-event-datepickers' ),
|
48 |
$tribe_tickets = $( '#tribetickets' ),
|
49 |
$tickets_container = $( '#event_tickets' ),
|
|
|
|
|
|
|
50 |
$body = $( 'html, body' ),
|
51 |
startofweek = 0;
|
52 |
|
@@ -81,13 +84,16 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
81 |
*/
|
82 |
'clear.tribe': function() {
|
83 |
var $this = $( this ),
|
84 |
-
$ticket_form = $this.find( '#ticket_form'
|
|
|
85 |
|
86 |
$this.find( 'a#ticket_form_toggle' ).show();
|
87 |
|
88 |
-
$
|
89 |
-
$
|
90 |
-
$
|
|
|
|
|
91 |
|
92 |
// some fields may have a default value we don't want to lose after clearing the form
|
93 |
$this.find( 'input[data-default-value]' ).each( function() {
|
@@ -105,6 +111,9 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
105 |
.siblings( '.no-update-message' ).html( '' ).hide()
|
106 |
.end().siblings( '.description' ).show();
|
107 |
|
|
|
|
|
|
|
108 |
$ticket_form.hide();
|
109 |
},
|
110 |
|
@@ -128,7 +137,7 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
128 |
'set-advanced-fields.tribe': function() {
|
129 |
var $this = $( this );
|
130 |
var $ticket_form = $this.find( '#ticket_form' );
|
131 |
-
var $ticket_advanced = $ticket_form.find( 'tr.ticket_advanced' ).find( 'input, select, textarea' );
|
132 |
var provider = $ticket_form.find( '#ticket_provider:checked' ).val();
|
133 |
|
134 |
// for each advanded ticket input, select, and textarea, relocate the name and id fields a bit
|
@@ -155,8 +164,57 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
155 |
} );
|
156 |
}
|
157 |
} );
|
158 |
-
}
|
159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
} );
|
161 |
|
162 |
if ( $event_pickers.length ) {
|
@@ -207,20 +265,61 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
207 |
}
|
208 |
} );
|
209 |
|
210 |
-
|
211 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
$( 'tr.ticket_advanced' ).hide();
|
|
|
213 |
$tribe_tickets.trigger( 'set-advanced-fields.tribe' );
|
214 |
-
$(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
} );
|
216 |
|
217 |
/* Show the advanced metabox for the selected provider and hide the others at ready */
|
218 |
$( 'input[name=ticket_provider]:checked' ).each( function() {
|
219 |
-
|
220 |
-
$ticket_advanced.hide()
|
221 |
-
.filter( 'tr.ticket_advanced_' + this.value )
|
222 |
-
.not( '.sale_price' )
|
223 |
-
.show();
|
224 |
} );
|
225 |
|
226 |
/* "Add a ticket" link action */
|
@@ -233,6 +332,7 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
233 |
.trigger( 'set-advanced-fields.tribe' )
|
234 |
.trigger( 'focus.tribe' );
|
235 |
$( '#ticket_form' ).show();
|
|
|
236 |
e.preventDefault();
|
237 |
} );
|
238 |
|
@@ -248,7 +348,7 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
248 |
$( '#ticket_form_save' ).click( function( e ) {
|
249 |
var $form = $( '#ticket_form_table' ),
|
250 |
type = $form.find( '#ticket_provider:checked' ).val(),
|
251 |
-
$rows = $form.find( '.ticket, .ticket_advanced_' + type );
|
252 |
|
253 |
$tribe_tickets.trigger( 'save-ticket.tribe', e ).trigger( 'spin.tribe', 'start' );
|
254 |
|
@@ -267,7 +367,7 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
267 |
|
268 |
if ( response.success ) {
|
269 |
$tribe_tickets.trigger( 'clear.tribe' );
|
270 |
-
$( 'td.ticket_list_container' ).empty().html( response.data );
|
271 |
$( '.ticket_time' ).hide();
|
272 |
}
|
273 |
},
|
@@ -429,9 +529,13 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
429 |
'name': '',
|
430 |
'id': ''
|
431 |
} );
|
432 |
-
$( 'tr.
|
433 |
$( 'tr.ticket.bottom' ).before( response.data.advanced_fields );
|
434 |
|
|
|
|
|
|
|
|
|
435 |
// set the prices after the advanced fields have been added to the form
|
436 |
var $ticket_price = $tribe_tickets.find( '#ticket_price' );
|
437 |
$ticket_price.val( regularPrice );
|
@@ -467,14 +571,16 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
467 |
$( '#ticket_purchase_limit' ).val( response.data.purchase_limit );
|
468 |
}
|
469 |
|
470 |
-
$( 'input:radio[name=ticket_provider]' ).filter( '[value=' + response.data.provider_class + ']' ).click();
|
471 |
-
|
472 |
$tribe_tickets.find( '.bumpdown-trigger' ).bumpdown();
|
473 |
$tribe_tickets.find( '.bumpdown' ).hide();
|
474 |
|
475 |
$( 'a#ticket_form_toggle' ).hide();
|
476 |
$( '#ticket_form' ).show();
|
477 |
|
|
|
|
|
|
|
|
|
478 |
},
|
479 |
'json'
|
480 |
).complete( function() {
|
@@ -495,6 +601,39 @@ var ticketHeaderImage = window.ticketHeaderImage || {};
|
|
495 |
$remove.show();
|
496 |
}
|
497 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
498 |
$('body').on( 'click', '#tribe_ticket_header_remove', function( e ) {
|
499 |
|
500 |
e.preventDefault();
|
47 |
var $event_pickers = $( '#tribe-event-datepickers' ),
|
48 |
$tribe_tickets = $( '#tribetickets' ),
|
49 |
$tickets_container = $( '#event_tickets' ),
|
50 |
+
$enable_global_stock = $( "#tribe-tickets-enable-global-stock" ),
|
51 |
+
$global_stock_level = $( "#tribe-tickets-global-stock-level" ),
|
52 |
+
global_stock_setting_changed = false,
|
53 |
$body = $( 'html, body' ),
|
54 |
startofweek = 0;
|
55 |
|
84 |
*/
|
85 |
'clear.tribe': function() {
|
86 |
var $this = $( this ),
|
87 |
+
$ticket_form = $this.find( '#ticket_form'),
|
88 |
+
$ticket_settings = $ticket_form.find( "tr:not(.event-wide-settings)" );
|
89 |
|
90 |
$this.find( 'a#ticket_form_toggle' ).show();
|
91 |
|
92 |
+
$ticket_settings.find( 'input:not(:button):not(:radio):not(:checkbox):not([type="hidden"]), textarea' ).val( '' );
|
93 |
+
$ticket_settings.find( 'input:checkbox' ).attr( 'checked', false );
|
94 |
+
$ticket_settings.find( '#ticket_id' ).val( '' );
|
95 |
+
|
96 |
+
$this.find( '#ticket_form input[name="show_attendee_info"]' ).prop( 'checked', false ).change();
|
97 |
|
98 |
// some fields may have a default value we don't want to lose after clearing the form
|
99 |
$this.find( 'input[data-default-value]' ).each( function() {
|
111 |
.siblings( '.no-update-message' ).html( '' ).hide()
|
112 |
.end().siblings( '.description' ).show();
|
113 |
|
114 |
+
$('#tribe-tickets-attendee-sortables').empty();
|
115 |
+
$('.tribe-tickets-attendee-saved-fields').show();
|
116 |
+
|
117 |
$ticket_form.hide();
|
118 |
},
|
119 |
|
137 |
'set-advanced-fields.tribe': function() {
|
138 |
var $this = $( this );
|
139 |
var $ticket_form = $this.find( '#ticket_form' );
|
140 |
+
var $ticket_advanced = $ticket_form.find( 'tr.ticket_advanced:not(.ticket_advanced_meta)' ).find( 'input, select, textarea' );
|
141 |
var provider = $ticket_form.find( '#ticket_provider:checked' ).val();
|
142 |
|
143 |
// for each advanded ticket input, select, and textarea, relocate the name and id fields a bit
|
164 |
} );
|
165 |
}
|
166 |
} );
|
|
|
167 |
|
168 |
+
// (Re-)set the global stock fields
|
169 |
+
$tribe_tickets.trigger( 'set-global-stock-fields.tribe' );
|
170 |
+
|
171 |
+
// Also reset each time the global stock mode selector is changed
|
172 |
+
$( '#ticket_global_stock' ).change( function() {
|
173 |
+
$tribe_tickets.trigger( 'set-global-stock-fields.tribe' );
|
174 |
+
});
|
175 |
+
},
|
176 |
+
|
177 |
+
'set-global-stock-fields.tribe': function() {
|
178 |
+
var provider_class = currently_selected_provider();
|
179 |
+
var $provider_fields = $( this ).find( '#ticket_form').find( '.ticket_advanced_' + provider_class );
|
180 |
+
|
181 |
+
if ( $provider_fields.length < 1 ) {
|
182 |
+
return;
|
183 |
+
}
|
184 |
+
|
185 |
+
var $normal_stock_field = $provider_fields.filter( '.stock' );
|
186 |
+
var $global_stock_fields = $provider_fields.filter( '.global-stock-mode' );
|
187 |
+
var $sales_cap_field = $global_stock_fields.filter( '.sales-cap-field' );
|
188 |
+
|
189 |
+
var mode = $( '#ticket_global_stock' ).val();
|
190 |
+
var enabled = global_stock_enabled();
|
191 |
+
|
192 |
+
// Show or hide global (and normal, "per-ticket") stock settings as appropriate
|
193 |
+
$global_stock_level.toggle( enabled );
|
194 |
+
$global_stock_fields.toggle( global_stock_enabled() );
|
195 |
+
$normal_stock_field.toggle( ! enabled );
|
196 |
+
|
197 |
+
// If global stock is not enabled we need go no further
|
198 |
+
if ( ! enabled ) {
|
199 |
+
return;
|
200 |
+
}
|
201 |
+
|
202 |
+
// Otherwise, toggle on and off the relevant stock quantity fields
|
203 |
+
switch ( mode ) {
|
204 |
+
case "global":
|
205 |
+
$sales_cap_field.hide();
|
206 |
+
$normal_stock_field.hide();
|
207 |
+
break;
|
208 |
+
case "capped":
|
209 |
+
$sales_cap_field.show();
|
210 |
+
$normal_stock_field.hide();
|
211 |
+
break;
|
212 |
+
case "own":
|
213 |
+
$sales_cap_field.hide();
|
214 |
+
$normal_stock_field.show();
|
215 |
+
break;
|
216 |
+
}
|
217 |
+
}
|
218 |
} );
|
219 |
|
220 |
if ( $event_pickers.length ) {
|
265 |
}
|
266 |
} );
|
267 |
|
268 |
+
/**
|
269 |
+
* Indicates if the "enable global stock" field has been checked.
|
270 |
+
*
|
271 |
+
* @returns boolean
|
272 |
+
*/
|
273 |
+
function global_stock_enabled() {
|
274 |
+
return $enable_global_stock.prop( "checked" );
|
275 |
+
}
|
276 |
+
|
277 |
+
/**
|
278 |
+
* Show or hide global stock fields and settings as appropriate.
|
279 |
+
*/
|
280 |
+
function show_hide_global_stock() {
|
281 |
+
global_stock_setting_changed = true;
|
282 |
+
$tribe_tickets.trigger( 'set-global-stock-fields.tribe' );
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Show or hide the appropriate set of provider-specific fields.
|
287 |
+
*/
|
288 |
+
function show_hide_advanced_fields() {
|
289 |
$( 'tr.ticket_advanced' ).hide();
|
290 |
+
$( 'tr.ticket_advanced_' + currently_selected_provider() + ':not(.sale_price)' ).show();
|
291 |
$tribe_tickets.trigger( 'set-advanced-fields.tribe' );
|
292 |
+
$( document.getElementById( 'tribetickets' ) ).trigger( 'ticket-provider-changed.tribe' );
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Returns the currently selected ticketing provider.
|
297 |
+
*
|
298 |
+
* @return string
|
299 |
+
*/
|
300 |
+
function currently_selected_provider() {
|
301 |
+
var $checked_provider = $( 'input[name="ticket_provider"]:checked' );
|
302 |
+
return ( $checked_provider.length > 0 )
|
303 |
+
? $checked_provider[0].value
|
304 |
+
: "";
|
305 |
+
}
|
306 |
+
|
307 |
+
// Show or hide the global stock level as appropriate, both initially and thereafter
|
308 |
+
$enable_global_stock.change( show_hide_global_stock );
|
309 |
+
$enable_global_stock.trigger( 'change' );
|
310 |
+
|
311 |
+
// Triggering a change event will falsely set the global_stock_setting_changed flag to
|
312 |
+
// true - undo this as it is a one-time false positive
|
313 |
+
global_stock_setting_changed = false;
|
314 |
+
|
315 |
+
/* Show the advanced metabox for the selected provider and hide the others on selection change */
|
316 |
+
$( 'input[name=ticket_provider]:radio' ).change( function() {
|
317 |
+
show_hide_advanced_fields();
|
318 |
} );
|
319 |
|
320 |
/* Show the advanced metabox for the selected provider and hide the others at ready */
|
321 |
$( 'input[name=ticket_provider]:checked' ).each( function() {
|
322 |
+
show_hide_advanced_fields();
|
|
|
|
|
|
|
|
|
323 |
} );
|
324 |
|
325 |
/* "Add a ticket" link action */
|
332 |
.trigger( 'set-advanced-fields.tribe' )
|
333 |
.trigger( 'focus.tribe' );
|
334 |
$( '#ticket_form' ).show();
|
335 |
+
$( document.getElementById( 'tribetickets' ) ).trigger( 'ticket-provider-changed.tribe' );
|
336 |
e.preventDefault();
|
337 |
} );
|
338 |
|
348 |
$( '#ticket_form_save' ).click( function( e ) {
|
349 |
var $form = $( '#ticket_form_table' ),
|
350 |
type = $form.find( '#ticket_provider:checked' ).val(),
|
351 |
+
$rows = $form.find( '.ticket, .ticket_advanced_meta, .ticket_advanced_' + type );
|
352 |
|
353 |
$tribe_tickets.trigger( 'save-ticket.tribe', e ).trigger( 'spin.tribe', 'start' );
|
354 |
|
367 |
|
368 |
if ( response.success ) {
|
369 |
$tribe_tickets.trigger( 'clear.tribe' );
|
370 |
+
$( 'td.ticket_list_container' ).empty().html( response.data.html );
|
371 |
$( '.ticket_time' ).hide();
|
372 |
}
|
373 |
},
|
529 |
'name': '',
|
530 |
'id': ''
|
531 |
} );
|
532 |
+
$( 'tr.ticket_advanced' ).remove();
|
533 |
$( 'tr.ticket.bottom' ).before( response.data.advanced_fields );
|
534 |
|
535 |
+
// trigger a change event on the provider radio input so the advanced fields can be re-initialized
|
536 |
+
$( 'input:radio[name=ticket_provider]' ).filter( '[value=' + response.data.provider_class + ']' ).click();
|
537 |
+
$( 'input[name=ticket_provider]:radio' ).change();
|
538 |
+
|
539 |
// set the prices after the advanced fields have been added to the form
|
540 |
var $ticket_price = $tribe_tickets.find( '#ticket_price' );
|
541 |
$ticket_price.val( regularPrice );
|
571 |
$( '#ticket_purchase_limit' ).val( response.data.purchase_limit );
|
572 |
}
|
573 |
|
|
|
|
|
574 |
$tribe_tickets.find( '.bumpdown-trigger' ).bumpdown();
|
575 |
$tribe_tickets.find( '.bumpdown' ).hide();
|
576 |
|
577 |
$( 'a#ticket_form_toggle' ).hide();
|
578 |
$( '#ticket_form' ).show();
|
579 |
|
580 |
+
$tribe_tickets
|
581 |
+
.trigger( 'set-advanced-fields.tribe' )
|
582 |
+
.trigger( 'edit-ticket.tribe' );
|
583 |
+
|
584 |
},
|
585 |
'json'
|
586 |
).complete( function() {
|
601 |
$remove.show();
|
602 |
}
|
603 |
|
604 |
+
/**
|
605 |
+
* Track changes to the global stock level. Changes to the global stock
|
606 |
+
* checkbox itself is handled elsewhere.
|
607 |
+
*/
|
608 |
+
$global_stock_level.change( function() {
|
609 |
+
global_stock_setting_changed = true;
|
610 |
+
} );
|
611 |
+
|
612 |
+
/**
|
613 |
+
* Unset the global stock settings changed flag if the post is being
|
614 |
+
* saved/updated (no need to trigger a confirmation dialog in these
|
615 |
+
* cases).
|
616 |
+
*/
|
617 |
+
$( 'input[type="submit"]' ).click( function() {
|
618 |
+
global_stock_setting_changed = false;
|
619 |
+
} );
|
620 |
+
|
621 |
+
/**
|
622 |
+
* If the user attempts to nav away without saving global stock setting
|
623 |
+
* changes then try to bring this to their attention!
|
624 |
+
*/
|
625 |
+
$( window ).on( 'beforeunload', function() {
|
626 |
+
// If the global stock settings have not changed, do not interfere
|
627 |
+
if ( ! global_stock_setting_changed ) {
|
628 |
+
return;
|
629 |
+
}
|
630 |
+
|
631 |
+
// We can't trigger a confirm() dialog from within this action but returning
|
632 |
+
// a string should achieve effectively the same result
|
633 |
+
return tribe_global_stock_admin_ui.nav_away_msg;
|
634 |
+
|
635 |
+
} );
|
636 |
+
|
637 |
$('body').on( 'click', '#tribe_ticket_header_remove', function( e ) {
|
638 |
|
639 |
e.preventDefault();
|
src/resources/js/tickets.min.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
var ticketHeaderImage=window.ticketHeaderImage||{};!function(
|
1 |
+
var ticketHeaderImage=window.ticketHeaderImage||{};!function(t,e,i){"use strict";ticketHeaderImage={uploader:function(){var t=wp.media({title:HeaderImageData.title,multiple:!1,library:{type:"image"},button:{text:HeaderImageData.button}});return t.on("close",function(){var e=t.state().get("selection").toJSON();e.length&&ticketHeaderImage.render(e[0])}),t.open(),!1},render:function(t){e("#tribe_ticket_header_preview").html(ticketHeaderImage.imgHTML(t)),e("#tribe_ticket_header_image_id").val(t.id),e("#tribe_ticket_header_remove").show()},imgHTML:function(t){var e='<img src="'+t.url+'" ';return e+='width="'+t.width+'" ',e+='height="'+t.height+'" ',e+="/>"}},e(document).ready(function(){function i(){return s.prop("checked")}function a(){l=!0,c.trigger("set-global-stock-fields.tribe")}function r(){e("tr.ticket_advanced").hide(),e("tr.ticket_advanced_"+n()+":not(.sale_price)").show(),c.trigger("set-advanced-fields.tribe"),e(document.getElementById("tribetickets")).trigger("ticket-provider-changed.tribe")}function n(){var t=e('input[name="ticket_provider"]:checked');return t.length>0?t[0].value:""}var d=e("#tribe-event-datepickers"),c=e("#tribetickets"),o=e("#event_tickets"),s=e("#tribe-tickets-enable-global-stock"),_=e("#tribe-tickets-global-stock-level"),l=!1,k=e("html, body"),g=0;c.on({"spin.tribe":function(t,i){("undefined"==typeof i||e.inArray(i,["start","stop"]))&&(i="stop"),"stop"===i?o.css("opacity","1").find("#tribe-loading").hide():o.css("opacity","0.5").find("#tribe-loading").show()},"clear.tribe":function(){var t=e(this),i=t.find("#ticket_form"),a=i.find("tr:not(.event-wide-settings)");t.find("a#ticket_form_toggle").show(),a.find('input:not(:button):not(:radio):not(:checkbox):not([type="hidden"]), textarea').val(""),a.find("input:checkbox").attr("checked",!1),a.find("#ticket_id").val(""),t.find('#ticket_form input[name="show_attendee_info"]').prop("checked",!1).change(),t.find("input[data-default-value]").each(function(){var t=e(this);t.val(t.data("default-value"))}),t.find("#ticket_start_date").datepicker("option","maxDate",null),t.find("#ticket_end_date").datepicker("option","minDate",null),t.find(".ticket_start_time, .ticket_end_time, .ticket.sale_price").hide(),t.find("#ticket_price").removeProp("disabled").siblings(".no-update-message").html("").hide().end().siblings(".description").show(),e("#tribe-tickets-attendee-sortables").empty(),e(".tribe-tickets-attendee-saved-fields").show(),i.hide()},"focus.tribe":function(){k.animate({scrollTop:o.offset().top-50},500)},"set-advanced-fields.tribe":function(){var t=e(this),i=t.find("#ticket_form"),a=i.find("tr.ticket_advanced:not(.ticket_advanced_meta)").find("input, select, textarea"),r=i.find("#ticket_provider:checked").val();a.each(function(){var t=e(this);t.attr("name")&&t.data("name",t.attr("name")).attr({name:"",id:""}),t.closest("tr").hasClass("ticket_advanced_"+r)&&t.data("name")&&0===t.attr("name").length&&t.attr({name:t.data("name"),id:t.data("name")})}),c.trigger("set-global-stock-fields.tribe"),e("#ticket_global_stock").change(function(){c.trigger("set-global-stock-fields.tribe")})},"set-global-stock-fields.tribe":function(){var t=n(),a=e(this).find("#ticket_form").find(".ticket_advanced_"+t);if(!(a.length<1)){var r=a.filter(".stock"),d=a.filter(".global-stock-mode"),c=d.filter(".sales-cap-field"),o=e("#ticket_global_stock").val(),s=i();if(_.toggle(s),d.toggle(i()),r.toggle(!s),s)switch(o){case"global":c.hide(),r.hide();break;case"capped":c.show(),r.hide();break;case"own":c.hide(),r.show()}}}}),d.length&&(g=d.data("startofweek"));var p={dateFormat:"yy-mm-dd",showAnim:"fadeIn",changeMonth:!0,changeYear:!0,numberOfMonths:3,firstDay:g,showButtonPanel:!0,onChange:function(){},onSelect:function(t,i){var a=e.datepicker.parseDate("yy-mm-dd",t);"ticket_start_date"===i.id?(e("#ticket_end_date").datepicker("option","minDate",a),a?e(".ticket_start_time").show():e(".ticket_start_time").hide()):(e("#ticket_start_date").datepicker("option","maxDate",a),a?e(".ticket_end_time").show():e(".ticket_end_time").hide())}};e("#ticket_start_date").datepicker(p).keyup(function(t){8!==t.keyCode&&46!==t.keyCode||e.datepicker._clearDate(this)}),e("#ticket_end_date").datepicker(p).keyup(function(t){8!==t.keyCode&&46!==t.keyCode||e.datepicker._clearDate(this)}),s.change(a),s.trigger("change"),l=!1,e("input[name=ticket_provider]:radio").change(function(){r()}),e("input[name=ticket_provider]:checked").each(function(){r()}),e("a#ticket_form_toggle").click(function(t){e("h4.ticket_form_title_edit").hide(),e("h4.ticket_form_title_add").show(),e(this).hide(),c.trigger("clear.tribe").trigger("set-advanced-fields.tribe").trigger("focus.tribe"),e("#ticket_form").show(),e(document.getElementById("tribetickets")).trigger("ticket-provider-changed.tribe"),t.preventDefault()}),e("#ticket_form_cancel").click(function(){c.trigger("clear.tribe").trigger("set-advanced-fields.tribe").trigger("focus.tribe")}),e("#ticket_form_save").click(function(t){var i=e("#ticket_form_table"),a=i.find("#ticket_provider:checked").val(),r=i.find(".ticket, .ticket_advanced_meta, .ticket_advanced_"+a);c.trigger("save-ticket.tribe",t).trigger("spin.tribe","start");var n={action:"tribe-ticket-add-"+e("input[name=ticket_provider]:checked").val(),formdata:r.find(".ticket_field").serialize(),post_ID:e("#post_ID").val(),nonce:TribeTickets.add_ticket_nonce};e.post(ajaxurl,n,function(t){c.trigger("saved-ticket.tribe",t),t.success&&(c.trigger("clear.tribe"),e("td.ticket_list_container").empty().html(t.data.html),e(".ticket_time").hide())},"json").complete(function(){c.trigger("spin.tribe","stop").trigger("focus.tribe")})}),c.on("click",".ticket_delete",function(t){t.preventDefault(),c.trigger("delete-ticket.tribe",t).trigger("spin.tribe","start");var i={action:"tribe-ticket-delete-"+e(this).attr("attr-provider"),post_ID:e("#post_ID").val(),ticket_id:e(this).attr("attr-ticket-id"),nonce:TribeTickets.remove_ticket_nonce};e.post(ajaxurl,i,function(t){c.trigger("deleted-ticket.tribe",t),t.success&&(c.trigger("clear.tribe"),e("td.ticket_list_container").empty().html(t.data))},"json").complete(function(){c.trigger("spin.tribe","stop")})}),c.on("click",".ticket_edit",function(t){t.preventDefault(),e("h4.ticket_form_title_edit").show(),e("h4.ticket_form_title_add").hide(),c.trigger("spin.tribe","start");var i={action:"tribe-ticket-edit-"+e(this).attr("attr-provider"),post_ID:e("#post_ID").val(),ticket_id:e(this).attr("attr-ticket-id"),nonce:TribeTickets.edit_ticket_nonce};e.post(ajaxurl,i,function(t){c.trigger("clear.tribe").trigger("set-advanced-fields.tribe").trigger("edit-ticket.tribe",t);var i=t.data.price,a=i,r=!1;"undefined"!=typeof t.data.on_sale&&t.data.on_sale&&(r=!0,i=t.data.regular_price),e("#ticket_id").val(t.data.ID),e("#ticket_name").val(t.data.name),e("#ticket_description").val(t.data.description),r&&e(".ticket_advanced_"+t.data.provider_class+".sale_price").show();var n=t.data.start_date.substring(0,10),d=t.data.end_date.substring(0,10);e("#ticket_start_date").val(n),e("#ticket_end_date").val(d);var o=e(document.getElementById("ticket_start_meridian")),s=e(document.getElementById("ticket_end_meridian"));if(t.data.start_date){var _=parseInt(t.data.start_date.substring(11,13)),l="am";_>12&&o.length&&(l="pm",_=parseInt(_)-12,_=("0"+_).slice(-2)),12===_&&(l="pm"),0===_&&"am"===l&&(_=12),_=_.toString(),1===_.length&&(_="0"+_),e("#ticket_start_hour").val(_),e("#ticket_start_meridian").val(l),e(".ticket_start_time").show()}if(t.data.end_date){var k=parseInt(t.data.end_date.substring(11,13)),g="am";k>12&&s.length&&(g="pm",k=parseInt(k)-12,k=("0"+k).slice(-2)),12===k&&(g="pm"),0===k&&"am"===g&&(k=12),k=k.toString(),1===k.length&&(k="0"+k),e("#ticket_end_hour").val(k),e("#ticket_end_meridian").val(g),e("#ticket_start_minute").val(t.data.start_date.substring(14,16)),e("#ticket_end_minute").val(t.data.end_date.substring(14,16)),e(".ticket_end_time").show()}var p=e("tr.ticket_advanced input");p.data("name",p.attr("name")).attr({name:"",id:""}),e("tr.ticket_advanced").remove(),e("tr.ticket.bottom").before(t.data.advanced_fields),e("input:radio[name=ticket_provider]").filter("[value="+t.data.provider_class+"]").click(),e("input[name=ticket_provider]:radio").change();var m=c.find("#ticket_price");m.val(i),"undefined"!=typeof t.data.disallow_update_price_message?m.siblings(".no-update-message").html(t.data.disallow_update_price_message):m.siblings(".no-update-message").html(""),"undefined"==typeof t.data.can_update_price||t.data.can_update_price?(m.removeProp("disabled"),m.siblings(".description").show(),m.siblings(".no-update-message").hide()):(m.prop("disabled","disabled"),m.siblings(".description").hide(),m.siblings(".no-update-message").show());var f=c.find("#ticket_sale_price");r?f.val(a).closest("tr").show():f.closest("tr").hide(),"undefined"!=typeof t.data.purchase_limit&&t.data.purchase_limit&&e("#ticket_purchase_limit").val(t.data.purchase_limit),c.find(".bumpdown-trigger").bumpdown(),c.find(".bumpdown").hide(),e("a#ticket_form_toggle").hide(),e("#ticket_form").show(),c.trigger("set-advanced-fields.tribe").trigger("edit-ticket.tribe")},"json").complete(function(){c.trigger("spin.tribe","stop").trigger("focus.tribe")})}).on("click","#tribe_ticket_header_image",function(t){t.preventDefault(),ticketHeaderImage.uploader("","")});var m=e("#tribe_ticket_header_remove"),f=e("#tribe_ticket_header_preview");if(f.find("img").length&&m.show(),_.change(function(){l=!0}),e('input[type="submit"]').click(function(){l=!1}),e(t).on("beforeunload",function(){return l?tribe_global_stock_admin_ui.nav_away_msg:void 0}),e("body").on("click","#tribe_ticket_header_remove",function(t){t.preventDefault(),f.html(""),m.hide(),e("#tribe_ticket_header_image_id").val("")}),e("#tribe_ticket_header_preview img").length){var h=e("#tribe_ticket_header_preview img");h.removeAttr("width").removeAttr("height"),c.width()<h.width()&&h.css("width","95%")}})}(window,jQuery);
|
src/template-tags/tickets.php
CHANGED
@@ -194,24 +194,53 @@ if ( ! function_exists( 'tribe_tickets_get_ticket_stock_message' ) ) {
|
|
194 |
/**
|
195 |
* Gets the "tickets sold" message for a given ticket
|
196 |
*
|
197 |
-
* @param
|
198 |
*
|
199 |
* @return string
|
200 |
*/
|
201 |
-
function tribe_tickets_get_ticket_stock_message( $ticket ) {
|
202 |
-
$stock
|
203 |
-
$sold
|
204 |
-
$
|
205 |
-
|
206 |
-
$
|
207 |
-
|
208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
}
|
210 |
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
}
|
216 |
|
217 |
return $message;
|
194 |
/**
|
195 |
* Gets the "tickets sold" message for a given ticket
|
196 |
*
|
197 |
+
* @param Tribe__Tickets__Ticket_Object $ticket Ticket to analyze
|
198 |
*
|
199 |
* @return string
|
200 |
*/
|
201 |
+
function tribe_tickets_get_ticket_stock_message( Tribe__Tickets__Ticket_Object $ticket ) {
|
202 |
+
$stock = $ticket->stock();
|
203 |
+
$sold = $ticket->qty_sold();
|
204 |
+
$cancelled = $ticket->qty_cancelled();
|
205 |
+
$pending = $ticket->qty_pending();
|
206 |
+
$event = Tribe__Tickets__Tickets::find_matching_event( $ticket );
|
207 |
+
$global_stock = new Tribe__Tickets__Global_Stock( $event->ID );
|
208 |
+
|
209 |
+
$is_global = Tribe__Tickets__Global_Stock::GLOBAL_STOCK_MODE === $ticket->global_stock_mode();
|
210 |
+
$is_capped = Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE === $ticket->global_stock_mode();
|
211 |
+
$stock_cap = $ticket->global_stock_cap();
|
212 |
+
|
213 |
+
// If ticket sales are capped, do not suggest that more than the cap amount are available
|
214 |
+
if ( $is_capped && $stock > $stock_cap ) {
|
215 |
+
$stock = $stock_cap;
|
216 |
}
|
217 |
|
218 |
+
// If it is a global-stock ticket but the global stock level has not yet been set for the event
|
219 |
+
// then return something better than just '0' as the available stock
|
220 |
+
if ( $is_global && 0 === $stock && ! $global_stock->is_enabled() ) {
|
221 |
+
$stock = '<i>' . __( 'global inventory', 'event-tickets-plus' ) . '</i>';
|
222 |
+
}
|
223 |
+
|
224 |
+
// There may not be a fixed inventory - in which case just report the number actually sold so far
|
225 |
+
if ( empty( $stock ) && $stock !== 0 ) {
|
226 |
+
$message = sprintf( esc_html__( 'Sold %d', 'event-tickets' ), esc_html( $sold ) );
|
227 |
+
}
|
228 |
+
// If we do have a fixed stock then we can provide more information
|
229 |
+
else {
|
230 |
+
$cancelled_count = empty( $cancelled ) ? '' : esc_html( sprintf(
|
231 |
+
_x( ' cancelled: %1$d', 'ticket stock message (cancelled stock)', 'event-tickets' ),
|
232 |
+
(int) $cancelled
|
233 |
+
) );
|
234 |
+
|
235 |
+
$pending_count = $pending < 1 ? '' : esc_html( sprintf(
|
236 |
+
__( ' pending: %1$d', 'ticket stock message (pending stock)', 'event-tickets' ),
|
237 |
+
(int) $pending
|
238 |
+
) );
|
239 |
+
|
240 |
+
$message = sprintf(
|
241 |
+
esc_html__( 'Sold %1$d (units remaining: %2$s%3$s%4$s)', 'event-tickets' ),
|
242 |
+
esc_html( $sold ), $stock, $cancelled_count, $pending_count
|
243 |
+
);
|
244 |
}
|
245 |
|
246 |
return $message;
|
src/views/tickets/rsvp.php
CHANGED
@@ -1,19 +1,23 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
$is_there_any_product = false;
|
4 |
$is_there_any_product_to_sell = false;
|
5 |
|
6 |
ob_start();
|
|
|
|
|
7 |
?>
|
8 |
-
<form action="" class="cart" method="post" enctype='multipart/form-data'>
|
9 |
<h2 class="tribe-events-tickets-title"><?php esc_html_e( 'RSVP', 'event-tickets' ) ?></h2>
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
if ( $messages ) {
|
14 |
-
?>
|
15 |
-
<div class="tribe-rsvp-messages">
|
16 |
-
<?php
|
17 |
foreach ( $messages as $message ) {
|
18 |
?>
|
19 |
<div class="tribe-rsvp-message tribe-rsvp-message-<?php echo esc_attr( $message->type ); ?>">
|
@@ -21,11 +25,12 @@ ob_start();
|
|
21 |
</div>
|
22 |
<?php
|
23 |
}//end foreach
|
24 |
-
|
|
|
|
|
|
|
25 |
</div>
|
26 |
-
|
27 |
-
}//end if
|
28 |
-
?>
|
29 |
<table width="100%" class="tribe-events-tickets tribe-events-tickets-rsvp">
|
30 |
<?php
|
31 |
foreach ( $tickets as $ticket ) {
|
@@ -39,7 +44,7 @@ ob_start();
|
|
39 |
|
40 |
?>
|
41 |
<tr>
|
42 |
-
<td class="tribe-ticket">
|
43 |
<input type="hidden" name="product_id[]" value="<?php echo absint( $ticket->ID ); ?>">
|
44 |
<?php
|
45 |
if ( $ticket->is_in_stock() ) {
|
@@ -73,6 +78,14 @@ ob_start();
|
|
73 |
</td>
|
74 |
</tr>
|
75 |
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
}
|
77 |
}//end foreach
|
78 |
|
@@ -80,10 +93,19 @@ ob_start();
|
|
80 |
?>
|
81 |
<tr class="tribe-tickets-meta-row">
|
82 |
<td colspan="4" class="tribe-tickets-attendees">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
<table>
|
84 |
<tr class="tribe-tickets-full-name-row">
|
85 |
<td>
|
86 |
-
<label for="tribe-tickets-full-name"><?php esc_html_e( 'Full Name
|
87 |
</td>
|
88 |
<td colspan="3">
|
89 |
<input type="text" name="attendee[full_name]" id="tribe-tickets-full-name">
|
@@ -91,12 +113,18 @@ ob_start();
|
|
91 |
</tr>
|
92 |
<tr class="tribe-tickets-email-row">
|
93 |
<td>
|
94 |
-
<label for="tribe-tickets-email"><?php esc_html_e( 'Email
|
95 |
</td>
|
96 |
<td colspan="3">
|
97 |
<input type="email" name="attendee[email]" id="tribe-tickets-email">
|
98 |
</td>
|
99 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
</table>
|
101 |
</td>
|
102 |
</tr>
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* This template renders the RSVP ticket form
|
4 |
+
*
|
5 |
+
* @version 4.1
|
6 |
+
*
|
7 |
+
*/
|
8 |
|
9 |
$is_there_any_product = false;
|
10 |
$is_there_any_product_to_sell = false;
|
11 |
|
12 |
ob_start();
|
13 |
+
$messages = Tribe__Tickets__RSVP::get_instance()->get_messages();
|
14 |
+
$messages_class = $messages ? 'tribe-rsvp-message-display' : '';
|
15 |
?>
|
16 |
+
<form action="" class="cart <?php echo esc_attr( $messages_class ); ?>" method="post" enctype='multipart/form-data'>
|
17 |
<h2 class="tribe-events-tickets-title"><?php esc_html_e( 'RSVP', 'event-tickets' ) ?></h2>
|
18 |
+
<div class="tribe-rsvp-messages">
|
19 |
+
<?php
|
20 |
+
if ( $messages ) {
|
|
|
|
|
|
|
|
|
21 |
foreach ( $messages as $message ) {
|
22 |
?>
|
23 |
<div class="tribe-rsvp-message tribe-rsvp-message-<?php echo esc_attr( $message->type ); ?>">
|
25 |
</div>
|
26 |
<?php
|
27 |
}//end foreach
|
28 |
+
}//end if
|
29 |
+
?>
|
30 |
+
<div class="tribe-rsvp-message tribe-rsvp-message-error tribe-rsvp-message-confirmation-error" style="display:none;">
|
31 |
+
<?php echo esc_html_e( 'Please fill in the RSVP confirmation name and email fields.', 'event-tickets' ); ?>
|
32 |
</div>
|
33 |
+
</div>
|
|
|
|
|
34 |
<table width="100%" class="tribe-events-tickets tribe-events-tickets-rsvp">
|
35 |
<?php
|
36 |
foreach ( $tickets as $ticket ) {
|
44 |
|
45 |
?>
|
46 |
<tr>
|
47 |
+
<td class="tribe-ticket quantity" data-product-id="<?php echo esc_attr( $ticket->ID ); ?>">
|
48 |
<input type="hidden" name="product_id[]" value="<?php echo absint( $ticket->ID ); ?>">
|
49 |
<?php
|
50 |
if ( $ticket->is_in_stock() ) {
|
78 |
</td>
|
79 |
</tr>
|
80 |
<?php
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Allows injection of HTML after an RSVP ticket table row
|
84 |
+
*
|
85 |
+
* @var Event ID
|
86 |
+
* @var Tribe__Tickets__Ticket_Object
|
87 |
+
*/
|
88 |
+
do_action( 'event_tickets_rsvp_after_ticket_row', tribe_events_get_ticket_event( $ticket->id ), $ticket );
|
89 |
}
|
90 |
}//end foreach
|
91 |
|
93 |
?>
|
94 |
<tr class="tribe-tickets-meta-row">
|
95 |
<td colspan="4" class="tribe-tickets-attendees">
|
96 |
+
<header><?php esc_html_e( 'Send RSVP confirmation to:', 'event-tickets-plus' ); ?></header>
|
97 |
+
<?php
|
98 |
+
/**
|
99 |
+
* Allows injection of HTML before RSVP ticket confirmation fields
|
100 |
+
*
|
101 |
+
* @var array of Tribe__Tickets__Ticket_Object
|
102 |
+
*/
|
103 |
+
do_action( 'event_tickets_rsvp_before_confirmation_fields', $tickets );
|
104 |
+
?>
|
105 |
<table>
|
106 |
<tr class="tribe-tickets-full-name-row">
|
107 |
<td>
|
108 |
+
<label for="tribe-tickets-full-name"><?php esc_html_e( 'Full Name', 'event-tickets' ); ?>:</label>
|
109 |
</td>
|
110 |
<td colspan="3">
|
111 |
<input type="text" name="attendee[full_name]" id="tribe-tickets-full-name">
|
113 |
</tr>
|
114 |
<tr class="tribe-tickets-email-row">
|
115 |
<td>
|
116 |
+
<label for="tribe-tickets-email"><?php esc_html_e( 'Email', 'event-tickets' ); ?>:</label>
|
117 |
</td>
|
118 |
<td colspan="3">
|
119 |
<input type="email" name="attendee[email]" id="tribe-tickets-email">
|
120 |
</td>
|
121 |
</tr>
|
122 |
+
<tr class="tribe-tickets-attendees-list-optout">
|
123 |
+
<td colspan="4">
|
124 |
+
<input type="checkbox" name="attendee[optout]" id="tribe-tickets-attendees-list-optout">
|
125 |
+
<label for="tribe-tickets-attendees-list-optout"><?php esc_html_e( 'Don\'t list me on the public attendee list', 'event-tickets' ); ?></label>
|
126 |
+
</td>
|
127 |
+
</tr>
|
128 |
</table>
|
129 |
</td>
|
130 |
</tr>
|
tests.md
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
# Events Calendar PRO tests
|
2 |
-
|
3 |
-
This is a brief and quick guide that's covering the bare essentials needed to set up the tests on your local plugin copy.
|
4 |
-
Please refer to [Codeception](http://codeception.com/docs) and [WP Browser](https://github.com/lucatume/wp-browser) documentation for any issue that's not TEC related.
|
5 |
-
|
6 |
-
## Set up
|
7 |
-
After cloning the TEX repository on your local machine change directory to the plugin root folder and pull in any needed dependency using [Composer](https://getcomposer.org/):
|
8 |
-
|
9 |
-
composer update
|
10 |
-
|
11 |
-
when Composer finished the update process (might take a while) set up your own [Codeception](http://codeception.com/) installation running
|
12 |
-
|
13 |
-
vendor/bin/wpcept bootstrap
|
14 |
-
|
15 |
-
The `wpcept bootstrap` command is a modified version of the default `codecept bootstrap` command that will take care of setting up a WordPress-friendly testing environment.
|
16 |
-
To be able to run successfully on your system Codeception will need to be configured to look for the right database, the right WordPress installation and so on.
|
17 |
-
Codeception allows for "distribution" versions of its configuration to be shared among developers, what you define in your local Codeception configuration files will override the "distribution" setting; think of CSS rules.
|
18 |
-
The repository contains a `codeception.dist.yml` file that Codeception will read before reading the local to your machine `codeception.yml` file.
|
19 |
-
Copy the distribution version of the Codeception configuration file in the root folder of the plugin
|
20 |
-
|
21 |
-
cp codeception.dist.yml codeception.yml
|
22 |
-
|
23 |
-
**Edit the file `codeception.yml` file to suit your database, installation folder and web driver settings.**
|
24 |
-
|
25 |
-
**Beware**: The `WPLoader` module that's used in functional tests will **destroy** the database it's working on: **do not** point it to the same database you use for development! A good rule of thumb is to have a database for development (e.g. `tec`) and one that will be used for tests (e.g. `tec-tests`).
|
26 |
-
On the same lines the repository packs "distribution" versions of the `unit.suite.dist.yml`, `functional.suite.dist.yml` and `acceptance.suite.dist.yml` configuration files: there is usually no need to override those but it's worth mentioning they exist.
|
27 |
-
The last piece of the configuration is the bootstrap file; the repository comes with "distribution" versions of these file in the root folder of the pluging tests (`/tests/_bootstrap.dist.php`) and a bootstrap file specific to each suite (`/tests/acceptance/_bootstrap.dist.php`, `/tests/functional/_bootstrap.dist.php`, `/tests/unit/_bootstrap.dist.php`); remove the root `_bootstrap.php` file Codeception created during bootstrapping and copy the one in the root of the plugin tests (`/tests`)
|
28 |
-
|
29 |
-
rm _bootstrap.php
|
30 |
-
cp _bootstrap.dist.php _bootstrap.php
|
31 |
-
|
32 |
-
You *should* not need to edit anything in any bootstrap file to make things work. Do the same for the suite specific bootstrap files
|
33 |
-
|
34 |
-
cp acceptance/_bootstrap.dist.php acceptance/_bootstrap.php
|
35 |
-
cp functional/_bootstrap.dist.php functional/_bootstrap.php
|
36 |
-
cp unit/_bootstrap.dist.php unit/_bootstrap.php
|
37 |
-
|
38 |
-
## Running the tests
|
39 |
-
Nothing different from a default Codeception environment so this command will run all the tests
|
40 |
-
|
41 |
-
vendor/bin/codecept run
|
42 |
-
|
43 |
-
Failing tests are ok in set up terms: the system works. Errors should be reported.
|
44 |
-
Please refer to [Codeception documentation](http://codeception.com/docs) to learn about more run and configuaration options.
|
45 |
-
|
46 |
-
## Contributing to tests
|
47 |
-
Should you come up with good utility methods, worthy database configurations and "cool additions" in general for the plugin tests feel free to open a PR and submit them for review.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|