array(
'name' => __( 'Quote Requests', 'boring-quote' ),
'singular_name' => __( 'Quote Request', 'boring-quote' ),
'edit_item' => __( 'Edit Quote Request', 'boring-quote' ),
'view_item' => __( 'View Quote Request', 'boring-quote' ),
'search_items' => __( 'Search Quote Requests', 'boring-quote' ),
'not_found' => __( 'No quote requests found.', 'boring-quote' ),
'not_found_in_trash' => __( 'No quote requests found in Trash.', 'boring-quote' ),
),
'public' => false,
'show_ui' => true,
'show_in_menu' => 'woocommerce',
'supports' => array( 'title' ),
'capability_type' => array( 'bbquote_quote', 'bbquote_quotes' ),
'capabilities' => array( 'create_posts' => 'do_not_allow' ),
'map_meta_cap' => true,
'exclude_from_search' => true,
)
);
foreach ( self::statuses() as $status => $label ) {
register_post_status(
$status,
array(
'label' => $label,
'public' => false,
'protected' => true, // Needed for the admin "All" view (WP_Query only lists public/protected/private).
'exclude_from_search' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
// translators: %s: number of quotes.
'label_count' => array(
'singular' => $label . ' (%s)',
'plural' => $label . ' (%s)',
'context' => null,
'domain' => null,
),
)
);
}
}
/**
* Quote statuses. All of them can be set by hand in Lite; add-ons may also set them programmatically.
*
* @return array
*/
public static function statuses() {
return apply_filters(
'bbquote_quote_statuses',
array(
'bbquote-new' => __( 'New', 'boring-quote' ),
'bbquote-pending' => __( 'In progress', 'boring-quote' ),
'bbquote-sent' => __( 'Offer sent', 'boring-quote' ),
'bbquote-accepted' => __( 'Accepted', 'boring-quote' ),
'bbquote-rejected' => __( 'Rejected', 'boring-quote' ),
'bbquote-expired' => __( 'Expired', 'boring-quote' ),
)
);
}
/**
* Statuses the admin can pick by hand in the status box. Every registered quote status
* is selectable. The current status is always included, so saving never changes it by accident.
*
* @param string $current Current status of the quote.
* @return array slug => label
*/
public static function selectable_statuses( $current = '' ) {
$all = self::statuses();
$selectable = $all;
/**
* Filters the statuses the admin can pick by hand in the quote status box.
*
* @param array $selectable slug => label.
* @param array $all All registered quote statuses (slug => label).
*/
$selectable = (array) apply_filters( 'bbquote_selectable_statuses', $selectable, $all );
if ( isset( $all[ $current ] ) && ! isset( $selectable[ $current ] ) ) {
$selectable = array( $current => $all[ $current ] ) + $selectable;
}
return $selectable;
}
/**
* Saving the edit screen may only set a quote status (never e.g. "publish"). Programmatic updates
* (offer flow, trash) do not send `original_post_status` and are not affected.
*
* @param array $data Post data to be saved.
* @param array $postarr Raw post array.
* @return array
*/
public function guard_status_change( $data, $postarr ) {
if ( self::POST_TYPE !== $data['post_type'] || empty( $postarr['original_post_status'] ) ) {
return $data;
}
$original = sanitize_key( $postarr['original_post_status'] );
if ( ! isset( self::selectable_statuses( $original )[ $data['post_status'] ] ) && isset( self::statuses()[ $original ] ) ) {
$data['post_status'] = $original;
}
return $data;
}
/**
* Create a quote post from submitted data.
*
* @param array $customer Customer fields (name, email, phone, message).
* @param array $items Quote list items.
* @return int|\WP_Error Post id.
*/
public static function create_quote( $customer, $items ) {
$quote_id = wp_insert_post(
array(
'post_type' => self::POST_TYPE,
'post_status' => 'bbquote-new',
'post_title' => sprintf(
/* translators: 1: customer name, 2: date */
__( 'Quote - %1$s - %2$s', 'boring-quote' ),
sanitize_text_field( $customer['name'] ),
wp_date( get_option( 'date_format' ) . ' H:i' )
),
),
true
);
if ( is_wp_error( $quote_id ) ) {
return $quote_id;
}
update_post_meta( $quote_id, '_bbquote_items', $items );
update_post_meta( $quote_id, '_bbquote_customer', array_map( 'sanitize_textarea_field', $customer ) );
// Separate, queryable copy for the privacy exporter/eraser.
update_post_meta( $quote_id, '_bbquote_customer_email', sanitize_email( $customer['email'] ?? '' ) );
if ( is_user_logged_in() ) {
update_post_meta( $quote_id, '_bbquote_customer_user', get_current_user_id() );
}
do_action( 'bbquote_quote_created', $quote_id, $customer, $items );
return $quote_id;
}
/**
* Admin list columns.
*
* @param array $columns Columns.
* @return array
*/
public function columns( $columns ) {
return array(
'cb' => $columns['cb'],
'title' => __( 'Quote', 'boring-quote' ),
'bbquote_customer' => __( 'Customer', 'boring-quote' ),
'bbquote_items' => __( 'Items', 'boring-quote' ),
'bbquote_status' => __( 'Status', 'boring-quote' ),
'date' => __( 'Date', 'boring-quote' ),
);
}
/**
* Column content.
*
* @param string $column Column id.
* @param int $post_id Post id.
*/
public function column_content( $column, $post_id ) {
if ( 'bbquote_customer' === $column ) {
$customer = (array) get_post_meta( $post_id, '_bbquote_customer', true );
$name = isset( $customer['name'] ) ? $customer['name'] : '';
$email = isset( $customer['email'] ) ? $customer['email'] : '';
printf( '%s
%s', esc_html( $name ), esc_attr( $email ), esc_html( $email ) );
}
if ( 'bbquote_items' === $column ) {
echo esc_html( (string) count( (array) get_post_meta( $post_id, '_bbquote_items', true ) ) );
}
if ( 'bbquote_status' === $column ) {
$statuses = self::statuses();
$status = get_post_status( $post_id );
printf(
'%s',
esc_attr( str_replace( 'bbquote-', '', (string) $status ) ),
esc_html( isset( $statuses[ $status ] ) ? $statuses[ $status ] : $status )
);
}
}
/**
* Read-only meta box with request content.
*/
public function meta_boxes() {
// The default Publish box would save the quote as "publish". Replace it with a status box.
remove_meta_box( 'submitdiv', self::POST_TYPE, 'side' );
add_meta_box(
'bbquote_quote_status',
__( 'Status', 'boring-quote' ),
array( $this, 'render_status_box' ),
self::POST_TYPE,
'side',
'high'
);
add_meta_box(
'bbquote_quote_content',
__( 'Quote request', 'boring-quote' ),
array( $this, 'render_meta_box' ),
self::POST_TYPE,
'normal',
'high'
);
}
/**
* Render the read-only quote view.
*
* @param \WP_Post $post Post.
*/
public function render_meta_box( $post ) {
self::render_customer_details( $post->ID );
/**
* Whether to render the default read-only product table.
* Pro returns false and renders its editable quote editor via `bbquote_admin_quote_view`.
*
* @param bool $render Render default view.
* @param \WP_Post $post Quote post.
*/
if ( ! apply_filters( 'bbquote_render_default_quote_view', true, $post ) ) {
do_action( 'bbquote_admin_quote_view', $post );
return;
}
echo '
| ' . esc_html__( 'Product', 'boring-quote' ) . ' | ' . esc_html__( 'Qty', 'boring-quote' ) . ' |
|---|---|
%s%s | %d |
| %s | %d |