|
<?php |
|
/** |
|
* Plugin Name: TEC View load test CLI |
|
* Plugin Description: Adds a wp-cli command the WordPress installation to generate test events, this plugin requires |
|
* an active The Events Calendar plugin installation to work. Run <code>wp tec-load-test --help</code> for the command |
|
* synopsis. |
|
*/ |
|
|
|
namespace Tribe\Events\Tests; |
|
|
|
use Tribe__Date_Utils as Dates; |
|
use Tribe__Events__Organizer as Organizer; |
|
use Tribe__Timezones as Timezones; |
|
use Tribe__Utils__Array as Arr; |
|
|
|
if ( ! defined( 'WP_CLI' ) ) { |
|
return; |
|
} |
|
|
|
\WP_CLI::add_command( 'tec-load-test', '\Tribe\Events\Tests\generate_test_events' ); |
|
\WP_CLI::add_command( 'tec-mysql-packet-size', '\Tribe\Events\Tests\msyql_packet_size' ); |
|
\WP_CLI::add_command( 'tec-count', '\Tribe\Events\Tests\count_events' ); |
|
|
|
/** |
|
* Generates n test events for each day in the specified period. |
|
* |
|
* ## OPTIONS |
|
* |
|
* <start> |
|
* : The period start date, in a format parsable by `strtotime`. |
|
* |
|
* <end> |
|
* : The period end date, in a format parsable by `strtotime`. |
|
* |
|
* [<n>] |
|
* : The number of events to generate for each day. |
|
* default: 200 |
|
* |
|
* [--every_days=<every_days>] |
|
* : An optional value to set the day frequency of the generated events. Defaults to 1 to create events each 1 day. |
|
* default: 1 |
|
* |
|
* [--title=<title>] |
|
* : An optional title that will be used in the template '<date> <title> <n>'. |
|
* default: test event |
|
* |
|
* [--category=<category>] |
|
* : An optional category to assign to each crated event; either the category slug or ID. |
|
* default: test |
|
* |
|
* [--featured] |
|
* : All created events will be featured if this flag is set. |
|
* |
|
* [--max_duration=<max_duration>] |
|
* : An optional upper limit to the maximum event duration, in hours. |
|
* default: 16 |
|
* |
|
* [--organizer=<organizer>] |
|
* : An optional comma-separated list of Organizer post IDs that will be randomly assigned to each event. |
|
* |
|
* [--with_thumbnails] |
|
* : Optionally pull and attach Lorem Picsum images to each event as featured images. |
|
* |
|
* [--with_ideal_ratio_thumbnails] |
|
* : Optionally pull and attach Lorem Picsum images to each event as featured images in the 16:9 ideal ratio. |
|
* |
|
* ## EXAMPLES |
|
* |
|
* Generate 200 events on each day between two dates: |
|
* wp tec-load-test 2019-09-25 2019-12-31 |
|
* |
|
* Generate 50 events on each day between two dates with a title seed of "single event": |
|
* wp tec-load-test 2019-09-25 2019-12-31 50 --title="single event" |
|
* |
|
* Generate 50 events on each day between two dates limiting duration to, at the most, 6 hours: |
|
* wp tec-load-test 2019-09-25 2019-12-31 50 --max_duration=6 |
|
* |
|
* Generate 2 events on each day between two dates assigning to each a random number of organizers from the list: |
|
* wp tec-load-test 2019-09-25 2019-12-31 2 --organizer=23,89,45,59 |
|
* |
|
* Generate 2 events each 3 days between two dates: |
|
* wp tec-load-test 2019-09-25 2019-12-31 2 --every_days=3 |
|
* |
|
* Generate 2 events each day attaching a post thumbnail to each: |
|
* wp tec-load-test 2019-09-25 2019-12-31 2 --with_thumbnails |
|
* |
|
* Generate 2 events each day attaching an ideal 16:9 ratio post thumbnail to each: |
|
* wp tec-load-test 2019-09-25 2019-12-31 2 --with_ideal_ratio_thumbnails |
|
*/ |
|
function generate_test_events( array $args, array $assoc_args ) { |
|
$count = 0; |
|
list( $start, $end ) = $args; |
|
$n = isset( $args[2] ) ? (int) $args[2] : 200; |
|
$start_date = Dates::build_date_object( $start ); |
|
$end_date = Dates::build_date_object( $end ); |
|
$days_count = $end_date->diff( $start_date )->days; |
|
|
|
\WP_CLI::debug( 'Start date: ' . $start_date->format( 'Y-m-d' ) ); |
|
\WP_CLI::debug( 'End date: ' . $end_date->format( 'Y-m-d' ) ); |
|
\WP_CLI::debug( 'Events per day: ' . $n ); |
|
|
|
$categories = handle_categories( $assoc_args ); |
|
$featured = ! empty( $assoc_args['featured'] ); |
|
$with_thumbnails = ! ( empty( $assoc_args['with_thumbnails'] ) && empty( $assoc_args['with_ideal_ratio_thumbnails'] ) ); |
|
$with_ideal_ratio_thumbnails = ! empty( $assoc_args['with_ideal_ratio_thumbnails'] ); |
|
$image_id = 1; |
|
|
|
$progress = \WP_CLI\Utils\make_progress_bar( sprintf( 'Generating %d events per day...', $n ), $days_count ); |
|
|
|
$one_minute = new \DateInterval( 'PT1M' ); |
|
$site_timezone = get_option( 'timezone_string', 'UTC' ); |
|
|
|
if ( ! Timezones::is_utc_offset( $site_timezone ) ) { |
|
// To avoid issues with event fetching, set the timezone to a "pretty" one, bail if we cannot. |
|
$site_timezone = Timezones::generate_timezone_string_from_utc_offset( $site_timezone ); |
|
if ( Timezones::is_utc_offset( $site_timezone ) ) { |
|
\WP_CLI::error( |
|
sprintf( |
|
'The site timezone is "%s"; please set a real timezone string (e.g. Europe/Paris).', |
|
$site_timezone |
|
) |
|
); |
|
} |
|
} |
|
|
|
$every_days = isset( $assoc_args['every_days'] ) ? $assoc_args['every_days'] : 1; |
|
$interval_spec = "P{$every_days}D"; |
|
// Add one minute to the end date, else the `00:00:00` time would exclude it from the period. |
|
$period = new \DatePeriod( $start_date, |
|
new \DateInterval( $interval_spec ), |
|
$end_date->add( $one_minute ) |
|
); |
|
|
|
$colors = [ 'blue', 'yellow', 'red', 'green', 'purple', 'saffron', 'crimson', 'magenta', 'orange' ]; |
|
$names = [ 'whale', 'elephant', 'seal', 'giraffe', 'condor', 'fox', 'dog', 'squirrel', 'raccoon', 'lion' ]; |
|
$max_duration = isset( $assoc_args['max_duration'] ) ? (int) $assoc_args['max_duration'] : 16; |
|
$organizer = isset( $assoc_args['organizer'] ) ? |
|
array_filter( Arr::list_to_array( $assoc_args['organizer'] ) ) |
|
: false; |
|
|
|
if ( ! empty( $organizer ) ) { |
|
foreach ( $organizer as $o ) { |
|
$organizer_post = get_post( $o ); |
|
if ( ! ( $organizer_post instanceof \WP_Post && $organizer_post->post_type === Organizer::POSTTYPE ) ) { |
|
\WP_CLI::error( 'Organizer ' . $o . ' is not a valid Organizer.' ); |
|
} |
|
} |
|
} |
|
|
|
/** @var \DateTime $day */ |
|
foreach ( $period as $day ) { |
|
$date_string = $day->format( ( 'm/d' ) ); |
|
|
|
foreach ( range( 1, $n ) as $i ) { |
|
$title = isset( $assoc_args['title'] ) |
|
? trim( $assoc_args['title'] ) |
|
: $colors[ random_int( 0, count( $colors ) - 1 ) ] |
|
. ' ' . $names[ random_int( 0, count( $names ) - 1 ) ]; |
|
|
|
$update_map = [ |
|
'title' => sprintf( '%s %s %s', $date_string, $title, $i ), |
|
'content' => sprintf( '%s %s %s', $date_string, $title, $i ), |
|
'status' => 'publish', |
|
'start_date' => ( clone $day )->setTime( mt_rand( 0, 23 ), mt_rand( 0, 59 ) ), |
|
'duration' => mt_rand( HOUR_IN_SECONDS, $max_duration * HOUR_IN_SECONDS ), |
|
'timezone' => $site_timezone, |
|
]; |
|
|
|
if ( $featured ) { |
|
$update_map['featured'] = true; |
|
} |
|
|
|
if ( $with_thumbnails || $with_ideal_ratio_thumbnails ) { |
|
$image_width = random_int( 320, 2000 ); |
|
$image_height = $with_ideal_ratio_thumbnails ? |
|
$image_width / 16 * 9 |
|
: random_int( 200, 2000 ); |
|
$image_url = sprintf( |
|
'https://picsum.photos/%d/%d.jpg', |
|
$image_width, |
|
$image_height |
|
); |
|
$thumbnail_id = tribe_upload_image( $image_url ); |
|
if ( false === $thumbnail_id ) { |
|
\WP_CLI::error( 'Failed to attach thumbnail "' . $image_url . '" to event.' ); |
|
} |
|
$update_map['_thumbnail_id'] = $thumbnail_id; |
|
} |
|
|
|
if ( ! empty( $organizer ) ) { |
|
if ( count( $organizer ) === 1 ) { |
|
$update_map['organizer'] = $organizer; |
|
} else { |
|
$picks = array_rand( $organizer, mt_rand( 1, count( $organizer ) ) ); |
|
if ( count( $picks ) ) { |
|
$update_map['organizer'] = array_map( static function ( $pick ) use ( $organizer ) { |
|
return $organizer[ $pick ]; |
|
}, (array) $picks ); |
|
} |
|
} |
|
} |
|
|
|
if ( ! empty( $categories ) ) { |
|
$taxonomy_obj = get_taxonomy( 'tribe_events_cat' ); |
|
|
|
if ( ! current_user_can( $taxonomy_obj->cap->assign_terms ) ) { |
|
$first_admin = get_users( [ 'role' => 'administrator', 'number' => 1 ] ); |
|
|
|
|
|
if ( empty( $first_admin ) || ! reset( $first_admin ) instanceof \WP_User ) { |
|
\WP_CLI::error( 'Current user cannot assign taxonomy terms and no admin user was found.' ); |
|
} |
|
|
|
$first_admin = reset( $first_admin ); |
|
wp_set_current_user( $first_admin->ID ); |
|
\WP_CLI::debug( 'Current user cannot assign taxonomy, switching to user ' . $first_admin->ID . '.' ); |
|
} |
|
|
|
$update_map['category'] = $categories; |
|
} |
|
|
|
try { |
|
$created = tribe_events()->set_args( $update_map )->create(); |
|
} catch ( \Tribe__Repository__Usage_Error $e ) { |
|
\WP_CLI::error( 'Error while trying to create event: ' . $e->getMessage() ); |
|
} |
|
|
|
if ( ! $created instanceof \WP_Post ) { |
|
\WP_CLI::error( 'Error while trying to create event: created event is not a post.' ); |
|
} |
|
|
|
\WP_CLI::debug( sprintf( |
|
'Created event %s for date %s', |
|
$i, |
|
$day->format( 'Y-m-d H:i:s' ) |
|
) |
|
); |
|
|
|
// Space events out by 1 minute. |
|
$day->add( $one_minute ); |
|
$count ++; |
|
} |
|
$progress->tick(); |
|
} |
|
|
|
\Tribe__Events__Dates__Known_Range::instance()->rebuild_known_range(); |
|
|
|
$progress->finish(); |
|
\WP_CLI::success( sprintf( 'Generated %d events. Done!', $count ) ); |
|
} |
|
|
|
/** |
|
* Handles the creation of event categories. |
|
* |
|
* @param array<string,mixed> $assoc_args The associative arguments as passed by the user. |
|
* |
|
* @return array<int> The term IDs of the found, or created, categories. |
|
* |
|
* @throws \WP_CLI\ExitException If the category, or categories, specified by the user cannot be found or created. |
|
*/ |
|
function handle_categories( array $assoc_args ) { |
|
$term_ids = []; |
|
|
|
if ( ! empty( $assoc_args['category'] ) ) { |
|
$categories = Arr::list_to_array( $assoc_args['category'] ); |
|
foreach ( $categories as $category ) { |
|
$term = get_term_by( 'slug', strtolower( $category ), 'tribe_events_cat' ); |
|
|
|
if ( ! $term instanceof \WP_Term ) { |
|
$term = get_term_by( 'id', $category, 'tribe_events_cat' ); |
|
} |
|
|
|
if ( ! $term instanceof \WP_Term ) { |
|
$inserted = wp_insert_term( $category, 'tribe_events_cat', [ 'slug' => $category ] ); |
|
|
|
if ( $inserted instanceof \WP_Error ) { |
|
\WP_CLI::error( 'Error while creating the event category: ' . $inserted->get_error_message() ); |
|
} |
|
|
|
list( $term_id ) = array_values( $inserted ); |
|
|
|
$term = get_term_by( 'id', $term_id, 'tribe_events_cat' ); |
|
} |
|
|
|
if ( ! $term instanceof \WP_Term ) { |
|
\WP_CLI::error( 'Could not find or create the "' . $category . '" event category.' ); |
|
} |
|
|
|
$term_data = [ |
|
'Name' => $term->name, |
|
'Slug' => $term->slug, |
|
'ID' => $term->term_id, |
|
]; |
|
\WP_CLI::debug( 'Event category found or created: ' . wp_json_encode( $term_data ) ); |
|
|
|
$term_ids[] = $term->term_id; |
|
} |
|
|
|
return $term_ids; |
|
} |
|
} |
|
|
|
/** |
|
* Returns the detected MySQL max_packet_size value. |
|
* |
|
* ## EXAMPLES |
|
* |
|
* wp tec-mysql-packet-size |
|
*/ |
|
function msyql_packet_size() { |
|
/** @var \Tribe__Feature_Detection $feature_detection */ |
|
$feature_detection = tribe( 'feature-detection' ); |
|
\WP_CLI::success( 'MySQL detected max_packet_size: ' . $feature_detection->get_mysql_max_packet_size() ); |
|
} |
|
|
|
/** |
|
* Counts The Events Calendar events in the database. |
|
* |
|
* ## OPTIONS |
|
* |
|
* [--status=<status>] |
|
* : The status, or a comma-separated list of post statuses, of the events to count. |
|
* |
|
* ## EXAMPLES |
|
* |
|
* Count the events currently in the database. |
|
* wp tec-count |
|
* |
|
* Count the events currently in the database that are in the "publish" post status. |
|
* wp tec-count --status=publish |
|
* |
|
* Count the events currently in the database that are in the "private" or "draft" post status. |
|
* wp tec-count --status=publish,draft |
|
*/ |
|
function count_events( array $args, array $assoc_args ) { |
|
$status = Arr::get( $assoc_args, 'status', 'any' ); |
|
|
|
\WP_CLI::line( tribe_events()->where( 'status', $status )->found() ); |
|
} |