Posted: February 26, 2020 at 10:50 am
Like others that have asked similar questions, we have three ticket types for our events and we want a promo code to only apply to the “Regular” ticket. To use the solution that I have linked to above I would have to be frequently modifying the lists of promo code ids and ticket ids to enforce correct promo code usage. |
|
Hi there,
Yes, there is. Our model system was designed to allow you to pull various objects even with complex queries fairly easily. You can start by checking the docs here: https://github.com/eventespresso/event-espresso-core/blob/master/docs/G–Model-System/
You could, but you don’t need to. To give you an example for your use case. Your looking for tickets and for specifically pulling in tickets you can use the EEM_Ticket model (this is explained in the docs above, which is why I started with those 🙂 ). Tickets relate to datetimes within an event and you want to search So to pull in all of the tickets with the name ‘Regular’ assigned to upcoming datetimes, you can do something like this:
In English, pull Tickets with the TKT_Name of ‘Regular’ that are assigned to Datetimes with a DTT_EVT_end (Datetime.DTT_EVT_end) greater than now (meaning they are upcoming). The model system takes care of the joins for you based on the dot notation used and returns an array of EE_Ticket objects which will be numerically indexed using the tickets ID.
Again, yes and again, you can use the models to pull those in. What are you defining at ‘valid promotions’ in this context? Note I recommend you do not simply add these queries to the function you mentioned above and run these queries on each and every request but rather run these queries when either an event or promotion is saved and cache the response, then simply call that value in the function mentioned. |
|
Hi Tony, |
|
There is an an action hook for hooking into promotions:
For creating/updating events you can use the default ‘save_post‘ wordpress hook.
Another option is to use a transient, save the results of the query to a transient and then rather than run the queries on every request, pull the transient, check it is still valid and use the values, if not run the queries again and save the transient once again. |
|
Hi Tony, I have successfully automated the generation of applicable promotion/ticket combinations and storing the value in a transient for use by the code snippet I linked to in my first post. I did not filter the promotions as there are different reasons for a promotion to be invalid and I will just let the checkout process handle that part. I use: function update_promo_code_ticket_array( ) { $where = array( 'TKT_name' => 'Regular', 'Datetime.DTT_EVT_end' => array( '>=', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) ) ); $tickets = EEM_Ticket::instance()->get_all( array( $where ) ); $promotions = EEM_Promotion::instance()->get_all(); // create array of all ticket ids for tickets named 'Regular' $ticket_array = array(); foreach ($tickets as $ticket) { $ticket_array[] = $ticket->ID(); } // create promotion id indexed array of all active promotions and assign the ticket array to each $promotion_tickets = array(); foreach ($promotions as $promotion) { $promotion_tickets[$promotion->ID()] = $ticket_array; } // store the multi-dimensional array of valid promotion/ticket combinations as a transient return $promotion_tickets; } if ( false === ( $applicable_promotion_tickets = get_transient( 'ticket-promotion-array' ) ) ) { // It wasn't there, so regenerate the data and save the transient $applicable_promotion_tickets = update_promo_code_ticket_array(); set_transient( 'ticket-promotion-array', $applicable_promotion_tickets, 3600 ); } instead of: // PLEASE ADD DATA TO THE FOLLOWING ARRAY $applicable_promotion_tickets = array(); I set the transient variable to expire after an hour and the code will regenerate it at that time. I will add the hooks to regenerate the array when either an event or promotion was added/updated at a later time. |
|
First, thanks for sharing your code, I’m sure it will be useful for some users. A couple of improvements for you, nothing major but should reduce the amount of processing needed.
However, rather than looping over each element to pull the ID from the ticket itself (or the above), you could just use Or even pull only the ID in the query itself:
Which reduces the query processing and as you are constructing the EE_Ticket objects, the amount of memory used. (Note the above will return the ID’s as strings so you’ll need to cast them to ints) — With this:
I know you mentioned not filtering the promotions, but I’d recommend you do. You could go through an filter the promotions manually but the next version of the promotions add-on has a
|
|
I seem to be having an issue when the transient variable expires. When the function runs to update it throws this: Any ideas why and how to prevent it? |
|
The only reference to that class is in this section and the error does point to the line number containing the EEM_Datetime class reference: $where = array( 'TKT_name' => 'Regular', 'Datetime.DTT_EVT_end' => array( '>=', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) ) ); $tickets = EEM_Ticket::instance()->get_all( array( $where ) ); |
|
Hmm, where are you adding that code on the site? You could try:
Although if you are getting the above error you may now simply get say the ‘EE_Registry’ class can not be found. |
|
I am using the code in a plugin as we want to keep all of our custom code easily portable to other themes. Here is the code in its entirety: <?php /* Plugin Name: Agile EE Promo Code Limiter Description: Ensures that promo codes can only be used on 'Regular' tickets Version: 1.0 */ function update_promo_code_ticket_array( ) { $where = array( 'TKT_name' => 'Regular', 'Datetime.DTT_EVT_end' => array( '>=', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) ) ); $tickets = EEM_Ticket::instance()->get_all( array( $where ) ); $promotions = EEM_Promotion::instance()->get_all(); // create array of all ticket ids for tickets named 'Regular' $ticket_array = array(); foreach ($tickets as $ticket) { $ticket_array[] = $ticket->ID(); } // create promotion id indexed array of all active promotions and assign the ticket array to each $promotion_tickets = array(); foreach ($promotions as $promotion) { $promotion_tickets[$promotion->ID()] = $ticket_array; } // store the multi-dimensional array of valid promotion/ticket combinations as a transient return $promotion_tickets; } if ( false === ( $applicable_promotion_tickets = get_transient( 'ticket-promotion-array' ) ) ) { // It wasn't there, so regenerate the data and save the transient $applicable_promotion_tickets = update_promo_code_ticket_array(); set_transient( 'ticket-promotion-array', $applicable_promotion_tickets, 3600 ); } // this is an array where keys are promotion IDs // and values are arrays of ticket IDs that are applicable to that promotion // in the following format: array( promo_ID => array( ticket_ID, ticket_ID ) ); // ex: array( 2 => array( 30, 35 ) ); // STOP!!! do not edit anything else beyond this add_filter('FHEE__EED_Promotions__get_applicable_items__applicable_items', function ($applicable_items, $promotion) use ($applicable_promotion_tickets) { $promotion_IDs = array_keys($applicable_promotion_tickets); if (! $promotion instanceof EE_Promotion || ! in_array($promotion->ID(), $promotion_IDs, true) ) { return $applicable_items; } foreach ($applicable_items as $key => $applicable_item) { if ($applicable_item instanceof EE_Line_Item && $applicable_item->OBJ_type() === 'Event') { $ticket_line_items = EEH_Line_Item::get_ticket_line_items($applicable_item); $valid_items = []; $invalid_items = []; if (is_array($ticket_line_items)) { foreach ($ticket_line_items as $ticket_line_item) { if (! $ticket_line_item instanceof EE_Line_Item) { continue; } foreach ($applicable_promotion_tickets as $promotion_ID => $promotion_tickets) { if ($promotion_ID !== $promotion->ID()) { continue; } if (in_array($ticket_line_item->OBJ_ID(), $promotion_tickets, true)) { // overwrite applicable event line item with ticket line item $applicable_items[ $key ] = $ticket_line_item; // and track the key so it's not removed on subsequent iterations $valid_items[] = $key; add_filter('FHEE__EED_Promotions__add_promotion_line_item__bypass_increment_promotion_scope_uses', function ($bypass_increment_promotion_scope_uses, $parent_line_item, $bypass_promotion) use ($ticket_line_item, $promotion) { if ($parent_line_item === $ticket_line_item && $bypass_promotion === $promotion) { $bypass_increment_promotion_scope_uses = true; } return $bypass_increment_promotion_scope_uses; }, 10, 4 ); add_filter('FHEE__EE_Promotion_Scope__generate_promotion_line_item', function ($new_line_item_props) use ($promotion_IDs) { if ($new_line_item_props['OBJ_type'] === 'Promotion' && in_array($new_line_item_props['OBJ_ID'], $promotion_IDs, true)) { $new_line_item_props['LIN_type'] = EEM_Line_Item::type_sub_line_item; } return $new_line_item_props; }); } else { // this ticket is not valid, but don't remove the applicable item just yet $invalid_items[] = $key; } } } } // remove valid items from list of invalid ones $invalid_items = array_diff($invalid_items, $valid_items); // then remove invalid items from list of applicable items foreach ($invalid_items as $invalid_item) { unset($applicable_items[ $invalid_item ]); } } } return $applicable_items; }, 10, 3 ); |
|
Ok, so it could be load order. Did you try the code I posted? It just forces manually loads the class first. |
|
Hi Tony, I did try the code you posted and got the error you predicted after the first time the transient value expired. I too suspected it was load order so I moved the code that checks if the transient has expired and triggers the reload to inside add_filter section. This seems to have fixed the problem as the error didn’t return after the transient would have expired the first time. I am sharing the entire working code below again in case it might help somebody else: <?php /* Plugin Name: Event Espresso Promo Code Limiter Description: Ensures that promo codes can only be used on 'Regular' tickets Version: 1.0 */ function update_promo_code_ticket_array( ) { $datetime_model = EE_Registry::instance()->load_model('Datetime'); $where = array( 'TKT_name' => 'Regular', 'Datetime.DTT_EVT_end' => array( '>=', $datetime_model->current_time_for_query( 'DTT_EVT_end' ) ) ); $tickets = EEM_Ticket::instance()->get_all( array( $where ) ); $promotions = EEM_Promotion::instance()->get_all(); // create array of all ticket ids for tickets named 'Regular' $ticket_array = array(); foreach ($tickets as $ticket) { $ticket_array[] = $ticket->ID(); } // create promotion id indexed array of all active promotions and assign the ticket array to each $promotion_tickets = array(); foreach ($promotions as $promotion) { $promotion_tickets[$promotion->ID()] = $ticket_array; } // store the multi-dimensional array of valid promotion/ticket combinations as a transient return $promotion_tickets; } // this is an array where keys are promotion IDs // and values are arrays of ticket IDs that are applicable to that promotion // in the following format: array( promo_ID => array( ticket_ID, ticket_ID ) ); // ex: array( 2 => array( 30, 35 ) ); // STOP!!! do not edit anything else beyond this add_filter('FHEE__EED_Promotions__get_applicable_items__applicable_items', function ($applicable_items, $promotion) { if ( false === ( $applicable_promotion_tickets = get_transient( 'ticket-promotion-array' ) ) ) { // It wasn't there, so regenerate the data and save the transient $applicable_promotion_tickets = update_promo_code_ticket_array(); set_transient( 'ticket-promotion-array', $applicable_promotion_tickets, 3600 ); } $promotion_IDs = array_keys($applicable_promotion_tickets); if (! $promotion instanceof EE_Promotion || ! in_array($promotion->ID(), $promotion_IDs, true) ) { return $applicable_items; } foreach ($applicable_items as $key => $applicable_item) { if ($applicable_item instanceof EE_Line_Item && $applicable_item->OBJ_type() === 'Event') { $ticket_line_items = EEH_Line_Item::get_ticket_line_items($applicable_item); $valid_items = []; $invalid_items = []; if (is_array($ticket_line_items)) { foreach ($ticket_line_items as $ticket_line_item) { if (! $ticket_line_item instanceof EE_Line_Item) { continue; } foreach ($applicable_promotion_tickets as $promotion_ID => $promotion_tickets) { if ($promotion_ID !== $promotion->ID()) { continue; } if (in_array($ticket_line_item->OBJ_ID(), $promotion_tickets, true)) { // overwrite applicable event line item with ticket line item $applicable_items[ $key ] = $ticket_line_item; // and track the key so it's not removed on subsequent iterations $valid_items[] = $key; add_filter('FHEE__EED_Promotions__add_promotion_line_item__bypass_increment_promotion_scope_uses', function ($bypass_increment_promotion_scope_uses, $parent_line_item, $bypass_promotion) use ($ticket_line_item, $promotion) { if ($parent_line_item === $ticket_line_item && $bypass_promotion === $promotion) { $bypass_increment_promotion_scope_uses = true; } return $bypass_increment_promotion_scope_uses; }, 10, 4 ); add_filter('FHEE__EE_Promotion_Scope__generate_promotion_line_item', function ($new_line_item_props) use ($promotion_IDs) { if ($new_line_item_props['OBJ_type'] === 'Promotion' && in_array($new_line_item_props['OBJ_ID'], $promotion_IDs, true)) { $new_line_item_props['LIN_type'] = EEM_Line_Item::type_sub_line_item; } return $new_line_item_props; }); } else { // this ticket is not valid, but don't remove the applicable item just yet $invalid_items[] = $key; } } } } // remove valid items from list of invalid ones $invalid_items = array_diff($invalid_items, $valid_items); // then remove invalid items from list of applicable items foreach ($invalid_items as $invalid_item) { unset($applicable_items[ $invalid_item ]); } } } return $applicable_items; }, 10, 3 ); |
|
This reply has been marked as private. | |
You can view the repo HERE.
Whilst I’d love to say yes, this isn’t a feature we’ve start working on yet, so its unliekyl to be released ‘soon’. |
|
The support post ‘Promo code for specific ticket types’ is closed to new replies.
Have a question about this support post? Create a new support post in our support forums and include a link to this existing support post so we can help you.