Inventory_Presser_Shortcode_Hours_Today
On This Page
Description Description
Creates a shortcode that outputs a sentence about whether or not the car lot is open. Also hooks into vehicle singles and tables of hours to automatically deploy the feature.
Source Source
File: includes/shortcode/class-shortcode-hours-today.php
class Inventory_Presser_Shortcode_Hours_Today {
const SHORTCODE_TAG = 'invp_hours_today';
/**
* add
*
* Adds two shortcodes
*
* @return void
*/
function add() {
// add a shortcode that outputs hours today
add_shortcode( self::SHORTCODE_TAG, array( $this, 'driver' ) );
add_shortcode( str_replace( '_', '-', self::SHORTCODE_TAG ), array( $this, 'driver' ) );
}
/**
* hooks
*
* Adds hooks that power the shortcode and attach it to other features
*
* @return void
*/
public function add_hooks() {
add_action( 'init', array( $this, 'add' ) );
// add hours today near the "this vehicle is located at" sentence
add_filter( 'invp_vehicle_location_sentence', array( $this, 'append_shortcode' ) );
// add hours today in the Hours widget
add_filter( 'invp_hours_title', array( $this, 'append_hours_today_to_hours_widget' ), 10, 2 );
}
/**
* append_hours_today_to_hours_widget
*
* Returns the output of the shortcode wrapped in some HTML
*
* @param string $hours_title_html
* @param string $hours_uid
* @return string HTML that renders a sentence
*/
function append_hours_today_to_hours_widget( $hours_title_html, $hours_uid ) {
$shortcode = '[' . self::SHORTCODE_TAG . ' hours_uid="' . $hours_uid . '"]';
$shortcode_output = '';
if ( function_exists( 'apply_shortcodes' ) ) {
$shortcode_output = apply_shortcodes( $shortcode );
} elseif ( function_exists( 'do_shortcode' ) ) {
$shortcode_output = do_shortcode( $shortcode );
}
if ( empty( $shortcode_output ) ) {
return $hours_title_html;
}
return $hours_title_html . '<p class="invp-hours-today">' . $shortcode_output . '</p>';
}
/**
* append_shortcode
*
* Filter callback that appends the shortcode to the end of a string of
* content.
*
* @param string $content
* @return string The provided $content with the shortcode appended to the end
*/
function append_shortcode( $content ) {
return trim( $content . ' <p>[' . self::SHORTCODE_TAG . ']</p>' );
}
/**
* Create a DateTime object from a string like "9:00 AM"
*
* @param string $hour_string A string like "9:00 AM"
* @return DateTime
*/
static function create_date_object_from_hour_string( $hour_string ) {
return DateTime::createFromFormat( 'g:ia', strtolower( str_replace( ' ', '', $hour_string ?? '' ) ) );
}
/**
* create_days_array_from_hours_array
*
* Translate the hours termmeta data structure into
* Inventory_Presser_Business_Day objects
*
* @param array $hours_arr
* @return array And array of Inventory_Presser_Business_Day objects
*/
public static function create_days_array_from_hours_array( $hours_arr ) {
$days = array();
$weekdays = array_keys( INVP::weekdays() );
for ( $d = 0; $d < 7; $d++ ) {
if ( empty( $hours_arr[ $weekdays[ $d ] . '_open' ] )
|| empty( $hours_arr[ $weekdays[ $d ] . '_close' ] )
) {
continue;
}
$day = new Inventory_Presser_Business_Day();
$day->weekday = $d + 1;
// open hour, turn "9:00 AM" into 9 and "4:00 PM" into 15
$date_obj = self::create_date_object_from_hour_string( $hours_arr[ $weekdays[ $d ] . '_open' ] );
if ( ! $date_obj ) {
continue;
}
$day->open_hour = $date_obj->format( 'G' );
$day->open_minute = $date_obj->format( 'i' );
// close hour
$date_obj = self::create_date_object_from_hour_string( $hours_arr[ $weekdays[ $d ] . '_close' ] );
if ( ! $date_obj ) {
continue;
}
$day->close_hour = $date_obj->format( 'G' );
$day->close_minute = $date_obj->format( 'i' );
array_push( $days, $day );
}
return $days;
}
/**
* create_sentence
*
* Examines the array of $days and generates the sentence, the core feature
* of this shortcode.
*
* @param array $days An array of Inventory_Presser_Business_Day objects
* @return string A string like "Open today until 5:00pm" or "Closed until 9:00am on Monday"
*/
function create_sentence( $days ) {
if ( null === $days || 0 === count( $days ) ) {
return '';
}
// Find today. It might not be in the array at all.
$today = null;
$today_weekday = gmdate( 'w', current_time( 'timestamp' ) ); // 0 if today is Sunday
foreach ( $days as $day ) {
if ( strval( $day->weekday ) === $today_weekday ) {
$today = $day;
break;
}
}
// are we open right now?
if ( null !== $today && $today->open_right_now() ) {
// currently open
return __( 'Open today until ', 'inventory-presser' ) . $today->close_string();
} elseif ( null != $today && $today->open_later_today() ) {
// not yet open today
$open_string = $today->open_string();
if ( '' == $open_string ) {
return '';
}
return __( 'Opening at ', 'inventory-presser' ) . $open_string . __( ' today', 'inventory-presser' );
}
// Find the next day we are open.
$next_open_day = self::find_next_open_day( $days );
if ( null === $next_open_day ) {
return '';
}
// closed today, tell them about the next time we are open
$str = __( 'Closed until ', 'inventory-presser' ) . $next_open_day->open_string();
// If $next_open_day is tomorrow, output "tomorrow" instead of "on Tuesday"
if ( $next_open_day->is_tomorrow() ) {
$str .= __( ' tomorrow', 'inventory-presser' );
} else {
$str .= __( ' on ', 'inventory-presser' ) . ucfirst( array_keys( INVP::weekdays() )[ $next_open_day->weekday - 1 ] );
}
return $str;
}
/**
* driver
*
* The shortcode callback method that returns the sentence.
*
* @param array $atts
* @return string The sentence
*/
public function driver( $atts ) {
// setup default attributes
$atts = shortcode_atts(
array(
'hours_uid' => 0,
),
$atts,
self::SHORTCODE_TAG
);
/**
* Find hours for which we will create sentence(s)
*/
$hours_set = $this->find_hours_set( $atts );
if ( null === $hours_set ) {
return '';
}
$days = $this->create_days_array_from_hours_array( $hours_set );
return $this->create_sentence( $days );
}
/**
* find_hours_set
*
* Uses the shortcode attributes to find the right set of hours
*
* @param array $shortcode_atts The shortcode attributes
* @return array A set of hours
*/
private function find_hours_set( $shortcode_atts ) {
if ( ! empty( $shortcode_atts['hours_uid'] ) ) {
// the hours identified by this unique id
return $this->find_hours_set_by_uid( $shortcode_atts['hours_uid'] );
} elseif ( is_singular( INVP::POST_TYPE ) ) {
// is there a location attached to this vehicle?
$location_terms = wp_get_object_terms( get_the_ID(), 'location' );
if ( ! empty( $location_terms ) ) {
$location_slug = $location_terms[0]->slug;
$sets = $this->find_hours_sets_by_location_slug( $location_slug );
if ( ! empty( $sets ) ) {
return $sets[0];
}
}
} else {
// no specific set or location identified.
$location_slugs = get_terms(
array(
'fields' => 'id=>slug',
'taxonomy' => 'location',
'hide_empty' => true,
'orderby' => 'term_id',
'order' => 'ASC',
)
);
// are there terms in the location taxonomy?
if ( 0 < sizeof( $location_slugs ) ) {
// take the first set of hours we find
foreach ( $location_slugs as $id => $slug ) {
$sets = $this->find_hours_sets_by_location_slug( $slug );
if ( ! empty( $sets ) ) {
return $sets[0];
}
}
}
}
return null;
}
/**
* find_hours_sets_by_location_slug
*
* Get all sets of hours attached to a term in the location taxonomy
*
* @param string $slug The slug of a term in our location taxonomy
* @return array A set of hours
*/
public function find_hours_sets_by_location_slug( $slug ) {
if ( ! is_string( $slug ) ) {
return null;
}
$location_term = get_term_by( 'slug', $slug, 'location' );
if ( ! $location_term ) {
return null;
}
return INVP::get_hours( $location_term->term_id );
}
/**
* find_hours_set_by_uid
*
* Get all sets of hours attached to a term in the location taxonomy by
* unique ID
*
* @param string $uid A unique identifier assigned to a set of hours
* @return array A set of hours
*/
function find_hours_set_by_uid( $uid ) {
// get all term ids in the location taxonomy
$location_term_ids = get_terms(
array(
'fields' => 'ids',
'orderby' => 'term_id', // oldest first
'taxonomy' => 'location',
'hide_empty' => false, // Dealers that don't tag each vehicle with a location will have no vehicles
)
);
if ( ! is_array( $location_term_ids ) ) {
return null;
}
foreach ( $location_term_ids as $term_id ) {
$sets = INVP::get_hours( $term_id );
if ( empty( $sets ) ) {
continue;
}
foreach ( $sets as $hours ) {
if ( isset( $hours['uid'] ) && $uid == $hours['uid'] ) {
// these are the hours we want
return $hours;
}
}
}
return null;
}
/**
* Takes an array of days and finds the next day the business has hours.
* Does not check if the business is still open today. Helps make the jump
* from Friday to the next open day on Monday.
*
* @param array $days An array of Inventory_Presser_Business_Day objects
* @return Inventory_Presser_Business_Day The next day that has open hours
*/
public static function find_next_open_day( $days ) {
// find today
$today_weekday = gmdate( 'w', current_time( 'timestamp' ) ); // 0 if today is Sunday
$after_day = null;
$before_day = null;
$open_days = array_filter(
$days,
function ( $day ) {
return $day->open_in_some_fashion();
}
);
foreach ( $open_days as $day ) {
if ( $day->weekday > $today_weekday && ( null === $after_day || $day->weekday < $after_day->weekday ) ) {
$after_day = $day;
}
if ( $day->weekday < $today_weekday && ( null === $before_day || $day->weekday < $before_day->weekday ) ) {
$before_day = $day;
}
}
return ( null === $after_day ? $before_day : $after_day );
}
}
Expand full source codeCollapse full source codeView on Github
Methods Methods
- add — add
- add_hooks — hooks
- append_hours_today_to_hours_widget — append_hours_today_to_hours_widget
- append_shortcode — append_shortcode
- create_date_object_from_hour_string — Create a DateTime object from a string like “9:00 AM”
- create_days_array_from_hours_array — create_days_array_from_hours_array
- create_sentence — create_sentence
- driver — driver
- find_hours_set — find_hours_set
- find_hours_set_by_uid — find_hours_set_by_uid
- find_hours_sets_by_location_slug — find_hours_sets_by_location_slug
- find_next_open_day — Takes an array of days and finds the next day the business has hours.