�PNG  IHDR22?�� pHYs  �� OiCCPPhotoshop ICC profilexڝSgTS�=���BK���KoR RB���&*! J�!��Q�EEȠ�����Q, � ��!���������{�kּ������>���� �H3Q5� �B�������.@� $p�d!s�#�~<<+"��x� �M��0���B�\���t�8K�@z�B�@F���&S�`�cb�P-`'������{[�!�� e�Dh;��V�EX0fK�9�-0IWfH���� � 0Q��){`�##x��F�W<�+��*x��<�$9E�[-qWW.(�I+6aa�@.�y�2�4���������x����6��_-��"bb���ϫp@�t~��,/��;�m��%�h^ �u��f�@����W�p�~<�5�j>{�-�]c�K'Xt����o��(�h���w��?�G�%�fI�q^D$.Tʳ?�D��*�A��,���� �`6�B$��BB d�r`)��B(�Ͱ*`/�@4�Qh��p.�U�=p�a��(�� A�a!ڈb�X#����!�H�$ ɈQ"K�5H1R�T UH�=r9�\F��;�2����G1���Q=� �C��7�F� �dt1�����r�=�6��Ыhڏ>C�0��3�l0.��B�8, �c˱"� ���V����cϱw�E� 6wB aAHXLXN�H� $4� 7 �Q�'"��K�&���b21�XH,#��/{�C�7$�C2'��I��T��F�nR#�,��4H#���dk�9�, +ȅ����3��!�[ �b@q��S�(R�jJ��4�e�2AU��Rݨ�T5�ZB���R�Q��4u�9̓IK�����hh�i��t�ݕN��W���G���w ��Ljg(�gw��L�Ӌ�T071���oUX*�*|�� �J�&�*/T����ު U�U�T��^S}�FU3S� Ԗ�U��P�SSg�;���g�oT?�~Y��Y�L�OC�Q��_�� c�x,!k ��u�5�&���|v*�����=���9C3J3W�R�f?�q��tN �(���~���)�)�4L�1e\k����X�H�Q�G�6������E�Y��A�J'\'Gg����S�Sݧ �M=:��.�k���Dw�n��^��Lo��y���}/�T�m���G X� $� �<�5qo</���QC]�@C�a�a�ᄑ��<��F�F�i�\�$�m�mƣ&&!&KM�M�RM��)�;L;L���͢�֙5�=1�2��כ߷`ZxZ,����eI��Z�Yn�Z9Y�XUZ]�F���%ֻ�����N�N���gð�ɶ�����ۮ�m�}agbg�Ů��}�}��= ���Z~s�r:V:ޚΜ�?}����/gX���3��)�i�S��Ggg�s�󈋉K��.�>.���Ƚ�Jt�q]�z���������ۯ�6�i�ܟ�4�)�Y3s���C�Q��? ��0k߬~OCO�g��#/c/�W�װ��w��a�>�>r��>�<7�2�Y_�7��ȷ�O�o�_��C#�d�z����%g��A�[��z|!��?:�e����A���AA�������!h�쐭!��Α�i�P~���a�a��~ '���W�?�p�X�1�5w��Cs�D�D�Dޛg1O9�-J5*>�.j<�7�4�?�.fY��X�XIlK9.*�6nl������� �{�/�]py�����.,:�@L�N8��A*��%�w%� y��g"/�6ш�C\*N�H*Mz�쑼5y$�3�,幄'���L Lݛ:��v m2=:�1����qB�!M��g�g�fvˬe����n��/��k���Y- �B��TZ(�*�geWf�͉�9���+��̳�ې7�����ᒶ��KW-X潬j9�������(�x��oʿ�ܔ���Ĺd�f�f���-�[����n �ڴ �V����E�/��(ۻ��C���<��e����;?T�T�T�T6��ݵa��n��{��4���[���>ɾ�UUM�f�e�I���?�������m]�Nmq����#�׹���=TR��+�G�����w- 6 U����#pDy��� �� :�v�{���vg/jB��F�S��[b[�O�>����z�G��499�?r����C�d�&����ˮ/~�����јѡ�򗓿m|������������x31^�V���w�w��O�| (�h���SЧ��������c3-� cHRMz%������u0�`:�o�_�F5IDATx��ytUս�?�;���fN$$��@B�!�k��� -*�gE���j�O�kQ�ʠ`U�B_ �AÐ0%�Ȕ�@r3ޛ;߳��$�@��v����^�s����������$��ߢ !�W��5�̱'-٘������4�>�Rƫ$�G��0U�H}�_ _� #��k�MJ/=�9Du *ڲ�k�PQ;0��j|�*�$�^컂脛y���>�z×� B��� ��(�:$�ʔ_�6��C!B����MVx��a��ζyY����j��ƋY2�9�F�{r��r�딟F��Q��hY6��� x��[l��RC��������nt@��;P��3��� F�w��7��:�P���ɋ'���mj���Bƪ�$�Q�L��y��߷g��\���z����v5�p�v$�v櫻�`6~K �Y�X����,�:��"�o�e0II"(��,������l_�C���/4�+f�E�!q��:����u����c��樼.UE�@� �]K�W���$-�h]�JG���Dz)�`��.�A/ ���mᏣc�3jK� �!�>���$�Q�!�_�? \�C2(E �M$Z I{�U���s�ǣ���=��@Բe ޻��W�����@ �w����}�9v,)��.}*|"�s��di���,���G�]W�AC�������|<����[��ߕ������K�*�G nߴ!��‹��J�!��6(L�a)��Am��������;adf��:�xm��nh�;֦I��(���o�C~ډa?�=��s����h��E������xp����)���_���t��W�����´;8���`dz=(��@@�+,�;�`�fhl��XȌ�3,uI�~z(J����� �ZX�A����H'�À�㜦�82|��a�n�z2��I���� ���EY�h�ε<�0�q�{��C��v�˅��?"@��χ�x�WS+��N�~�KQ�J�8ل�� _.W��� !TU{�����,��"�� �;�������HI S� ��))�o�1�H�D� ���� (� ;����"Ҕ��,���� �F=���O��&�Ph>�`���y��߲ &S��P�<��'��1s�1cĂ�N����2)����@�u��tv��<�+�-&�����h��[!FSG���' � z z0��<����8d&�����E0�,��<��"!P�b4��� �{S�����X����.�囤���T��hEF��X�q0"-<����h���]�Py*����F⩍��@v�˂�Y08�� .q��a��s����(!<̫1�3�L�H��7sYW�`��qtu�\7��?�@�Y�� %Ka�x�GZ�*W�P��y�����N0r9��Z�c�%���q,��k�����!!,��>���IB��� �x1�Xu�Y���v-���ֺ��N������JP��a�2`�e5��w��u;�6�i���̃��(K���ťa��(l51��JL��O'%���]���ٖ뿉!��{*�p+f ���i8��D�ȑ���ܩ�M��V��ӟz��x�7Z�1i}�^͜���6e����x��)u�d�ˏ�V�eG�\�X1�����=n�U'�~Y����L�\,�(d!x ,�:�TW8� M`r���@��r+v�Q0��>^;˴�VbF��('����� �*O��i��j�Ӆ����^�S3&� ���{������.ی�� N;��NU%d0�Ce\r"�C�b��&t7N�7��� �ȪD�[%l�۪�$��'m?�A9tI�9>��NVL ��� 6v~M�����ъ�B���0����9$&=ώm��W�0���L���&��E���f�f��'+�9��hv��7,���M��6�D�&�^� �����8 D֮�����o��k^z��O��hP�8q�5d*��YVq3�{��������#LX4�?��jP=3�~�؅c�ݰ�̱�ұ��8̲��2�G�����j��έ�9��w7���U�X�w�85C��?!I&���o&����L���I#�^�eV�,�^t5�k� �xs˛\��U�8��."���{���ǵ�l4��ݼ�;��r"���G�/~���gJV�N糦��ZZ^k+NN�D��I$�=OE�z����|*�*{��%k���G��>�`9��b;�s���8,�qs��c��.b��q�%�>r��n�R�Ƨ�%�,�A��le#�8���}; 21�0�b�&�QX�f���q�00����$>�h�N�'�a3��A���/�r ��L5�8�GԲ'�����w;��c#�q1���h$*��V^�k��QĽ�b:i������� ����H F#�_���,��]g����Ը����`RUU���� ��"�qD���>-��ϤI�~��3�̴�����NZ[[555�eeek7�m����YF#[��Đ��R��i��L�H�r ��@��J-�Pŝ��_|�-��6y��ks�V�U~��6���w.����(��0A� 4��f��� /���C�xŊ�ٳ����z=6�����rg���mKo��o�/����a�g���?'9%9��P��斓��~���L{�� �H��{AW��B��$����v�1b�&Mb�ر��ر#�0`�`xMBp! )Z�Nmo�mZ�g�}�eذaWTVV ���'99��C5��&�&+5�bT>|8��PUUETT����&���t��~TE%��'������b�tEGG;RSS�S�N�v��ѯ��t����u1@�ޚ"f��͈���r'L�Ph��m��ƌ�74o��`�x�q�P���NRSS�X,�����l&&&��MFFA!-��`��ҷ�n��Yuu�����x<I�LB%����KԒ50�!�3�bz�����ʸKL���;---�l6[��`��������Ȏ;�����egg4��!D�T��jWujyZ��������K����%����p�^���X,6��sV=�ܖ����6�3�X ���4ҿ��A2�&����_k�;d�� �VfOIEND�B`�
Warning: session_start(): Session cannot be started after headers have already been sent in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 124

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 130

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 131

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 132

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 133

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 134

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 135

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 547

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 548

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 549

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 550

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 551
account = $account; } /** * Returns the disabled response used while the feature flag is off. * * @return array */ public function get_disabled_overview_payload(): array { return [ 'overview' => [ 'enabled' => false, 'hidden' => true, 'score' => 0, 'total' => 0, 'state' => self::STATUS_INCOMPLETE, 'isDismissed' => true, 'completeSignalIds' => [], 'incompleteSignalIds' => [], 'signals' => [], 'dismissal' => [ 'isDismissed' => true, 'isStoredDismissal' => false, 'reappearReason' => 'feature_disabled', ], ], ]; } /** * Builds the enabled overview payload. * * @return array */ public function get_overview_payload(): array { $signals = $this->get_signals(); $total = count( $signals ); $complete_signal_ids = []; $incomplete_signal_ids = []; foreach ( $signals as $signal ) { if ( self::STATUS_COMPLETE === $signal['status'] ) { $complete_signal_ids[] = $signal['id']; } else { $incomplete_signal_ids[] = $signal['id']; } } $score = count( $complete_signal_ids ); $dismissal = $this->get_dismissal_state( $score, $total, $incomplete_signal_ids ); return [ 'overview' => [ 'enabled' => true, 'hidden' => false, 'score' => $score, 'total' => $total, 'state' => $score === $total ? self::STATUS_COMPLETE : self::STATUS_INCOMPLETE, 'isDismissed' => $dismissal['isDismissed'], 'completeSignalIds' => $complete_signal_ids, 'incompleteSignalIds' => $incomplete_signal_ids, 'signals' => $signals, 'dismissal' => $dismissal, ], ]; } /** * Stores dismissal metadata for the current overview state. * * @return array Updated overview payload. */ public function dismiss_overview_card(): array { $payload = $this->get_overview_payload(); $overview = $payload['overview']; update_option( self::DISMISSAL_OPTION, [ 'dismissed' => true, 'dismissed_at' => gmdate( 'c' ), 'score_at_dismissal' => $overview['score'], 'total_at_dismissal' => $overview['total'], 'incomplete_signal_ids' => $overview['incompleteSignalIds'], ], false ); return $this->get_overview_payload(); } /** * Confirms that the current statement descriptor clearly identifies the store. * * @return array Updated overview payload. */ public function confirm_statement_descriptor(): array { $descriptor = $this->get_statement_descriptor( $this->get_cached_account_data() ); update_option( self::STATEMENT_DESCRIPTOR_CONFIRMATION_OPTION, [ 'confirmed' => true, 'confirmed_at' => gmdate( 'c' ), 'descriptor' => $descriptor, 'normalized_descriptor' => $this->normalize_descriptor_value( $descriptor ), ], false ); return $this->get_overview_payload(); } /** * Builds all v1 overview signals. * * @return array[] */ private function get_signals(): array { $account_data = $this->get_cached_account_data(); return [ $this->get_statement_descriptor_signal( $account_data ), $this->get_refund_policy_signal(), $this->get_support_contact_signal( $account_data ), $this->get_terms_and_conditions_signal(), ]; } /** * Returns the refund policy signal. * * @return array */ private function get_refund_policy_signal(): array { $page_id = (int) get_option( 'woocommerce_refund_returns_page_id', 0 ); $status = $this->is_complete_page( $page_id ) ? self::STATUS_COMPLETE : self::STATUS_INCOMPLETE; return [ 'id' => self::SIGNAL_REFUND_POLICY, 'status' => $status, 'label' => __( 'Refund policy page published', 'woocommerce-payments' ), 'description' => __( 'Publish a refund policy so customers can resolve issues with you before filing a dispute.', 'woocommerce-payments' ), 'actionLabel' => __( 'Fix it', 'woocommerce-payments' ), 'actionUrl' => $this->get_page_action_url( $page_id ), ]; } /** * Returns the terms and conditions signal. * * @return array */ private function get_terms_and_conditions_signal(): array { $page_id = function_exists( 'wc_terms_and_conditions_page_id' ) ? (int) wc_terms_and_conditions_page_id() : (int) get_option( 'woocommerce_terms_page_id', 0 ); $status = $this->is_complete_page( $page_id ) ? self::STATUS_COMPLETE : self::STATUS_INCOMPLETE; return [ 'id' => self::SIGNAL_TERMS_AND_CONDITIONS, 'status' => $status, 'label' => __( 'Terms & conditions linked at checkout', 'woocommerce-payments' ), 'description' => __( 'Add a T&C link at checkout so customers acknowledge your policies before completing a purchase.', 'woocommerce-payments' ), 'actionLabel' => __( 'Fix it', 'woocommerce-payments' ), 'actionUrl' => $this->get_woocommerce_advanced_settings_url(), ]; } /** * Returns the statement descriptor signal. * * @param array $account_data Cached account data. * @return array */ private function get_statement_descriptor_signal( array $account_data ): array { $descriptor = $this->get_statement_descriptor( $account_data ); $trimmed = trim( $descriptor ); $is_empty = '' === $trimmed; $needs_review = ! $is_empty && ! $this->looks_like_recognizable_descriptor( $descriptor, $account_data ); $is_confirmed = $needs_review && $this->is_statement_descriptor_confirmed( $descriptor ); $status = ! $is_empty && ( ! $needs_review || $is_confirmed ) ? self::STATUS_COMPLETE : self::STATUS_INCOMPLETE; $action_label = __( 'Fix it', 'woocommerce-payments' ); $settings_url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=woocommerce_payments' ); $review_prompt = null; if ( self::STATUS_INCOMPLETE === $status && $needs_review ) { $review_prompt = [ 'text' => __( "Your statement descriptor will show up on your customers' bank statements. Does it clearly identify your store?", 'woocommerce-payments' ), 'currentDescriptor' => $trimmed, 'confirmLabel' => __( 'Looks good', 'woocommerce-payments' ), 'updateLabel' => __( 'Update', 'woocommerce-payments' ), ]; } $signal = [ 'id' => self::SIGNAL_STATEMENT_DESCRIPTOR, 'status' => $status, 'label' => __( 'Recognizable statement descriptor', 'woocommerce-payments' ), 'description' => __( 'Make sure your business name appears clearly on customer bank statements to prevent confusion.', 'woocommerce-payments' ), 'actionLabel' => $action_label, 'actionUrl' => $settings_url, 'reason' => $this->get_statement_descriptor_reason( $descriptor, $needs_review, $is_confirmed ), ]; if ( null !== $review_prompt ) { $signal['reviewPrompt'] = $review_prompt; } return $signal; } /** * Returns the support contact signal. * * @param array $account_data Cached account data. * @return array */ private function get_support_contact_signal( array $account_data ): array { $business_profile = isset( $account_data['business_profile'] ) && is_array( $account_data['business_profile'] ) ? $account_data['business_profile'] : []; $support_email = isset( $business_profile['support_email'] ) ? trim( (string) $business_profile['support_email'] ) : ''; $support_phone = isset( $business_profile['support_phone'] ) ? trim( (string) $business_profile['support_phone'] ) : ''; $status = '' !== $support_email || '' !== $support_phone ? self::STATUS_COMPLETE : self::STATUS_INCOMPLETE; return [ 'id' => self::SIGNAL_SUPPORT_CONTACT, 'status' => $status, 'label' => __( 'Customer support contact linked in order emails', 'woocommerce-payments' ), 'description' => __( 'Give customers a direct way to reach you from their order emails to handle issues quickly.', 'woocommerce-payments' ), 'actionLabel' => __( 'Fix it', 'woocommerce-payments' ), 'actionUrl' => admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=woocommerce_payments' ), ]; } /** * Returns cached account data safely. * * @return array */ private function get_cached_account_data(): array { $account_data = $this->account->get_cached_account_data(); return is_array( $account_data ) ? $account_data : []; } /** * Determines whether a configured page exists, is published, and has meaningful content. * * @param int $page_id Page ID. * @return bool */ private function is_complete_page( int $page_id ): bool { if ( ! $this->is_published_page( $page_id ) ) { return false; } $page = get_post( $page_id ); $content = strip_shortcodes( (string) $page->post_content ); $content = wp_strip_all_tags( $content ); $content = preg_replace( '/\s+/', '', $content ); return '' !== $content; } /** * Determines whether a configured page exists and is published. * * @param int $page_id Page ID. * @return bool */ private function is_published_page( int $page_id ): bool { if ( $page_id <= 0 ) { return false; } $page = get_post( $page_id ); return $page && 'publish' === $page->post_status; } /** * Returns the edit URL for an assigned page or the WooCommerce page setup settings URL. * * @param int $page_id Page ID. * @return string */ private function get_page_action_url( int $page_id ): string { if ( $page_id > 0 && get_post( $page_id ) ) { $edit_post_link = get_edit_post_link( $page_id, '' ); return $edit_post_link ? $edit_post_link : admin_url( 'post.php?post=' . $page_id . '&action=edit' ); } return $this->get_woocommerce_advanced_settings_url(); } /** * Returns the WooCommerce advanced settings URL. * * @return string */ private function get_woocommerce_advanced_settings_url(): string { return admin_url( 'admin.php?page=wc-settings&tab=advanced' ); } /** * Returns the current dismissal state. * * @param int $score Current score. * @param int $total Current total. * @param array $incomplete_signal_ids Current incomplete signal IDs. * @return array */ private function get_dismissal_state( int $score, int $total, array $incomplete_signal_ids ): array { $stored = get_option( self::DISMISSAL_OPTION, [] ); if ( ! is_array( $stored ) || empty( $stored['dismissed'] ) ) { return [ 'isDismissed' => false, 'isStoredDismissal' => false, 'reappearReason' => null, ]; } $score_at_dismissal = isset( $stored['score_at_dismissal'] ) ? (int) $stored['score_at_dismissal'] : 0; $total_at_dismissal = isset( $stored['total_at_dismissal'] ) ? (int) $stored['total_at_dismissal'] : 0; $stored_incomplete_ids = isset( $stored['incomplete_signal_ids'] ) && is_array( $stored['incomplete_signal_ids'] ) ? array_values( $stored['incomplete_signal_ids'] ) : []; $current_incomplete_ids = array_values( $incomplete_signal_ids ); $reappear_reason = null; sort( $stored_incomplete_ids ); sort( $current_incomplete_ids ); if ( $total !== $total_at_dismissal ) { $reappear_reason = 'total_changed'; } elseif ( $score < $score_at_dismissal ) { $reappear_reason = 'score_decreased'; } elseif ( $score === $score_at_dismissal && $current_incomplete_ids !== $stored_incomplete_ids ) { $reappear_reason = 'incomplete_signals_changed'; } return [ 'isDismissed' => null === $reappear_reason, 'isStoredDismissal' => true, 'reappearReason' => $reappear_reason, 'dismissedAt' => isset( $stored['dismissed_at'] ) ? (string) $stored['dismissed_at'] : null, 'scoreAtDismissal' => $score_at_dismissal, 'totalAtDismissal' => $total_at_dismissal, 'incompleteSignalIds' => $stored_incomplete_ids, ]; } /** * Returns the current account statement descriptor. * * @param array $account_data Cached account data. * @return string */ private function get_statement_descriptor( array $account_data ): string { if ( isset( $account_data['statement_descriptor'] ) ) { return (string) $account_data['statement_descriptor']; } return ''; } /** * Returns the reason code for the statement descriptor signal. * * @param string $descriptor Statement descriptor. * @param bool $needs_review Whether the descriptor needs review. * @param bool $is_confirmed Whether the merchant confirmed the descriptor. * @return string */ private function get_statement_descriptor_reason( string $descriptor, bool $needs_review, bool $is_confirmed ): string { if ( '' === trim( $descriptor ) ) { return 'empty'; } if ( $is_confirmed ) { return 'confirmed'; } return $needs_review ? 'needs_review' : 'looks_recognizable'; } /** * Determines whether a descriptor looks recognizable enough to complete automatically. * * @param string $descriptor Statement descriptor. * @param array $account_data Cached account data. * @return bool */ private function looks_like_recognizable_descriptor( string $descriptor, array $account_data ): bool { $normalized_descriptor = $this->normalize_descriptor_value( $descriptor ); if ( '' === $normalized_descriptor || $this->is_generic_descriptor_value( $normalized_descriptor ) ) { return false; } foreach ( $this->get_store_descriptor_candidates( $account_data ) as $candidate ) { $normalized_candidate = $this->normalize_descriptor_value( (string) $candidate ); if ( '' === $normalized_candidate || $this->is_generic_descriptor_value( $normalized_candidate ) ) { continue; } if ( $normalized_descriptor === $normalized_candidate ) { return true; } } return strlen( $normalized_descriptor ) >= 5; } /** * Determines whether the merchant confirmed the current descriptor. * * @param string $descriptor Statement descriptor. * @return bool */ private function is_statement_descriptor_confirmed( string $descriptor ): bool { $stored = get_option( self::STATEMENT_DESCRIPTOR_CONFIRMATION_OPTION, [] ); if ( ! is_array( $stored ) || empty( $stored['confirmed'] ) ) { return false; } $stored_descriptor = isset( $stored['normalized_descriptor'] ) ? (string) $stored['normalized_descriptor'] : ''; return '' !== $stored_descriptor && $stored_descriptor === $this->normalize_descriptor_value( $descriptor ); } /** * Returns possible store-specific descriptor comparison values. * * @param array $account_data Cached account data. * @return array */ private function get_store_descriptor_candidates( array $account_data ): array { $candidates = array_merge( [ get_bloginfo( 'name' ), get_home_url(), get_site_url(), ], $this->get_url_candidates( get_home_url() ), $this->get_url_candidates( get_site_url() ) ); $business_profile = isset( $account_data['business_profile'] ) && is_array( $account_data['business_profile'] ) ? $account_data['business_profile'] : []; if ( ! empty( $business_profile['url'] ) ) { $candidates = array_merge( $candidates, $this->get_url_candidates( (string) $business_profile['url'] ) ); } return array_unique( array_filter( $candidates ) ); } /** * Returns host/path candidates for a URL. * * @param string $url URL. * @return array */ private function get_url_candidates( string $url ): array { $host = (string) wp_parse_url( $url, PHP_URL_HOST ); $path = (string) wp_parse_url( $url, PHP_URL_PATH ); return array_filter( [ $url, $host, preg_replace( '/^www\./i', '', $host ), trim( $path, '/' ), ] ); } /** * Determines whether a normalized descriptor value is generic. * * @param string $normalized_descriptor Normalized descriptor. * @return bool */ private function is_generic_descriptor_value( string $normalized_descriptor ): bool { $generic_values = [ 'woocommerce', 'woocommercepayments', 'woopayments', 'woopaymentsstore', 'mystore', 'teststore', 'store', 'shop', 'onlinestore', ]; foreach ( $generic_values as $generic_value ) { if ( $normalized_descriptor === $generic_value || 0 === strpos( $normalized_descriptor, $generic_value ) ) { return true; } } return false; } /** * Normalizes values for statement descriptor comparison. * * @param string $value Raw value. * @return string */ private function normalize_descriptor_value( string $value ): string { $value = strtolower( trim( $value ) ); $value = preg_replace( '#^https?://#', '', $value ); $value = preg_replace( '#^www\.#', '', $value ); $value = preg_replace( '/[^a-z0-9]/', '', $value ); return is_string( $value ) ? $value : ''; } }