*/
private $template_form = array(
'recipient_type' => 'customer',
'order_status' => 'wc-processing',
'scheme' => 'sms',
'message' => '',
'preview_order' => '',
);
/**
* Constructor.
*/
public function __construct() {
$this->template_repository = new TemplateRepository();
$this->template_renderer = new TemplateRenderer();
}
/**
* Render page.
*/
public function render(): void {
$this->prepare_page();
$notice = $this->handle_template_submit();
$status_notice = $this->handle_statuses_submit();
if ( null === $notice ) {
$notice = $status_notice;
}
$tabs = array(
'statuses' => __( 'Statuses', 'inteltele' ),
'templates' => __( 'Messages', 'inteltele' ),
);
$tab = $this->get_current_tab( 'statuses', array_keys( $tabs ) );
$this->open_page( __( 'WooCommerce', 'inteltele' ) );
$this->render_tabs( $tabs, $tab, 'inteltele-woocommerce' );
$this->render_step_notice();
$this->render_notice( $notice );
if ( 'templates' === $tab ) {
$this->render_templates_tab();
} else {
$this->render_statuses_tab();
}
$this->close_page();
}
/**
* Handle template form submission.
*
* @return array{type:string,messages:string[]}|null
*/
private function handle_template_submit(): ?array {
if ( ! $this->is_post_request() ) {
return null;
}
$action = isset( $_POST['inteltele_action'] ) ? sanitize_key( wp_unslash( $_POST['inteltele_action'] ) ) : '';
if ( ! in_array( $action, array( 'save_template', 'preview_template' ), true ) ) {
return null;
}
if ( ! current_user_can( 'inteltele_manage' ) ) {
return array(
'type' => 'error',
'messages' => array( __( 'You do not have permission to manage IntelTele templates.', 'inteltele' ) ),
);
}
if ( ! isset( $_POST['inteltele_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['inteltele_nonce'] ) ), 'inteltele_save_template' ) ) {
return array(
'type' => 'error',
'messages' => array( __( 'Security check failed. Please reload the page and try again.', 'inteltele' ) ),
);
}
$this->template_form = array(
'recipient_type' => isset( $_POST['recipient_type'] ) ? sanitize_key( wp_unslash( $_POST['recipient_type'] ) ) : 'customer',
'order_status' => isset( $_POST['order_status'] ) ? sanitize_key( wp_unslash( $_POST['order_status'] ) ) : 'wc-processing',
'scheme' => isset( $_POST['scheme'] ) ? sanitize_key( wp_unslash( $_POST['scheme'] ) ) : 'sms',
'message' => isset( $_POST['message'] ) ? sanitize_textarea_field( wp_unslash( $_POST['message'] ) ) : '',
'preview_order' => isset( $_POST['preview_order'] ) ? (string) absint( wp_unslash( $_POST['preview_order'] ) ) : '',
);
$errors = $this->validate_template_form();
if ( ! empty( $errors ) ) {
return array(
'type' => 'error',
'messages' => $errors,
);
}
if ( 'preview_template' === $action ) {
return null;
}
$saved = $this->template_repository->save(
$this->template_form['recipient_type'],
$this->template_form['order_status'],
$this->template_form['scheme'],
$this->template_form['message'],
get_current_user_id()
);
if ( $saved ) {
$saved = $this->get_settings_repository()->save_wc_template_scheme(
$this->template_form['recipient_type'],
$this->template_form['order_status'],
$this->template_form['scheme']
);
}
if ( ! $saved ) {
return array(
'type' => 'error',
'messages' => array( __( 'Template could not be saved. Please try again.', 'inteltele' ) ),
);
}
return array(
'type' => 'success',
'messages' => array( __( 'Saved.', 'inteltele' ) ),
);
}
/**
* Validate template form.
*
* @return string[]
*/
private function validate_template_form(): array {
$errors = array();
if ( ! in_array( $this->template_form['recipient_type'], array( 'customer', 'admin' ), true ) ) {
$errors[] = __( 'Recipient type is invalid.', 'inteltele' );
}
if ( ! array_key_exists( $this->template_form['order_status'], $this->get_order_statuses() ) ) {
$errors[] = __( 'Order status is invalid.', 'inteltele' );
}
if ( ! in_array( $this->template_form['scheme'], array( 'sms', 'viber', 'viber_sms' ), true ) ) {
$errors[] = __( 'Selected sending scheme is invalid.', 'inteltele' );
}
if ( '' === trim( $this->template_form['message'] ) ) {
$errors[] = __( 'Message text is required.', 'inteltele' );
}
$limit = 'sms' === $this->template_form['scheme'] ? 256 : 1000;
if ( $this->string_length( $this->template_form['message'] ) > $limit ) {
$errors[] = sprintf(
/* translators: %d: character limit. */
__( 'Message text must not exceed %d characters.', 'inteltele' ),
$limit
);
}
return $errors;
}
/**
* Get UTF-8 string length.
*
* @param string $value Value.
*/
private function string_length( string $value ): int {
if ( function_exists( 'mb_strlen' ) ) {
return mb_strlen( $value );
}
return strlen( $value );
}
/**
* Render submit notice.
*
* @param array{type:string,messages:string[]}|null $notice Notice.
*/
private function render_notice( ?array $notice ): void {
if ( null === $notice ) {
return;
}
$class = 'success' === $notice['type'] ? 'notice-success' : 'notice-error';
echo '
';
foreach ( $notice['messages'] as $message ) {
echo '
' . esc_html( $message ) . '
';
}
echo '
';
}
/**
* Render statuses tab.
*/
private function render_statuses_tab(): void {
$statuses = $this->get_order_statuses();
$enabled = $this->get_settings_repository()->get_wc_statuses();
echo '';
}
/**
* Render templates tab.
*/
private function render_templates_tab(): void {
$this->hydrate_template_form_from_query();
$saved_template = $this->template_repository->get( $this->template_form['recipient_type'], $this->template_form['order_status'], $this->template_form['scheme'] );
if ( '' === $this->template_form['message'] && $saved_template ) {
$this->template_form['message'] = (string) $saved_template->message;
}
$unknown_variables = TemplateRenderer::find_unknown_variables( $this->template_form['message'] );
$sms_segments = SmsSegments::calculate( $this->template_form['message'] );
$preview = $this->get_template_preview();
echo '';
if ( null !== $preview ) {
echo '' . esc_html__( 'Message preview', 'inteltele' ) . '
';
echo '';
}
if ( $saved_template && ! empty( $saved_template->updated_at ) ) {
echo '';
echo esc_html(
sprintf(
/* translators: 1: date, 2: user ID. */
__( 'Last updated: %1$s by user #%2$d.', 'inteltele' ),
(string) $saved_template->updated_at,
(int) $saved_template->updated_by
)
);
echo '
';
}
}
/**
* Hydrate template form values from GET for switching saved templates.
*/
private function hydrate_template_form_from_query(): void {
if ( $this->is_post_request() ) {
return;
}
$this->template_form['recipient_type'] = isset( $this->query['recipient_type'] ) ? sanitize_key( $this->query['recipient_type'] ) : $this->template_form['recipient_type'];
$this->template_form['order_status'] = isset( $this->query['order_status'] ) ? sanitize_key( $this->query['order_status'] ) : $this->template_form['order_status'];
$this->template_form['scheme'] = isset( $this->query['scheme'] )
? sanitize_key( $this->query['scheme'] )
: $this->get_settings_repository()->get_wc_template_scheme( $this->template_form['recipient_type'], $this->template_form['order_status'] );
}
/**
* Render recent order select.
*/
private function render_order_select(): void {
echo '';
}
/**
* Get recent WooCommerce orders.
*
* @return array
*/
private function get_recent_orders(): array {
if ( ! function_exists( 'wc_get_orders' ) ) {
return array();
}
$orders = wc_get_orders(
array(
'limit' => 20,
'orderby' => 'date',
'order' => 'DESC',
'return' => 'objects',
)
);
$options = array();
foreach ( $orders as $order ) {
if ( ! is_object( $order ) || ! method_exists( $order, 'get_id' ) ) {
continue;
}
$order_id = (int) $order->get_id();
$options[ $order_id ] = sprintf(
/* translators: 1: order ID, 2: customer name. */
__( 'Order #%1$d - %2$s', 'inteltele' ),
$order_id,
method_exists( $order, 'get_formatted_billing_full_name' ) ? (string) $order->get_formatted_billing_full_name() : ''
);
}
return $options;
}
/**
* Get rendered preview text.
*/
private function get_template_preview(): ?string {
if ( '' === $this->template_form['preview_order'] ) {
return null;
}
if ( ! function_exists( 'wc_get_order' ) ) {
return __( 'WooCommerce is not available.', 'inteltele' );
}
$order = wc_get_order( absint( $this->template_form['preview_order'] ) );
if ( ! $order ) {
return __( 'Selected order was not found.', 'inteltele' );
}
return $this->template_renderer->render( $this->template_form['message'], $order );
}
/**
* Render status checkbox column.
*
* @param string $title Column title.
* @param string $name Input group name.
* @param array $statuses Order statuses.
* @param string[] $enabled Enabled status keys.
*/
private function render_status_column( string $title, string $name, array $statuses, array $enabled ): void {
echo '';
}
/**
* Handle statuses form.
*
* @return array{type:string,messages:string[]}|null
*/
private function handle_statuses_submit(): ?array {
if ( ! $this->is_post_request() ) {
return null;
}
$action = isset( $_POST['inteltele_action'] ) ? sanitize_key( wp_unslash( $_POST['inteltele_action'] ) ) : '';
if ( 'save_wc_statuses' !== $action ) {
return null;
}
if ( ! current_user_can( 'inteltele_manage' ) ) {
return array(
'type' => 'error',
'messages' => array( __( 'You do not have permission to manage WooCommerce status automation.', 'inteltele' ) ),
);
}
if ( ! isset( $_POST['inteltele_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['inteltele_nonce'] ) ), 'inteltele_save_wc_statuses' ) ) {
return array(
'type' => 'error',
'messages' => array( __( 'Security check failed. Please reload the page and try again.', 'inteltele' ) ),
);
}
$available = array_keys( $this->get_order_statuses() );
$admin = $this->sanitize_status_selection( isset( $_POST['admin_statuses'] ) ? array_map( 'sanitize_key', (array) wp_unslash( $_POST['admin_statuses'] ) ) : array(), $available );
$customer = $this->sanitize_status_selection( isset( $_POST['customer_statuses'] ) ? array_map( 'sanitize_key', (array) wp_unslash( $_POST['customer_statuses'] ) ) : array(), $available );
if ( empty( $admin ) && empty( $customer ) ) {
return array(
'type' => 'error',
'messages' => array( __( 'Select at least one order status.', 'inteltele' ) ),
);
}
$saved = $this->get_settings_repository()->save_wc_statuses(
array(
'admin' => $admin,
'customer' => $customer,
)
);
if ( ! $saved ) {
return array(
'type' => 'error',
'messages' => array( __( 'Settings could not be saved. Please try again.', 'inteltele' ) ),
);
}
return array(
'type' => 'success',
'messages' => array( __( 'Saved.', 'inteltele' ) ),
);
}
/**
* Sanitize selected statuses.
*
* @param mixed $raw Raw values.
* @param string[] $available Available statuses.
* @return string[]
*/
private function sanitize_status_selection( $raw, array $available ): array {
$values = is_array( $raw ) ? $raw : array();
$result = array();
foreach ( $values as $value ) {
$status = sanitize_key( $value );
if ( in_array( $status, $available, true ) ) {
$result[] = $status;
}
}
return array_values( array_unique( $result ) );
}
/**
* Get settings repository.
*/
private function get_settings_repository(): \IntelTele\Repositories\SettingsRepository {
static $repository = null;
if ( null === $repository ) {
$repository = new \IntelTele\Repositories\SettingsRepository();
}
return $repository;
}
/**
* Get WooCommerce statuses or fallback defaults.
*
* @return array
*/
private function get_order_statuses(): array {
if ( function_exists( 'wc_get_order_statuses' ) ) {
return wc_get_order_statuses();
}
return array(
'wc-pending' => __( 'Pending payment', 'inteltele' ),
'wc-processing' => __( 'Processing', 'inteltele' ),
'wc-on-hold' => __( 'On hold', 'inteltele' ),
'wc-completed' => __( 'Completed', 'inteltele' ),
'wc-cancelled' => __( 'Cancelled', 'inteltele' ),
'wc-refunded' => __( 'Refunded', 'inteltele' ),
'wc-failed' => __( 'Failed', 'inteltele' ),
);
}
}