$errors */
private static function render_step( int $step, array $settings, array $facts, string $language, array $errors ): void {
switch ( $step ) {
case 1:
self::step_languages( $settings, $facts, $language, $errors );
break;
case 2:
self::step_business( $settings, $language, $errors );
break;
case 3:
self::step_sales( $settings, $language, $errors );
break;
case 4:
self::step_terms( $settings, $facts, $language, $errors );
break;
case 5:
self::step_delivery( $settings, $facts, $language, $errors );
break;
case 6:
self::step_documents( $settings, $facts, $language, $errors );
break;
}
}
private static function step_languages( array $settings, array $facts, string $language, array $errors ): void {
$languages = (array) $settings['languages'];
$state = AuditRuntime::setup()->get_state();
$is_new = '' === (string) ( $state['updated_at'] ?? '' );
self::section_heading( $language, 'language_title', 'language_intro' );
?>
';
?>
- order_storage
- checkout_mode
- currency
- site_locale
';
self::field( 'legal_name', 'legal_name', $m['legal_name'], $language, $errors, true, 'text', 'legal_name_help' );
self::field( 'registered_name', 'registered_name', $m['registered_name'], $language, $errors, false, 'text', 'registered_name_help' );
self::field( 'registration_number', 'registration_number', $m['registration_number'], $language, $errors, true, 'text', 'registration_number_help' );
self::field( 'registration_authority', 'registration_authority', $m['registration_authority'], $language, $errors, true, 'text', 'registration_authority_help' );
self::field( 'tax_id', 'tax_id', $m['tax_id'], $language, $errors, true, 'text', 'tax_id_help' );
self::checkbox( 'vat_registered', 'vat_registered', $m['vat_registered'], $language, $errors );
self::field( 'vat_number', 'vat_number', $m['vat_number'], $language, $errors, false );
self::field( 'address', 'address', $m['address'], $language, $errors, true );
self::field( 'city', 'city', $m['city'], $language, $errors, true );
self::field( 'postcode', 'postcode', $m['postcode'], $language, $errors, true );
self::field( 'phone', 'phone', $m['phone'], $language, $errors, true, 'tel', 'phone_help', 'phone_placeholder' );
self::field( 'email', 'email', $m['email'], $language, $errors, true, 'email' );
self::field( 'site', 'site', $m['site'], $language, $errors, false, 'url' );
self::select_field(
'establishment',
'establishment',
(string) $m['establishment'],
array(
'' => self::t( $language, 'select' ),
'FBIH' => 'Federacija BiH',
'RS' => 'Republika Srpska',
'BD' => 'Brčko distrikt',
),
$language,
$errors,
true,
'establishment_help'
);
echo '';
}
private static function step_sales( array $settings, string $language, array $errors ): void {
$s = (array) $settings['sales'];
$m = (array) $settings['merchant'];
self::section_heading( $language, 'sales_title', 'sales_intro' );
echo '' . esc_html( self::t( $language, 'scope_confirmations_title' ) ) . '
' . esc_html( self::t( $language, 'self_declared' ) ) . '';
$registration_help = array(
'FBIH' => 'distance_registration_help_fbih',
'RS' => 'distance_registration_help_rs',
'BD' => 'distance_registration_help_bd',
)[ (string) ( $m['establishment'] ?? '' ) ] ?? 'distance_registration_help';
self::checkbox( 'distance_sale_registration_confirmed', 'distance_registration', $s['distance_sale_registration_confirmed'], $language, $errors, $registration_help, true );
self::checkbox( 'physical_goods_scope_confirmed', 'physical_scope', $s['physical_goods_scope_confirmed'], $language, $errors, 'physical_scope_help', true );
echo '' . esc_html( self::t( $language, 'customer_contacts_title' ) ) . '
' . esc_html( self::t( $language, 'customer_contacts_intro' ) ) . '
';
$complaints_email = '' !== (string) $s['complaints_email'] ? $s['complaints_email'] : self::legacy_email( (string) $s['complaints_contact'] );
self::field( 'complaints_email', 'complaints_email', $complaints_email, $language, $errors, false, 'email', 'complaints_email_help', '', 'conditional' );
self::field( 'complaints_phone', 'complaints_phone', $s['complaints_phone'], $language, $errors, false, 'tel', 'complaints_phone_help', 'phone_placeholder' );
echo '
';
self::checkbox( 'returns_same_as_complaints', 'returns_same', $s['returns_same_as_complaints'], $language, $errors );
echo '';
$returns_email = '' !== (string) $s['returns_email'] ? $s['returns_email'] : self::legacy_email( (string) $s['returns_contact'] );
self::field( 'returns_email', 'returns_email', $returns_email, $language, $errors, false, 'email', '', '', 'conditional' );
self::field( 'returns_phone', 'returns_phone', $s['returns_phone'], $language, $errors, false, 'tel', '', 'phone_placeholder' );
self::field( 'returns_address', 'returns_address', $s['returns_address'], $language, $errors, false, 'text', 'returns_address_help' );
echo '
' . esc_html( self::t( $language, 'returns_postal_title' ) ) . '
' . esc_html( self::t( $language, 'returns_postal_help' ) ) . '
';
self::checkbox( 'returns_use_merchant_address', 'returns_use_merchant_address', $s['returns_use_merchant_address'], $language, $errors );
echo '
';
self::field( 'returns_recipient', 'returns_recipient', $s['returns_recipient'], $language, $errors, false, 'text', '', '', 'conditional' );
self::field( 'returns_street', 'returns_street', $s['returns_street'], $language, $errors, false, 'text', '', '', 'conditional' );
self::field( 'returns_postcode', 'returns_postcode', $s['returns_postcode'], $language, $errors, false, 'text', '', '', 'conditional' );
self::field( 'returns_city', 'returns_city', $s['returns_city'], $language, $errors, false, 'text', '', '', 'conditional' );
self::field( 'returns_country', 'returns_country', $s['returns_country'], $language, $errors, false, 'text', '', '', 'conditional' );
echo '
' . esc_html( self::t( $language, 'customer_information_title' ) ) . '
' . esc_html( self::t( $language, 'self_declared' ) ) . '';
self::checkbox( 'offer_validity_configured', 'offer_validity', $s['offer_validity_configured'], $language, $errors, 'offer_validity_help', true );
self::checkbox( 'warranty_information_configured', 'warranty_information', $s['warranty_information_configured'], $language, $errors, 'warranty_information_help', true );
self::checkbox( 'sells_across_bih', 'sells_across_bih', $s['sells_across_bih'], $language, $errors, 'sells_across_bih_help' );
echo '' . esc_html( self::t( $language, 'why_cross_entity' ) ) . '
' . esc_html( self::t( $language, 'cross_entity_legal_review' ) ) . '
';
echo '' . esc_html( self::t( $language, 'supplier_title' ) ) . '
' . esc_html( self::t( $language, 'supplier_intro' ) ) . '
';
$merchant_name = trim( (string) $m['legal_name'] );
self::select_field(
'supplier_relationship',
'supplier_relationship',
(string) $m['supplier_relationship'],
array(
'SAME_AS_MERCHANT' => '' !== $merchant_name ? $merchant_name : self::t( $language, 'supplier_same_fallback' ),
'SEPARATE_CONTRACT_SUPPLIER' => self::t( $language, 'supplier_separate' ),
),
$language,
$errors,
true,
'supplier_separate_help',
'data-lmcc-supplier-select'
);
echo '';
self::field( 'separate_supplier_name', 'supplier_name', $m['separate_supplier_name'], $language, $errors, false );
self::field( 'separate_supplier_email', 'supplier_email', $m['separate_supplier_email'], $language, $errors, false, 'email' );
echo '
';
}
private static function step_terms( array $settings, array $facts, string $language, array $errors ): void {
$t = (array) $settings['terms'];
self::section_heading( $language, 'terms_title', 'terms_intro' );
echo '' . esc_html( self::t( $language, 'terms_page_heading' ) ) . '
';
$terms_ready = ! empty( $facts['terms_page_id'] ) && 'publish' === (string) ( $facts['terms_page_status'] ?? '' ) && ! empty( $facts['terms_page_url_present'] );
echo '' . esc_html( self::t( $language, $terms_ready ? 'connected' : 'needs_setup' ) ) . '';
if ( $terms_ready ) {
echo '';
} else {
echo '';
}
self::inline_error( 'terms_page', $language, $errors );
$pages = array( '' => self::t( $language, 'select_published_terms' ) );
$current = (int) ( $facts['terms_page_option_id'] ?? 0 ) > 0 ? (string) (int) $facts['terms_page_option_id'] : '';
foreach ( (array) ( $facts['published_pages'] ?? array() ) as $page ) {
if ( is_array( $page ) && ! empty( $page['id'] ) ) {
$pages[ (string) (int) $page['id'] ] = (string) ( $page['title'] ?? '#' . (int) $page['id'] );
}
}
self::select_field( 'terms_page_id', 'terms_page_select', $current, $pages, $language, $errors, false, 'terms_page_select_help' );
if ( ! empty( $facts['terms_page_id_mismatch'] ) ) {
echo '' . esc_html( self::t( $language, 'terms_resolution_details' ) ) . '
' . esc_html( self::t( $language, 'terms_resolution_mismatch', array( (string) ( $facts['terms_page_option_id'] ?? 0 ), (string) ( $facts['terms_page_wc_id'] ?? 0 ) ) ) ) . '
';
}
echo '' . esc_html( self::t( $language, 'contract_acceptance_heading' ) ) . '
' . esc_html( self::t( $language, 'contract_acceptance_help' ) ) . '
';
self::select_field(
'contract_formation_mode',
'contract_mode',
(string) $t['contract_formation_mode'],
array(
'ORDER_CREATED' => self::t( $language, 'mode_order_created' ),
'PAYMENT_COMPLETED' => self::t( $language, 'mode_payment_completed' ),
'ORDER_STATUS' => self::t( $language, 'mode_order_status' ),
'CUSTOM_PROVIDER' => self::t( $language, 'mode_custom_provider' ),
),
$language,
$errors,
true,
'',
'data-lmcc-contract-mode'
);
echo '';
$statuses = (array) ( $facts['order_statuses'] ?? array() );
$current_status = (string) $t['contract_formation_status'];
if ( '' !== $current_status && ! isset( $statuses[ $current_status ] ) ) {
$statuses = array( $current_status => self::t( $language, 'saved_status_missing', array( $current_status ) ) ) + $statuses;
}
self::select_field( 'contract_formation_status', 'contract_status', $current_status, array( '' => self::t( $language, 'select' ) ) + $statuses, $language, $errors, false, 'contract_status_help' );
echo '
';
echo '';
self::field( 'contract_formation_provider', 'contract_provider', $t['contract_formation_provider'] ?? '', $language, $errors, false );
echo '
';
self::checkbox( 'order_process_information_confirmed', 'order_process', $t['order_process_information_confirmed'], $language, $errors, 'order_process_help', true );
self::checkbox( 'terms_accessible_saveable_confirmed', 'terms_accessible', $t['terms_accessible_saveable_confirmed'], $language, $errors, 'terms_accessible_help', true );
self::checkbox( 'rs_payment_obligation_confirmed', 'rs_payment', $t['rs_payment_obligation_confirmed'], $language, $errors, 'rs_payment_help', true );
echo '' . wp_kses_post( self::brand_text( self::t( $language, 'legal_confirmation_help' ) ) ) . '
' . esc_html( self::t( $language, 'legal_review_details' ) ) . '
' . esc_html( self::t( $language, 'cross_entity_legal_review' ) ) . '
';
}
private static function step_delivery( array $settings, array $facts, string $language, array $errors ): void {
$d = (array) $settings['delivery'];
$s = (array) $settings['sales'];
self::section_heading( $language, 'delivery_title', 'delivery_intro' );
echo '';
echo '' . esc_html( self::t( $language, 'shipping_methods_heading' ) ) . '
' . esc_html( self::t( $language, 'automatically_checked' ) ) . '';
self::method_list( (array) ( $facts['shipping_methods'] ?? array() ), $language );
echo '' . esc_html( self::t( $language, 'manage_shipping_methods' ) ) . '' . esc_html( self::t( $language, 'method_detection_limit' ) ) . '
';
echo '' . esc_html( self::t( $language, 'checkout_review_heading' ) ) . '
' . esc_html( self::t( $language, 'self_declared' ) ) . '';
self::checkbox( 'payment_delivery_information_confirmed', 'payment_delivery', $s['payment_delivery_information_confirmed'], $language, $errors, 'payment_delivery_help', true );
self::checkbox( 'completed_means_dispatched', 'completed_dispatched', $d['completed_means_dispatched'], $language, $errors, 'completed_help' );
$email_help = ! empty( $facts['pro_active'] ) ? 'customer_email_help_pro' : 'customer_email_help_free';
self::email_select( 'customer_email_id', 'customer_email', (string) $d['customer_email_id'], (array) ( $facts['customer_emails'] ?? array() ), $language, $errors, $email_help );
echo '';
}
private static function step_documents( array $settings, array $facts, string $language, array $errors ): void {
$d = (array) $settings['documents'];
$l = (array) $settings['languages'];
self::section_heading( $language, 'documents_title', 'documents_intro' );
echo '' . esc_html( self::t( $language, 'pdf_contents_title' ) ) . '' . esc_html( self::t( $language, 'pdf_contents' ) ) . '
' . esc_html( self::t( $language, 'basic_pdf_notice' ) ) . '
';
self::checkbox( 'basic_pdf_enabled', 'basic_pdf_enabled', $d['basic_pdf_enabled'], $language, $errors );
echo '';
self::email_select( 'basic_pdf_email_id', 'basic_pdf_email', (string) $d['basic_pdf_email_id'], (array) ( $facts['customer_emails'] ?? array() ), $language, $errors, 'basic_pdf_email_help' );
echo '
' . esc_html( self::t( $language, 'delivery_preview' ) ) . '' . esc_html( self::t( $language, 'delivery_preview_body' ) ) . '
' . esc_html( self::t( $language, 'pdf_off' ) ) . '
';
echo '' . esc_html( self::t( $language, 'no_side_effects' ) ) . '
';
$enabled_languages = array_values( array_intersect( LanguageCatalog::supported_codes(), array_map( 'strval', (array) ( $l['enabled_customer_languages'] ?? array() ) ) ) );
$preview_language = in_array( (string) ( $l['default_document_language'] ?? '' ), $enabled_languages, true ) ? (string) $l['default_document_language'] : ( $enabled_languages[0] ?? LanguageCatalog::BOSNIAN );
echo '' . esc_html( self::t( $language, 'pdf_preview_title' ) ) . '
' . esc_html( self::t( $language, 'pdf_preview_help' ) ) . '
' . esc_html( self::t( $language, 'preview_language_help' ) ) . '
' . esc_html( self::t( $language, 'view_pdf' ) ) . ' ' . esc_html( self::t( $language, 'download_sample' ) ) . '
';
echo '' . esc_html( self::t( $language, 'pro_boundary' ) ) . '' . esc_html( self::t( $language, ! empty( $facts['pro_active'] ) ? 'pro_active_pdf_note' : 'pro_available_pdf_note' ) ) . '
';
}
private static function render_audit_step( string $language ): void {
$report = AuditRuntime::last_report();
self::section_heading( $language, 'audit_title', 'audit_intro' );
echo '';
if ( $report instanceof AuditReport ) {
self::render_audit_report( $report, $language );
} else {
echo '' . esc_html( self::t( $language, 'audit_not_run' ) ) . '
'; }
$can_finish = $report instanceof AuditReport && ! $report->has_blockers();
if ( $can_finish ) {
echo '' . esc_html( self::t( $language, 'setup_ready_title' ) ) . '' . esc_html( self::t( $language, 'setup_ready_body' ) ) . '
';
}
echo '' . esc_html( self::t( $language, 'free_boundary' ) ) . '
';
}
public static function render_audit_report( AuditReport $report, string $language ): void {
$counts = $report->counts();
echo '' . esc_html( self::t( $language, 'audit_counts', array( (string) $counts['pass'], (string) $counts['warning'], (string) $counts['blocker'] ) ) ) . '
';
$key = $report->has_blockers() ? 'audit_blocker' : ( $counts['warning'] > 0 ? 'audit_warning' : 'audit_pass' );
echo '' . esc_html( self::t( $language, $key ) ) . '
';
$groups = array(
'blocker' => array( 'audit_fixes', false ),
'warning' => array( 'audit_warnings', false ),
'pass' => array( 'audit_passed', true ),
'not_applicable' => array( 'audit_not_applicable', true ),
);
foreach ( $groups as $status => $group ) {
$results = array_filter( $report->results(), static fn( $result ): bool => $status === $result->get_status() );
if ( empty( $results ) ) {
continue;
}
echo '' . esc_html( self::t( $language, $group[0] ) ) . ' ' . esc_html( (string) count( $results ) ) . '
';
foreach ( $results as $result ) {
self::audit_finding( $result, $language );
}
echo '
';
}
}
private static function audit_finding( $result, string $language ): void {
$mapping = AuditPresentationMap::for_code( $result->get_code() );
$title = $mapping ? self::t( $language, $mapping['title_key'] ) : self::t( $language, 'unmapped_finding' );
$status = $result->get_status();
$reason = $mapping && 'pass' === $status ? WizardTextCatalog::audit_pass( $language, $result->get_code() ) : ( $mapping && in_array( $status, array( 'blocker', 'warning' ), true ) ? self::t( $language, $mapping['issue_key'] ) : self::t( $language, 'finding_' . $status ) );
echo '' . esc_html( $title ) . '' . esc_html( $reason ) . '
';
if ( $mapping && in_array( $status, array( 'blocker', 'warning' ), true ) ) {
echo '
' . esc_html( self::t( $language, 'what_to_do' ) ) . ' ' . esc_html( self::t( $language, $mapping['fix_key'] ) ) . '
';
}
echo '
';
if ( $mapping ) {
$target = self::url( $mapping['step'] );
if ( '' !== $mapping['field'] ) {
$target .= '#lmcc-field-' . rawurlencode( $mapping['field'] );
}
echo '' . esc_html( self::t( $language, in_array( $status, array( 'blocker', 'warning' ), true ) ? 'go_fix' : 'view_setting' ) ) . '';
} else {
echo '' . esc_html( self::t( $language, 'mapping_unavailable' ) ) . '';
}
$source_rule = '' !== $result->get_source_rule() ? $result->get_source_rule() : '—';
echo '' . esc_html( self::t( $language, 'diagnostic_details' ) ) . '
- ' . esc_html( self::t( $language, 'check_id' ) ) . '
' . esc_html( $result->get_code() ) . '- ' . esc_html( self::t( $language, 'source_rule' ) ) . '
' . esc_html( $source_rule ) . '- ' . esc_html( self::t( $language, 'engine_message' ) ) . '
- ' . esc_html( $reason ) . '
';
if ( $mapping && in_array( $status, array( 'blocker', 'warning' ), true ) ) {
echo '- ' . esc_html( self::t( $language, 'engine_remediation' ) ) . '
- ' . esc_html( self::t( $language, $mapping['fix_key'] ) ) . '
';
}
echo '
';
}
public static function current_language(): string {
return self::language( AuditRuntime::setup()->get_settings() );
}
public static function text( string $language, string $key, array $values = array() ): string {
return self::t( $language, $key, $values );
}
private static function section_heading( string $language, string $title_key, string $intro_key ): void {
echo '';
}
private static function field( string $name, string $label_key, $value, string $language, array $errors, bool $required, string $type = 'text', string $help_key = '', string $placeholder_key = '', string $badge_key = '' ): void {
$error = self::field_error( $name, $errors );
$id = 'lmcc-field-' . $name;
$description_id = $id . '-description';
$badge = '' !== $badge_key ? $badge_key : ( $required ? 'required' : 'optional' );
echo '';
echo '
';
if ( '' !== $help_key ) {
echo '
' . esc_html( self::t( $language, $help_key ) ) . '
';
} self::inline_error( $name, $language, $errors );
echo '
';
}
private static function checkbox( string $name, string $label_key, $value, string $language, array $errors, string $help_key = '', bool $completion_required = false ): void {
$id = 'lmcc-field-' . $name;
echo '';
if ( '' !== $help_key ) {
echo '
' . esc_html( self::t( $language, $help_key ) ) . '
';
} self::inline_error( $name, $language, $errors );
echo '
';
}
private static function select_field( string $name, string $label_key, string $current, array $options, string $language, array $errors, bool $required, string $help_key = '', string $extra_attribute = '' ): void {
$id = 'lmcc-field-' . $name;
echo '';
if ( '' !== $help_key ) {
echo '
' . esc_html( self::t( $language, $help_key ) ) . '
';
} self::inline_error( $name, $language, $errors );
echo '
';
}
private static function language_select( string $name, string $label_key, string $current, string $language, array $errors, bool $auto_submit, string $help_key = '' ): void {
$options = array();
foreach ( LanguageCatalog::supported_codes() as $code ) {
$options[ $code ] = LanguageCatalog::label( $code, $language ); }
self::select_field( $name, $label_key, $current, $options, $language, $errors, true, $help_key, $auto_submit ? 'data-lmcc-language-select' : '' );
}
private static function checkout_label( string $mode, string $language ): string {
if ( 'classic' === $mode ) {
return self::t( $language, 'checkout_classic' );
}
if ( 'blocks' === $mode ) {
return self::t( $language, 'checkout_blocks' );
}
return '' !== $mode ? $mode : '—';
}
private static function currency_label( string $code, string $language ): string {
$code = strtoupper( trim( $code ) );
if ( 'BAM' === $code ) {
return self::t( $language, 'currency_bam' );
}
if ( '' === $code ) {
return '—';
}
if ( function_exists( 'get_woocommerce_currencies' ) ) {
$currencies = get_woocommerce_currencies();
if ( isset( $currencies[ $code ] ) && '' !== trim( (string) $currencies[ $code ] ) ) {
return (string) $currencies[ $code ] . ' (' . $code . ')';
}
}
return $code;
}
private static function locale_label( string $locale, string $language ): string {
$prefix = strtolower( substr( $locale, 0, 2 ) );
if ( in_array( $prefix, array( 'bs', 'hr', 'sr', 'en' ), true ) ) {
return self::t( $language, 'locale_' . $prefix );
}
return '' !== $locale ? $locale : '—';
}
public static function brand_text( string $text ): string {
$parts = explode( 'Leanmerce', $text, 2 );
if ( 2 !== count( $parts ) ) {
return esc_html( $text );
}
return esc_html( $parts[0] ) . 'Leanmerce' . esc_html( $parts[1] );
}
private static function email_select( string $name, string $label_key, string $current, array $emails, string $language, array $errors, string $help_key = '' ): void {
$options = array( '' => self::t( $language, 'select_eligible_email' ) );
$current_label = '';
$current_valid = false;
foreach ( $emails as $email ) {
if ( ! is_array( $email ) || empty( $email['id'] ) ) {
continue;
}
$id = (string) $email['id'];
$title = self::email_label( $id, (string) ( $email['title'] ?? $id ), $language );
$eligible = ! empty( $email['eligible'] ) || ( ! array_key_exists( 'eligible', $email ) && ! empty( $email['enabled'] ) && in_array( $id, array( 'customer_processing_order', 'customer_completed_order', 'customer_on_hold_order' ), true ) );
if ( $id === $current ) {
$current_label = $title;
$current_valid = $eligible;
}
if ( $eligible ) {
$options[ $id ] = $title . ' — ' . self::t( $language, 'enabled' );
}
}
if ( '' !== $current && ! $current_valid ) {
$options = array( $current => ( '' !== $current_label ? $current_label : $current ) . ' — ' . self::t( $language, 'email_needs_replacement' ) ) + $options;
}
self::select_field( $name, $label_key, $current, $options, $language, $errors, true, $help_key );
}
private static function email_label( string $id, string $fallback, string $language ): string {
$key = 'email_' . $id;
$text = self::t( $language, $key );
return '[' . $key . ']' === $text ? $fallback : $text;
}
private static function render_edition_note( array $facts, string $language, bool $compact = false ): void {
$key = ! empty( $facts['pro_active'] ) ? 'edition_pro_active' : 'edition_free_only';
$class = $compact ? ' lmcc-edition-note--compact' : '';
echo '' . esc_html( self::t( $language, ! empty( $facts['pro_active'] ) ? 'edition_pro_title' : 'edition_free_title' ) ) . '' . esc_html( self::t( $language, $key ) ) . '
';
}
/** @return array */
private static function maybe_bind_terms_page( array $input ): array {
$page_id = isset( $input['terms_page_id'] ) ? absint( $input['terms_page_id'] ) : 0;
if ( $page_id <= 0 ) {
return array();
}
// phpcs:ignore WordPress.WP.Capabilities.Unknown -- WooCommerce registers this capability.
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return array(
array(
'field' => 'terms_page_id',
'code' => 'terms_page_permission',
),
);
}
if ( ! function_exists( 'get_post_type' ) || 'page' !== get_post_type( $page_id ) || ! function_exists( 'get_post_status' ) || 'publish' !== get_post_status( $page_id ) ) {
return array(
array(
'field' => 'terms_page_id',
'code' => 'terms_page_selection',
),
);
}
if ( function_exists( 'update_option' ) ) {
update_option( 'woocommerce_terms_page_id', $page_id, false );
AuditRuntime::repository()->clear_audit_cache();
}
return array();
}
private static function render_navigation( int $current, array $completion, string $language ): void {
echo '';
}
private static function render_notices( string $language ): void {
$map = array(
'lmcc_saved' => 'step_saved',
'lmcc_draft_saved' => 'draft_saved',
'lmcc_finish_blocked' => 'finish_blocked',
'lmcc_completed' => 'setup_completed',
);
foreach ( $map as $query => $text ) {
if ( ! empty( $_GET[ $query ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only redirect notice.
$type = 'lmcc_finish_blocked' === $query ? 'error' : 'success';
echo '' . esc_html( self::t( $language, $text ) ) . '
'; }
}
if ( ! empty( $_GET['lmcc_audited'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only redirect notice.
$problems = isset( $_GET['lmcc_problems'] ) ? absint( wp_unslash( $_GET['lmcc_problems'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only count.
echo '' . esc_html( self::t( $language, 'audit_executed', array( (string) $problems ) ) ) . '
';
}
}
private static function render_error_summary( array $errors, string $language ): void {
if ( empty( $errors ) ) {
return; }
echo '' . esc_html( self::t( $language, 'error_summary_title' ) ) . '
';
}
private static function inline_error( string $field, string $language, array $errors ): void {
$error = self::field_error( $field, $errors );
if ( $error ) {
echo '' . esc_html( self::error_text( $language, $error['code'] ) ) . '
'; }
}
private static function field_error( string $field, array $errors ): ?array {
foreach ( $errors as $error ) {
if ( $field === $error['field'] ) {
return $error;
}
} return null;
}
private static function error_text( string $language, string $code ): string {
return self::t( $language, 'error_' . $code ); }
private static function t( string $language, string $key, array $values = array() ): string {
return WizardTextCatalog::text( $language, $key, $values ); }
private static function language( array $settings ): string {
$language = (string) ( $settings['languages']['admin_language'] ?? LanguageCatalog::BOSNIAN );
return in_array( $language, LanguageCatalog::supported_codes(), true ) ? $language : LanguageCatalog::BOSNIAN; }
private static function request_errors(): array {
$raw = isset( $_GET['lmcc_errors'] ) ? sanitize_text_field( wp_unslash( $_GET['lmcc_errors'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only redirect state.
$errors = array();
foreach ( array_filter( explode( ',', $raw ) ) as $encoded ) {
$parts = explode( '.', $encoded );
if ( 3 === count( $parts ) ) {
$errors[] = array(
'step' => absint( $parts[0] ),
'field' => sanitize_key( $parts[1] ),
'code' => sanitize_key( $parts[2] ),
);
}
} return $errors;
}
private static function encode_errors( array $errors, int $default_step = 0 ): string {
$encoded = array();
foreach ( $errors as $error ) {
$encoded[] = (int) ( $error['step'] ?? $default_step ) . '.' . sanitize_key( $error['field'] ) . '.' . sanitize_key( $error['code'] );
} return implode( ',', $encoded );
}
private static function redirect( int $step, array $args = array() ): void {
$args['page'] = self::PAGE_SLUG;
$args['step'] = $step;
wp_safe_redirect( add_query_arg( $args, admin_url( 'admin.php' ) ) );
exit; }
private static function url( int $step ): string {
return add_query_arg(
array(
'page' => self::PAGE_SLUG,
'step' => max( 1, min( SetupService::TOTAL_STEPS, $step ) ),
),
admin_url( 'admin.php' )
); }
private static function requested_step( int $fallback ): int {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only navigation.
$step = isset( $_GET['step'] ) ? absint( wp_unslash( $_GET['step'] ) ) : $fallback;
return max( 1, min( SetupService::TOTAL_STEPS, $step ) ); }
private static function require_capability(): void {
if ( ! current_user_can( Capabilities::MANAGE_SETTINGS ) ) {
wp_die( esc_html( self::t( self::current_language(), 'error_permission' ) ), '', array( 'response' => 403 ) ); } }
private static function count_enabled( array $items ): int {
$count = 0;
foreach ( $items as $item ) {
if ( is_array( $item ) && ! empty( $item['enabled'] ) ) {
++$count;
}
} return $count; }
private static function method_list( array $items, string $language ): void {
if ( empty( $items ) ) {
echo '' . esc_html( self::t( $language, 'none_detected' ) ) . '
';
return;
}
echo '';
foreach ( $items as $item ) {
if ( ! is_array( $item ) ) {
continue;
}
echo '- ' . esc_html( (string) ( $item['title'] ?? $item['id'] ?? '—' ) ) . '' . esc_html( self::t( $language, empty( $item['enabled'] ) ? 'disabled' : 'enabled' ) ) . '
';
}
echo '
';
}
private static function legacy_email( string $value ): string {
$value = trim( $value );
return false !== filter_var( $value, FILTER_VALIDATE_EMAIL ) ? $value : '';
}
private function __construct() {}
}