From 15f0c6b3d82dc1589c4f613fd91c631308a7afbe Mon Sep 17 00:00:00 2001
From: Brian DiChiara <122309362+bd-viget@users.noreply.github.com>
Date: Thu, 21 Dec 2023 09:24:31 -0600
Subject: [PATCH] Auction Status & Auction Start Cron (#111)
* [#81] Set and Get the GUID for Auctions
* [#81] Added Auction End Date/Time field
* [#81] API access method + documentation
* Fix a PHP bug.
* VS Code settings and extensions recommendations
* Update Auction Meta Box, Determine Auction Status
* Just some PR feedback that got left off.
* [#26] Data validation, restructure, & Status Column
* [#26] Added Time Until info
* Styling tweaks
* [#26] Update Auction meta when auction has started.
* [#26] Cron hook documentation
* [#26] Last minute tweaks.
* [#26] Better method name.
* [#26] Removed a space
* [#26] Swap API for $this
* [#26] More last second fixes.
* [N/A] Modified Auction Metrics block.
* [N/A] Last change to Pattern
---------
Co-authored-by: Nathan Schmidt <91974372+nathan-schmidt-viget@users.noreply.github.com>
---
.../blocks/auction-metrics-general/block.json | 15 +
.../blocks/auction-metrics-general/render.php | 50 +++
.../blocks/reward-product-gallery/block.php | 38 ++-
.../goodbids/blocks/reward-product/block.json | 15 -
.../goodbids/blocks/reward-product/render.php | 41 ---
.../src/classes/Auctions/Auctions.php | 320 +++++++++++++++---
.../goodbids/src/classes/Auctions/Bids.php | 2 +-
.../goodbids/src/classes/Network/Sites.php | 7 +-
.../goodbids/views/admin/auctions/details.php | 27 ++
.../goodbids/views/admin/auctions/metrics.php | 48 +++
.../patterns/template-archive-auction.php | 2 +-
.../views/patterns/template-auction.php | 3 +-
docs/hooks/actions.md | 14 +
13 files changed, 447 insertions(+), 135 deletions(-)
create mode 100644 client-mu-plugins/goodbids/blocks/auction-metrics-general/block.json
create mode 100644 client-mu-plugins/goodbids/blocks/auction-metrics-general/render.php
delete mode 100644 client-mu-plugins/goodbids/blocks/reward-product/block.json
delete mode 100644 client-mu-plugins/goodbids/blocks/reward-product/render.php
create mode 100644 client-mu-plugins/goodbids/views/admin/auctions/details.php
create mode 100644 client-mu-plugins/goodbids/views/admin/auctions/metrics.php
diff --git a/client-mu-plugins/goodbids/blocks/auction-metrics-general/block.json b/client-mu-plugins/goodbids/blocks/auction-metrics-general/block.json
new file mode 100644
index 000000000..358cdb07e
--- /dev/null
+++ b/client-mu-plugins/goodbids/blocks/auction-metrics-general/block.json
@@ -0,0 +1,15 @@
+{
+ "name": "auction-metrics-general",
+ "title": "Auction Metrics (General)",
+ "description": "Displays the general Auction metrics.",
+ "icon": "awards",
+ "category": "goodbids",
+ "textdomain": "goodbids",
+ "keywords": ["custom", "details", "stats", "auction"],
+ "acf": {
+ "mode": "preview"
+ },
+ "supports": {
+ "jsx": false
+ }
+}
diff --git a/client-mu-plugins/goodbids/blocks/auction-metrics-general/render.php b/client-mu-plugins/goodbids/blocks/auction-metrics-general/render.php
new file mode 100644
index 000000000..7b57c6add
--- /dev/null
+++ b/client-mu-plugins/goodbids/blocks/auction-metrics-general/render.php
@@ -0,0 +1,50 @@
+auctions->get_goal();
+$estimated_value = goodbids()->auctions->get_estimated_value();
+$expected_high_bid = goodbids()->auctions->get_expected_high_bid();
+
+// Display an Admin message to make the block easier to find.
+if ( ! $goal && ! $estimated_value && ! $expected_high_bid && is_admin() ) :
+ printf(
+ '
%s
',
+ esc_html__( 'No stats yet.', 'goodbids' )
+ );
+ return;
+endif;
+?>
+>
+ %s',
+ esc_html__( wc_price( $goal ), 'goodbids' )
+ );
+ endif;
+
+ // Estimated Value.
+ if ( $estimated_value ) :
+ printf(
+ '%s
',
+ esc_html__( wc_price( $estimated_value ), 'goodbids' )
+ );
+ endif;
+
+ // Expected High Bid.
+ if ( $expected_high_bid ) :
+ printf(
+ '%s
',
+ esc_html__( wc_price( $expected_high_bid ), 'goodbids' )
+ );
+ endif;
+ ?>
+
diff --git a/client-mu-plugins/goodbids/blocks/reward-product-gallery/block.php b/client-mu-plugins/goodbids/blocks/reward-product-gallery/block.php
index c99c18131..a8b21e439 100644
--- a/client-mu-plugins/goodbids/blocks/reward-product-gallery/block.php
+++ b/client-mu-plugins/goodbids/blocks/reward-product-gallery/block.php
@@ -1,29 +1,33 @@
auctions->get_post_type() ) ) {
+ return;
+ }
+
+ if ( current_theme_supports( 'wc-product-gallery-zoom' ) ) {
+ wp_enqueue_script( 'zoom' );
+ }
+ if ( current_theme_supports( 'wc-product-gallery-slider' ) ) {
+ wp_enqueue_script( 'flexslider' );
+ }
+ if ( current_theme_supports( 'wc-product-gallery-lightbox' ) ) {
+ wp_enqueue_script( 'photoswipe-ui-default' );
+ wp_enqueue_style( 'photoswipe-default-skin' );
+ add_action( 'wp_footer', 'woocommerce_photoswipe' );
}
+ wp_enqueue_script( 'wc-single-product' );
}
);
diff --git a/client-mu-plugins/goodbids/blocks/reward-product/block.json b/client-mu-plugins/goodbids/blocks/reward-product/block.json
deleted file mode 100644
index f668b4b27..000000000
--- a/client-mu-plugins/goodbids/blocks/reward-product/block.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "reward-product",
- "title": "Reward Product",
- "description": "Displays the reward product information",
- "icon": "awards",
- "category": "goodbids",
- "textdomain": "goodbids",
- "keywords": ["custom", "product", "reward", "auction"],
- "acf": {
- "mode": "preview"
- },
- "supports": {
- "jsx": false
- }
-}
diff --git a/client-mu-plugins/goodbids/blocks/reward-product/render.php b/client-mu-plugins/goodbids/blocks/reward-product/render.php
deleted file mode 100644
index 305d9535d..000000000
--- a/client-mu-plugins/goodbids/blocks/reward-product/render.php
+++ /dev/null
@@ -1,41 +0,0 @@
-auctions->get_goal();
-$estimated_value = goodbids()->auctions->get_estimated_value();
-$expected_high_bid = goodbids()->auctions->get_expected_high_bid();
-?>
->
- %s',
- esc_html__( $goal, 'goodbids' )
- );
- }
-
- // Estimated Value
- if ( $estimated_value ) {
- printf(
- '%s
',
- esc_html__( $estimated_value, 'goodbids' )
- );
- }
-
- // Expected High Bid
- if ( $expected_high_bid ) {
- printf(
- '%s
',
- esc_html__( $expected_high_bid, 'goodbids' )
- );
- }
- ?>
-
diff --git a/client-mu-plugins/goodbids/src/classes/Auctions/Auctions.php b/client-mu-plugins/goodbids/src/classes/Auctions/Auctions.php
index ed288f1d6..185a5ec99 100644
--- a/client-mu-plugins/goodbids/src/classes/Auctions/Auctions.php
+++ b/client-mu-plugins/goodbids/src/classes/Auctions/Auctions.php
@@ -9,6 +9,7 @@
namespace GoodBids\Auctions;
use WC_Order;
+use WP_Query;
/**
* Class for Auctions
@@ -53,12 +54,30 @@ class Auctions {
*/
const GUID_META_KEY = 'gb_guid';
+ /**
+ * @since 1.0.0
+ * @var string
+ */
+ const CRON_AUCTION_START_HOOK = 'goodbids_auction_start_event';
+
+ /**
+ * @since 1.0.0
+ * @var string
+ */
+ const AUCTION_STARTED_META_KEY = '_auction_started';
+
/**
* @since 1.0.0
* @var Bids
*/
public Bids $bids;
+ /**
+ * @since 1.0.0
+ * @var string
+ */
+ public string $cron_interval = '1min';
+
/**
* Initialize Auctions
*
@@ -74,12 +93,15 @@ public function __construct() {
// Init Rewards Category.
$this->init_rewards_category();
- // Add Auction Metrics Meta Box.
- $this->add_metrics_meta_box();
+ // Add Auction Meta Box to display details and metrics.
+ $this->add_info_meta_box();
// Add custom Admin Columns for Auctions.
$this->add_admin_columns();
+ // Configure some values for new Auction posts.
+ $this->new_auction_post_init();
+
// Update Bid Product when Auction is updated.
$this->update_bid_product_on_auction_update();
@@ -91,6 +113,15 @@ public function __construct() {
// Generate a unique ID for each Auction.
$this->generate_guid_on_publish();
+
+ // Set up 1min Cron Job Schedule.
+ $this->add_one_min_cron_schedule();
+
+ // Schedule a cron job to trigger the start of auctions.
+ $this->schedule_bid_start_cron();
+
+ // Use cron action to start auctions.
+ $this->check_for_starting_auctions();
}
/**
@@ -165,7 +196,7 @@ function () {
'template' => $this->get_template(),
];
- register_post_type( self::POST_TYPE, $args );
+ register_post_type( $this->get_post_type(), $args );
}
);
}
@@ -359,7 +390,13 @@ public function get_estimated_value( int $auction_id = null ): int {
* @return string
*/
public function get_start_date_time( int $auction_id = null ): string {
- return $this->get_setting( 'auction_start', $auction_id );
+ $start = $this->get_setting( 'auction_start', $auction_id );
+
+ if ( ! $start ) {
+ return '';
+ }
+
+ return $start;
}
/**
@@ -372,7 +409,13 @@ public function get_start_date_time( int $auction_id = null ): string {
* @return string
*/
public function get_end_date_time( int $auction_id = null ): string {
- return $this->get_setting( 'auction_end', $auction_id );
+ $end = $this->get_setting( 'auction_end', $auction_id );
+
+ if ( ! $end ) {
+ return '';
+ }
+
+ return $end;
}
/**
@@ -386,11 +429,33 @@ public function get_end_date_time( int $auction_id = null ): string {
*/
public function has_started( int $auction_id = null ): bool {
$start_date_time = $this->get_start_date_time( $auction_id );
+
if ( ! $start_date_time ) {
+ // TODO: Log error.
+ return false;
+ }
+
+ return strtotime( $start_date_time ) < current_datetime()->format( 'U' );
+ }
+
+ /**
+ * Check if an Auction has ended.
+ *
+ * @since 1.0.0
+ *
+ * @param ?int $auction_id
+ *
+ * @return bool
+ */
+ public function has_ended( int $auction_id = null ): bool {
+ $end_date_time = $this->get_end_date_time( $auction_id );
+
+ if ( ! $end_date_time ) {
+ // TODO: Log error.
return false;
}
- return strtotime( $start_date_time ) < time();
+ return strtotime( $end_date_time ) < current_datetime()->format( 'U' );
}
/**
@@ -463,6 +528,34 @@ public function get_expected_high_bid( int $auction_id = null ): int {
return intval( $this->get_setting( 'expected_high_bid', $auction_id ) );
}
+ /**
+ * Update Auction with some initial data when created.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function new_auction_post_init(): void {
+ add_action(
+ 'wp_after_insert_post',
+ function ( $post_id ): void {
+ // Bail if this is a revision.
+ if ( wp_is_post_revision( $post_id ) || 'publish' !== get_post_status( $post_id ) ) {
+ return;
+ }
+
+ // Bail if not an Auction.
+ if ( $this->get_post_type() !== get_post_type( $post_id ) ) {
+ return;
+ }
+
+ // Set started to 0 for easier querying.
+ update_post_meta( $post_id, self::AUCTION_STARTED_META_KEY, 0 );
+ },
+ 12
+ );
+ }
+
/**
* Update the Bid Product when an Auction is updated.
*
@@ -475,7 +568,7 @@ private function update_bid_product_on_auction_update(): void {
'save_post',
function ( int $post_id ) {
// Bail if not an Auction and not published.
- if ( wp_is_post_revision( $post_id ) || 'publish' !== get_post_status( $post_id ) || self::POST_TYPE !== get_post_type( $post_id ) ) {
+ if ( wp_is_post_revision( $post_id ) || 'publish' !== get_post_status( $post_id ) || $this->get_post_type() !== get_post_type( $post_id ) ) {
return;
}
@@ -664,13 +757,40 @@ public function get_last_bid( int $auction_id ): ?WC_Order {
}
/**
- * Add a meta box to show Auction metrics.
+ * Get the status of an Auction.
+ *
+ * @since 1.0.0
+ *
+ * @param int $auction_id
+ *
+ * @return string
+ */
+ public function get_status( int $auction_id ): string {
+ if ( 'publish' !== get_post_status( $auction_id ) ) {
+ return __( 'Draft', 'goodbids' );
+ }
+
+ $status = __( 'Upcoming', 'goodbids' );
+
+ if ( $this->has_started( $auction_id ) ) {
+ $status = __( 'Live', 'goodbids' );
+ }
+
+ if ( $this->has_ended( $auction_id ) ) {
+ $status = __( 'Closed', 'goodbids' );
+ }
+
+ return $status;
+ }
+
+ /**
+ * Add a meta box to show Auction metrics and other details.
*
* @since 1.0.0
*
* @return void
*/
- private function add_metrics_meta_box(): void {
+ private function add_info_meta_box(): void {
add_action(
'current_screen',
function (): void {
@@ -681,9 +801,9 @@ function (): void {
}
add_meta_box(
- 'goodbids-auction-metrics',
- __( 'Auction Metrics', 'goodbids' ),
- [ $this, 'metrics_meta_box' ],
+ 'goodbids-auction-info',
+ __( 'Auction Info', 'goodbids' ),
+ [ $this, 'info_meta_box' ],
$screen->id,
'side'
);
@@ -722,49 +842,31 @@ function ( int $order_id, int $auction_id ) {
}
/**
- * Display the Auction Metrics
+ * Display the Auction Metrics and other details.
*
* @since 1.0.0
*
* @return void
*/
- public function metrics_meta_box(): void {
+ public function info_meta_box(): void {
$auction_id = $this->get_auction_id();
- printf(
- '%s
%s
',
- esc_html__( 'Total Bids', 'goodbids' ),
- esc_html( $this->get_bid_count( $auction_id ) )
- );
+ // Display the Auction Details.
+ include GOODBIDS_PLUGIN_PATH . 'views/admin/auctions/details.php';
- printf(
- '%s
%s
',
- esc_html__( 'Total Raised', 'goodbids' ),
- wp_kses_post( wc_price( $this->get_total_raised( $auction_id ) ) )
- );
+ echo '
';
- $bid_product = wc_get_product( $this->get_bid_product_id( $auction_id ) );
-
- if ( $bid_product ) :
- printf(
- '%s
%s
',
- esc_html__( 'Current Bid', 'goodbids' ),
- wp_kses_post( wc_price( $bid_product->get_price() ) )
- );
- endif;
-
- $last_bid = $this->get_last_bid( $auction_id );
-
- if ( $last_bid ) {
- printf(
- '%s
%s
',
- esc_html__( 'Last Bid', 'goodbids' ),
- esc_url( get_edit_post_link( $last_bid->get_id() ) ),
- wp_kses_post( wc_price( $last_bid->get_total() ) )
- );
- }
+ // Display the Auction Metrics.
+ include GOODBIDS_PLUGIN_PATH . 'views/admin/auctions/metrics.php';
}
+ /**
+ * Insert custom metrics admin columns
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
private function add_admin_columns(): void {
add_filter(
'manage_' . $this->get_post_type() . '_posts_columns',
@@ -776,6 +878,7 @@ function ( array $columns ): array {
// Insert Custom Columns after the Title column.
if ( 'title' === $column ) {
+ $new_columns['status'] = __( 'Status', 'goodbids' );
$new_columns['starting_bid'] = __( 'Starting Bid', 'goodbids' );
$new_columns['bid_increment'] = __( 'Bid Increment', 'goodbids' );
$new_columns['total_bids'] = __( 'Total Bids', 'goodbids' );
@@ -792,7 +895,8 @@ function ( array $columns ): array {
add_action(
'manage_' . $this->get_post_type() . '_posts_custom_column',
function ( $column, $post_id ) {
- $bid_cols = [
+ // Columns that require a "published" status.
+ $published_cols = [
'starting_bid',
'bid_increment',
'total_bids',
@@ -802,13 +906,15 @@ function ( $column, $post_id ) {
];
// Bail early if Auction isn't published.
- if ( in_array( $column, $bid_cols, true ) && 'publish' !== get_post_status( $post_id ) ) {
+ if ( in_array( $column, $published_cols, true ) && 'publish' !== get_post_status( $post_id ) ) {
echo '—';
return;
}
// Output the column values.
- if ( 'starting_bid' === $column ) {
+ if ( 'status' === $column ) {
+ echo esc_html( $this->get_status( $post_id ) );
+ } elseif ( 'starting_bid' === $column ) {
echo wp_kses_post( wc_price( $this->calculate_starting_bid( $post_id ) ) );
} elseif ( 'bid_increment' === $column ) {
echo wp_kses_post( wc_price( $this->get_bid_increment( $post_id ) ) );
@@ -844,12 +950,10 @@ function ( string $html, int $post_id ) {
return $html;
}
- $reward_id = goodbids()->auctions->get_reward_product_id( $post_id );
- $product = wc_get_product( $reward_id );
- $image_html = $product->get_image();
- return sprintf(
- $image_html,
- );
+ $reward_id = $this->get_reward_product_id( $post_id );
+ $product = wc_get_product( $reward_id );
+
+ return $product->get_image();
},
10,
2
@@ -903,4 +1007,114 @@ function ( $post_id ): void {
}
);
}
+
+ /**
+ * Add a 1min Cron Job Schedule.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function add_one_min_cron_schedule(): void {
+ add_filter(
+ 'cron_schedules', // phpcs:ignore
+ function ( array $schedules ): array {
+ // If one is already set, confirm it matches our schedule.
+ if ( ! empty( $schedules[ $this->cron_interval ] ) ) {
+ if ( MINUTE_IN_SECONDS === $schedules[ $this->cron_interval ]['interval'] ) {
+ return $schedules;
+ }
+
+ $this->cron_interval = '1minute';
+ }
+
+ // Adds every minute cron schedule.
+ $schedules[ $this->cron_interval ] = [
+ 'interval' => MINUTE_IN_SECONDS,
+ 'display' => __( 'Once Every Minute', 'goodbids' ),
+ ];
+
+ return $schedules;
+ }
+ );
+ }
+
+ /**
+ * Schedule a cron job that runs every minute to trigger auctions to start.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function schedule_bid_start_cron(): void {
+ add_action(
+ 'init',
+ function (): void {
+ if ( wp_next_scheduled( self::CRON_AUCTION_START_HOOK ) ) {
+ return;
+ }
+
+ wp_schedule_event( current_datetime()->format( 'U' ), $this->cron_interval, self::CRON_AUCTION_START_HOOK );
+ }
+ );
+ }
+
+ /**
+ * Check for Auctions that are starting during cron hook.
+ *
+ * @since 1.0.0
+ *
+ * @return void
+ */
+ private function check_for_starting_auctions(): void {
+ add_action(
+ self::CRON_AUCTION_START_HOOK,
+ function (): void {
+ $auctions = $this->get_starting_auctions();
+
+ if ( ! $auctions->have_posts() ) {
+ return;
+ }
+
+ foreach ( $auctions->posts as $auction_id ) {
+ // TODO: Tell Node first.
+ // TODO: Wrap in condition based on Node API response.
+ // Update the Auction meta to indicate it has started.
+ update_post_meta( $auction_id, self::AUCTION_STARTED_META_KEY, 1 );
+ }
+ }
+ );
+ }
+
+ /**
+ * Get Auctions that are starting.
+ *
+ * @since 1.0.0
+ *
+ * @return WP_Query
+ */
+ private function get_starting_auctions(): WP_Query {
+ // Use the current time + 1min to get Auctions about to start.
+ $auction_start = current_datetime()->add( new \DateInterval( 'PT1M' ) )->format( 'Y-m-d H:i:s' );
+
+ $args = [
+ 'post_type' => $this->get_post_type(),
+ 'post_status' => 'publish',
+ 'posts_per_page' => -1,
+ 'return' => 'ids',
+ 'meta_query' => [
+ [
+ 'key' => 'auction_start',
+ 'value' => $auction_start,
+ 'compare' => '<=',
+ ],
+ [
+ 'key' => self::AUCTION_STARTED_META_KEY,
+ 'value' => 0,
+ ],
+ ],
+ ];
+
+ return new WP_Query( $args );
+ }
}
diff --git a/client-mu-plugins/goodbids/src/classes/Auctions/Bids.php b/client-mu-plugins/goodbids/src/classes/Auctions/Bids.php
index b0150c3f9..067583cb4 100644
--- a/client-mu-plugins/goodbids/src/classes/Auctions/Bids.php
+++ b/client-mu-plugins/goodbids/src/classes/Auctions/Bids.php
@@ -57,7 +57,7 @@ function ( $post_id ): void {
}
// Bail if not an Auction.
- if ( Auctions::POST_TYPE !== get_post_type( $post_id ) ) {
+ if ( goodbids()->auctions->get_post_type() !== get_post_type( $post_id ) ) {
return;
}
diff --git a/client-mu-plugins/goodbids/src/classes/Network/Sites.php b/client-mu-plugins/goodbids/src/classes/Network/Sites.php
index 20fd3d838..ac9929eee 100644
--- a/client-mu-plugins/goodbids/src/classes/Network/Sites.php
+++ b/client-mu-plugins/goodbids/src/classes/Network/Sites.php
@@ -422,7 +422,7 @@ function ( string $html, int $blog_id ) {
}
/**
- * Set the archive to show nine posts per pagination
+ * Set the archive default to show 9 posts per page
*
* @since 1.0.0
*
@@ -432,10 +432,7 @@ private function set_default_posts_per_page(): void {
add_action(
'goodbids_init_site',
function ( int $site_id ): void {
- update_option(
- 'posts_per_page',
- 9
- );
+ update_option( 'posts_per_page', 9 );
}
);
}
diff --git a/client-mu-plugins/goodbids/views/admin/auctions/details.php b/client-mu-plugins/goodbids/views/admin/auctions/details.php
new file mode 100644
index 000000000..7f41c4013
--- /dev/null
+++ b/client-mu-plugins/goodbids/views/admin/auctions/details.php
@@ -0,0 +1,27 @@
+
+
+
+get_start_date_time();
+
+printf(
+ '%s
%s%s
',
+ esc_html__( 'Status', 'goodbids' ),
+ esc_html( $this->get_status( $auction_id ) ),
+
+ $start_time ? sprintf(
+ ' (%s)',
+ esc_html( human_time_diff( current_datetime()->format( 'U' ), strtotime( $start_time ) ) )
+ ) : ''
+);
diff --git a/client-mu-plugins/goodbids/views/admin/auctions/metrics.php b/client-mu-plugins/goodbids/views/admin/auctions/metrics.php
new file mode 100644
index 000000000..2a7f1d003
--- /dev/null
+++ b/client-mu-plugins/goodbids/views/admin/auctions/metrics.php
@@ -0,0 +1,48 @@
+get_bid_product_id( $auction_id ) );
+$last_bid = $this->get_last_bid( $auction_id );
+?>
+
+
+
+
%s%s',
+ esc_html__( 'Total Bids', 'goodbids' ),
+ esc_html( $this->get_bid_count( $auction_id ) )
+ );
+
+ printf(
+ '
%s
%s
',
+ esc_html__( 'Total Raised', 'goodbids' ),
+ wp_kses_post( wc_price( $this->get_total_raised( $auction_id ) ) )
+ );
+
+ if ( $bid_product ) :
+ printf(
+ '
%s
%s
',
+ esc_html__( 'Current Bid', 'goodbids' ),
+ wp_kses_post( wc_price( $bid_product->get_price() ) )
+ );
+ endif;
+
+ if ( $last_bid ) :
+ printf(
+ '
%s
%s
',
+ esc_html__( 'Last Bid', 'goodbids' ),
+ esc_url( get_edit_post_link( $last_bid->get_id() ) ),
+ wp_kses_post( wc_price( $last_bid->get_total() ) )
+ );
+ endif;
+ ?>
+
diff --git a/client-mu-plugins/goodbids/views/patterns/template-archive-auction.php b/client-mu-plugins/goodbids/views/patterns/template-archive-auction.php
index 309f5c201..788f4ed66 100644
--- a/client-mu-plugins/goodbids/views/patterns/template-archive-auction.php
+++ b/client-mu-plugins/goodbids/views/patterns/template-archive-auction.php
@@ -5,8 +5,8 @@
* @since 1.0.0
* @package GoodBids
*/
-?>
+?>
diff --git a/client-mu-plugins/goodbids/views/patterns/template-auction.php b/client-mu-plugins/goodbids/views/patterns/template-auction.php
index 9cf1c5305..37c2f8ac8 100644
--- a/client-mu-plugins/goodbids/views/patterns/template-auction.php
+++ b/client-mu-plugins/goodbids/views/patterns/template-auction.php
@@ -9,7 +9,6 @@
*/
?>
-
@@ -28,7 +27,7 @@
-
+
diff --git a/docs/hooks/actions.md b/docs/hooks/actions.md
index 31e0c19c6..92186fe21 100644
--- a/docs/hooks/actions.md
+++ b/docs/hooks/actions.md
@@ -26,3 +26,17 @@ add_action(
}
);
```
+### goodbids_auction_start_event
+
+Cron event, fired every minute.
+
+> **Be EXTREMELY CAUTIOUS using this hook.**
+
+```php
+add_action(
+ 'goodbids_auction_start_event',
+ function (): void {
+ // Are you sure you want to use this hook?
+ }
+);
+```