default ( array $defaults ). */ const DEFAULTS_FILTER = 'careback_text_defaults'; /** Filter: one text as it is shown ( string $value, string $key, Settings $settings ). */ const FILTER = 'careback_text'; /** Filter: one hint per key, naming where the text is shown ( array $hints ). */ const HINTS_FILTER = 'careback_text_hints'; /** Filter: the display grouping of the keys ( array $groups ). */ const GROUPS_FILTER = 'careback_text_groups'; /** Filter: the keys whose value is rendered as HTML ( string[] $keys ). */ const HTML_FILTER = 'careback_text_html_keys'; /** * Filter: the texts whose number the code fills in, key => a callable that * returns the wording for a number, %d kept ( array $counted ). See * counted() and format_number(). */ const COUNTED_FILTER = 'careback_text_counted'; /** * Suffix of a key's wording while the shop pays for sending the goods back * (N-116, Return_Costs): while it does, a key read through get() or all() * reads the key + this suffix where that key exists — this plugin's own * and an add-on's alike — and the shop's own wording of it. */ const SHOP_PAYS = '_shop_pays'; /** * Every key with its built-in wording: this plugin's own, and those an add-on * registers through `careback_text_defaults`. A key of this plugin's own * keeps its wording here whatever a callback returns (the shop's own wording * is laid over it by `careback_text`). * * @return array */ public static function defaults() { $own = self::own_defaults(); return self::keep_own( apply_filters( self::DEFAULTS_FILTER, $own ), $own ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- careback_text_defaults, the final prefix. } /** * A key => value list an add-on's callbacks returned, with the free part's * own entries put back as the free part has them: in place where the list * still holds the key, at the end where a callback took it out. * * @param mixed $filtered What the callbacks returned. * @param array $own The free part's own entries. * @return array */ public static function keep_own( $filtered, array $own ) { $out = is_array( $filtered ) ? $filtered : array(); foreach ( $own as $key => $value ) { $out[ $key ] = $value; } return $out; } /** * The keys this plugin itself shows, with their built-in wording. * * @return array */ private static function own_defaults() { $own = array( 'order_number' => __( 'Order number', 'careback' ), 'email' => __( 'Email address', 'careback' ), 'continue' => __( 'Continue', 'careback' ), 'checking' => __( 'Checking…', 'careback' ), 'need_order' => __( 'Please enter your order number.', 'careback' ), 'need_email' => __( 'Please enter a valid email address.', 'careback' ), 'no_order_items' => __( 'This order has no returnable items. Please contact us directly.', 'careback' ), 'quantity' => __( 'Quantity', 'careback' ), 'select_items' => __( 'Select the items you want to return', 'careback' ), 'unit_claimed' => __( 'already requested', 'careback' ), 'unit_claimed_withdrawal' => __( 'already in another request — you can still withdraw from the purchase for this item', 'careback' ), 'line_fully_claimed' => __( 'A request has already been filed for every unit of this item.', 'careback' ), 'units_rights_notice' => __( 'Your statutory right of withdrawal for the remaining items is unaffected. If a request was declined or withdrawn, that unit becomes available again.', 'careback' ), /* translators: a counter beside an item bought more than once: 1: units still available, 2: units bought. */ 'units_available' => __( 'Available: %1$d of %2$d', 'careback' ), 'reason' => __( 'Reason', 'careback' ), 'choose' => __( 'Please choose', 'careback' ), 'comment' => __( 'Comment', 'careback' ), 'send' => __( 'Send request', 'careback' ), // Per-route submit labels. Blank falls back to 'send'. 'send_withdrawal' => __( 'Confirm withdrawal', 'careback' ), 'send_return' => __( 'Send return request', 'careback' ), 'back' => __( 'Back', 'careback' ), 'sending' => __( 'Sending…', 'careback' ), 'thanks' => __( 'Thank you. We have received your request. A confirmation of receipt is on its way to your email address — if it does not arrive within a few minutes, please contact us.', 'careback' ), 'error' => __( 'Something went wrong. Please try again or contact us directly.', 'careback' ), 'no_items' => __( 'Please select at least one item.', 'careback' ), 'need_reason' => __( 'Please choose a reason for this return.', 'careback' ), 'need_comment' => __( 'Please add a comment describing the reason.', 'careback' ), // Server replies. Shown by the form when the request is refused. 'err_no_match' => __( 'We could not match those details. Please check the order number and email address, or contact us directly.', 'careback' ), 'err_throttled' => __( 'Too many attempts. Please try again later or contact us directly.', 'careback' ), 'err_session_expired' => __( 'Your session has expired, so we need to find your order again. Nothing has been sent yet.', 'careback' ), 'err_form_stale' => __( 'This page has been open for a while. Please reload it and send the form again.', 'careback' ), 'err_dispatch_reference' => __( 'Please enter the tracking or receipt number so we can match your parcel.', 'careback' ), 'dispatch_prompt' => __( 'Already sent it back? Tell us the tracking number', 'careback' ), 'dispatch_hint' => __( 'A tracking number, a receipt number from the counter, or whatever your carrier gave you. Telling us means we do not have to wait for the parcel to arrive before we can pay you back.', 'careback' ), 'dispatch_button' => __( 'Confirm sending', 'careback' ), 'dispatch_thanks' => __( 'Thank you — we have noted that you sent the parcel back.', 'careback' ), 'dispatch_already' => __( 'We already have this. Nothing further is needed from you.', 'careback' ), 'err_already_submitted' => __( 'We already have this request. Please start again if you want to send another one.', 'careback' ), 'err_reason_and_comment' => __( 'Please choose a reason and add a comment for this return.', 'careback' ), 'err_save_failed' => __( 'The request could not be saved. Please contact us directly.', 'careback' ), // The choice of route, and the way round the form. 'no_units_left' => __( 'All items in this order are already covered by a request. Please contact us directly if something is missing.', 'careback' ), 'no_script' => __( 'This form needs JavaScript. You can also withdraw or return by email: tell us your name, the order number and the items, and that you withdraw from the purchase or want to return them.', 'careback' ), /* translators: %s: site contact email address. */ 'fallback_default' => __( 'Cannot find your order? Write to us at %s.', 'careback' ), 'flow_question' => __( 'What would you like to do?', 'careback' ), 'flow_withdrawal' => __( 'Withdraw from the purchase and get my money back', 'careback' ), 'flow_withdrawal_hint' => __( 'No reason needed. This is your statutory right — the conditions below for our voluntary offers do not apply to it.', 'careback' ), 'flow_withdrawal_closed' => __( 'The statutory withdrawal period for this order has ended.', 'careback' ), 'flow_return' => __( 'Return the item and get my money back', 'careback' ), 'flow_return_hint' => __( 'Our voluntary return offer. The item must reach us unworn and complete, and you carry the direct cost of sending it back.', 'careback' ), 'flow_return_closed' => __( 'The return period for this order has ended. Please contact us directly.', 'careback' ), 'flow_none_available' => __( 'None of the options above is available for this order any more. Please contact us directly.', 'careback' ), // The form while statutory withdrawal is switched off (N-80): the return // is the one way back, named on its own, and nothing speaks of a right // the shop's customers do not have. 'return_single_title' => __( 'Return items', 'careback' ), // Its number is filled in by the code: a form for one and one for more (counted()). 'return_single_hint' => self::counted_default( self::own_counted()['return_single_hint'] ), 'units_rights_notice_return' => __( 'If a request was declined or withdrawn, that unit becomes available again.', 'careback' ), 'no_script_return' => __( 'This form needs JavaScript. You can also send us your return request by email: tell us your name, the order number and the items.', 'careback' ), 'link_returns' => __( 'Returns', 'careback' ), // Email body labels — editable so the whole email can be localised. /* translators: %s: date and time the request arrived. */ 'email_received' => __( 'We confirm that we received your declaration on %s.', 'careback' ), /* translators: %s: date and time the withdrawal arrived. */ 'email_withdrawal_received' => __( 'We confirm that we received your withdrawal from the purchase on %s. Your withdrawal is effective: the contract is cancelled and the period for refunding you has started. We will refund what you paid, including the standard delivery cost, as soon as the goods are back with us or you have sent us proof that you sent them back.', 'careback' ), /* translators: %s: date and time the report arrived. */ 'email_defect_received' => __( 'We confirm that we received your report of a faulty or incorrect item on %s. We will come back to you by email with the next steps. Your statutory rights, including any right of withdrawal still open to you, are unaffected.', 'careback' ), // The same while statutory withdrawal is switched off (N-80): no statutory right named. /* translators: %s: date and time the report arrived. */ 'email_defect_neutral' => __( 'We confirm that we received your report of a faulty or incorrect item on %s. We will come back to you by email with the next steps.', 'careback' ), 'email_fault_note' => __( 'You also told us that the item is damaged or is not the item you ordered. We will look into that and come back to you by email about it. Your legal guarantee rights are unaffected by this request.', 'careback' ), 'email_details' => __( 'Your details:', 'careback' ), 'email_order' => __( 'Order', 'careback' ), 'email_name' => __( 'Name', 'careback' ), 'email_reference'=> __( 'Reference', 'careback' ), 'email_receipt_code' => __( 'Receipt code', 'careback' ), 'email_items' => __( 'Items', 'careback' ), 'email_reason' => __( 'Reason', 'careback' ), 'email_comment' => __( 'Comment', 'careback' ), 'email_default_closing' => __( 'We will get back to you with the next steps.', 'careback' ), 'email_subject_ack' => __( 'Confirmation of receipt', 'careback' ), 'email_subject_status' => __( 'Update on your request', 'careback' ), /* translators: 1: request reference, 2: human readable status, 3: order number. */ 'email_status_default_body' => __( '

Your request %1$s is now: %2$s.

Order: %3$s

', 'careback' ), 'email_name_fallback' => __( 'Customer', 'careback' ), // Status names as the customer reads them, in the portal and in emails. 'status_new' => __( 'Received', 'careback' ), 'status_confirmed' => __( 'Confirmed', 'careback' ), 'status_label_sent' => __( 'Return instructions sent', 'careback' ), 'status_received' => __( 'Parcel received', 'careback' ), 'status_inspected' => __( 'Inspected', 'careback' ), 'status_refunded' => __( 'Refunded', 'careback' ), 'status_awaiting_customer' => __( 'Waiting for you', 'careback' ), 'status_rejected' => __( 'Not accepted', 'careback' ), 'status_duplicate' => __( 'Already in progress', 'careback' ), 'status_cancelled' => __( 'Cancelled', 'careback' ), // Field names of the personal-data export handed to the customer. 'privacy_group' => __( 'Careback requests', 'careback' ), 'privacy_reference' => __( 'Reference', 'careback' ), 'privacy_order' => __( 'Order', 'careback' ), 'privacy_name' => __( 'Name', 'careback' ), 'privacy_items' => __( 'Items', 'careback' ), 'privacy_reason' => __( 'Reason', 'careback' ), 'privacy_comment' => __( 'Comment', 'careback' ), 'privacy_status' => __( 'Status', 'careback' ), 'privacy_browser' => __( 'Browser', 'careback' ), 'privacy_created' => __( 'Created (UTC)', 'careback' ), 'privacy_resolution' => __( 'Agreed outcome', 'careback' ), 'privacy_resolution_note' => __( 'Note on the agreed outcome', 'careback' ), 'privacy_consent_quote' => __( 'Statement you confirmed', 'careback' ), ); return array_merge( $own, self::form_defaults(), self::shop_pays_defaults() ); } /** * The lines of step 2 on the cost of sending the goods back, in the shop's * words while it pays for it (N-116, SHOP_PAYS). * * @return array */ private static function shop_pays_defaults() { return array( 'flow_return_hint_shop_pays' => __( 'Our voluntary return offer. The item must reach us unworn and complete, and we pay the cost of sending it back.', 'careback' ), 'return_single_hint_shop_pays' => self::counted_default( self::own_counted()['return_single_hint_shop_pays'] ), ); } /** * The texts of the form's three steps, its check step and done screen * (N-04), the returns policy (N-12, N-13) and the link to the form, a legal * text (LEGAL). * * @return array */ private static function form_defaults() { return array( // The three steps of the form, the check step and the done screen (N-04). 'progress_label' => __( 'Steps', 'careback' ), 'step_find' => __( 'Find your order', 'careback' ), 'step_choose' => __( 'Choose items', 'careback' ), 'step_check' => __( 'Check and send', 'careback' ), /* translators: 1: number of the current step, 2: number of steps, 3: name of the current step. */ 'progress_short' => __( 'Step %1$d of %2$d: %3$s', 'careback' ), /* translators: 1: order number, 2: the day the order was placed. */ 'order_line' => __( 'Order #%1$s, placed %2$s', 'careback' ), 'review_title_withdrawal' => __( 'Check your withdrawal', 'careback' ), 'review_title_return' => __( 'Check your return request', 'careback' ), 'review_title' => __( 'Check your request', 'careback' ), /* translators: %s: the words on the button that sends the request, such as "Confirm withdrawal". */ 'review_not_sent' => __( 'Nothing has been sent yet. It is sent when you press “%s”.', 'careback' ), // Not the bare "Request" or "Return": a customer text shares no wording // with a label a catalogue ships translated (tests/test-texts.php). 'review_request' => __( 'Type of request', 'careback' ), 'review_order' => __( 'Order', 'careback' ), /* translators: 1: order number, 2: the day the order was placed. */ 'review_order_value' => __( '#%1$s, placed %2$s', 'careback' ), 'review_items' => __( 'Items', 'careback' ), 'review_name' => __( 'Name', 'careback' ), 'review_receipt_to' => __( 'Receipt to', 'careback' ), 'review_policy' => __( 'Returns policy', 'careback' ), 'review_type_withdrawal' => __( 'Withdrawal from the purchase', 'careback' ), 'review_type_return' => __( 'Return of items', 'careback' ), 'review_policy_accepted' => __( 'Accepted', 'careback' ), /* translators: 1: item name, 2: units chosen of it, 3: units bought. */ 'review_units' => __( '%1$s — %2$d of %3$d', 'careback' ), /* translators: %s: the customer's email address. */ 'review_receipt_note' => __( 'We will email a receipt to %s with these details and the date and time we received them.', 'careback' ), // Who pays for sending the goods back (N-116): the check step's row and // the confirmation email, on the routes whose goods go back. 'review_cost' => __( 'Cost of sending back', 'careback' ), 'return_cost' => __( 'You pay the direct cost of sending the items back.', 'careback' ), 'return_cost_shop_pays' => __( 'We pay the cost of sending the items back.', 'careback' ), 'review_name_input' => __( 'Your name', 'careback' ), 'review_need_name' => __( 'Please enter your name.', 'careback' ), 'done_title_withdrawal' => __( 'We have received your withdrawal', 'careback' ), 'done_title_return' => __( 'We have received your return request', 'careback' ), 'done_title' => __( 'We have received your request', 'careback' ), /* translators: 1: date, 2: time, 3: time zone, 4: reference of the request, such as "#128". */ 'done_received' => __( 'Received on %1$s at %2$s (%3$s). Your reference: %4$s.', 'careback' ), /* translators: %s: the customer's email address. */ 'done_receipt' => __( 'A receipt is on its way to %s. If it does not arrive within a few minutes, please contact us.', 'careback' ), /* translators: %s: the words on the button that sends the request, such as "Confirm withdrawal". */ 'err_confirm_network' => __( 'The connection failed before we could confirm your request. Please press “%s” again — if it did arrive, it is not recorded twice.', 'careback' ), // The returns policy: its link (N-13) and the consent with it (N-12). 'policy_link' => __( 'Read our returns policy', 'careback' ), 'opens_new_tab' => __( '(opens in a new tab)', 'careback' ), /* translators: %s: the link "returns policy" (consent_link). */ 'consent_label' => __( 'I have read and accept the %s.', 'careback' ), 'consent_link' => __( 'returns policy', 'careback' ), 'need_consent' => __( 'Please accept the returns policy to continue.', 'careback' ), // The link to the form in the shop's footer or menu: a legal text (LEGAL). 'withdraw_link' => __( 'Withdraw from contract here', 'careback' ), // The link under the form to the model withdrawal form (N-114). 'model_form_link' => __( 'Model withdrawal form', 'careback' ), 'email_policy_accepted' => __( 'You accepted our returns policy.', 'careback' ), // The consent in the customer's copy of their data (N-12). 'privacy_policy_accepted' => __( 'Returns policy accepted', 'careback' ), /* translators: 1: title of the returns policy page, 2: the moment it last changed (UTC). */ 'privacy_policy_page' => __( '“%1$s”, last changed %2$s (UTC)', 'careback' ), ); } /** * One hint per key of `defaults()`, naming the screen, step or email the * string is rendered in and the condition under which it is rendered: this * plugin's own, and those an add-on registers through `careback_text_hints`. * Read by a screen that lets the shop edit the texts. * * @return array */ public static function hints() { return (array) apply_filters( self::HINTS_FILTER, self::own_hints() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- careback_text_hints, the final prefix. } /** * The hints of this plugin's own keys. * * @return array */ private static function own_hints() { $own = array( // Step 1 — finding the order. 'order_number' => __( 'Label of the order-number field on step 1 of the portal. Always visible.', 'careback' ), 'email' => __( 'Label of the email field on step 1 of the portal. Always visible.', 'careback' ), 'continue' => __( 'Label of the button that closes step 1 and looks the order up. Always visible.', 'careback' ), 'checking' => __( 'Status line under the step 1 form. Shown from pressing the button until the answer arrives.', 'careback' ), 'need_order' => __( 'Inline message under the step 1 form. Shown when the button is pressed with an empty order-number field.', 'careback' ), 'need_email' => __( 'Inline message under the step 1 form. Shown when the button is pressed with an empty or malformed email address.', 'careback' ), 'no_order_items' => __( 'Replaces step 2 when the order was found but carries no line that can be returned.', 'careback' ), 'no_script' => __( 'Lead line of the block that replaces the portal when the browser has JavaScript switched off: how to withdraw or return by email instead.', 'careback' ), 'no_script_return' => __( 'The same line while statutory withdrawal is switched off in Settings: how to send a return request by email instead.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'fallback_default' => __( 'Contact line printed under the portal and inside the no-JavaScript block. Used only while the contact line in the settings above is empty; %s becomes the site admin address.', 'careback' ), // Step 2 — the options. 'flow_question' => __( 'Heading over the list of options on step 2. Always visible once an order is found.', 'careback' ), 'flow_withdrawal' => __( 'Label of the statutory withdrawal option on step 2. Always listed.', 'careback' ), 'flow_withdrawal_hint' => __( 'Line under the statutory withdrawal option on step 2. Shown while that option can still be chosen.', 'careback' ), 'flow_withdrawal_closed' => __( 'Shown next to the statutory withdrawal option when the period recorded for this order has passed. The option is disabled and this line explains why.', 'careback' ), 'flow_return' => __( 'Label of the voluntary return option on step 2. Listed only once the statutory period has passed.', 'careback' ), 'flow_return_hint' => __( 'Line under the voluntary return option on step 2. Shown while that option can still be chosen.', 'careback' ), 'flow_return_closed' => __( 'Replaces that line when the return period for this order has passed. The option stays listed but cannot be selected.', 'careback' ), 'return_single_title' => __( 'Heading of the return on step 2 while statutory withdrawal is switched off in Settings, where it is the only option.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'return_single_hint' => __( 'Line under that heading while statutory withdrawal is switched off. %d becomes your return period in days.', 'careback' ), 'link_returns' => __( 'The text of the link in your footer or menu that opens the form, while statutory withdrawal is switched off. Setup hands it over to copy.', 'careback' ), 'flow_none_available' => __( 'Replaces the whole of step 2 when no option is open for this order. Also the answer when the chosen option closed while the form was open.', 'careback' ), 'send_withdrawal' => __( 'The button on the check step that sends a statutory withdrawal, and the words the line above it names. A legal text: set it under Portal and form → Legal wording.', 'careback' ), 'send_return' => __( 'The button on the check step that sends a voluntary return, and the words the line above it names. Blank falls back to the generic submit label.', 'careback' ), // Step 2 — the items. 'select_items' => __( 'Heading over the item list on step 2. Always visible.', 'careback' ), 'unit_claimed' => __( 'Badge next to a single unit of an item that an earlier request already covers. Appears only when part of an order is already claimed.', 'careback' ), 'unit_claimed_withdrawal' => __( 'Replaces that badge while the statutory withdrawal option is selected and the earlier request is an exchange or a voluntary return. The unit stays tickable on that option and is greyed out on every other one.', 'careback' ), 'line_fully_claimed' => __( 'Note on an item whose every unit an earlier request already covers. The item is listed but cannot be ticked.', 'careback' ), 'units_rights_notice' => __( 'Paragraph under the item list on step 2. Shown only when at least one unit is marked as already requested.', 'careback' ), 'units_rights_notice_return' => __( 'The same paragraph while statutory withdrawal is switched off in Settings.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'units_available' => __( 'Counter beside an item bought more than once. Shown only when part of that item is already claimed; %1$d is what is left, %2$d what was bought.', 'careback' ), 'quantity' => __( 'Screen-reader label of the quantity box that replaces one row per unit, used when an item was bought more often than the threshold set above.', 'careback' ), 'reason' => __( 'Label of the reason dropdown on step 2. Hidden while the reason field is switched off above, and forced back on once the statutory period has passed.', 'careback' ), 'choose' => __( 'Empty first entry of the reason dropdown. Shown whenever that dropdown is.', 'careback' ), 'comment' => __( 'Label of the comment box on step 2. Hidden while the comment field is switched off above, and forced back on once the statutory period has passed.', 'careback' ), 'send' => __( 'Label of the button that sends the request on the check step. Used while the selected option carries no label of its own.', 'careback' ), 'back' => __( 'Label of the button that goes back a step: on step 2 to the order lookup, on the check step to step 2 with everything chosen kept.', 'careback' ), 'sending' => __( 'Status line under the form. Shown from pressing submit until the answer arrives.', 'careback' ), // Validation messages. 'error' => __( 'Generic failure line under the form. Shown when the server could not be reached or answered without a message of its own.', 'careback' ), 'err_no_match' => __( 'Answer to step 1 when order number and email match no order. Deliberately the same wording whether the number or the address was wrong.', 'careback' ), 'err_throttled' => __( 'Answer to a lookup or a submit after more attempts from the same visitor than the limit set below allows.', 'careback' ), 'err_session_expired' => __( 'Answer to a submit whose session has run out. The form goes back to step 1 with the order number and email still filled in.', 'careback' ), 'err_dispatch_reference' => __( 'Answer when the customer pressed the button without typing a reference. The law binds proof of return to no particular form, so anything they type is accepted — but something has to be there to match the parcel against.', 'careback' ), 'dispatch_prompt' => __( 'Heading of the small form on the portal where a customer tells you they have posted the goods back. It appears on a statutory withdrawal that is still waiting, and disappears once the parcel or the proof is recorded.', 'careback' ), 'dispatch_hint' => __( 'Explains what to type. Worth keeping plain: the whole point is that the customer supplies this rather than the shop guessing, because their message ends the right to withhold payment on the day it arrives.', 'careback' ), 'dispatch_button' => __( 'Wording on the button beneath that field.', 'careback' ), 'dispatch_thanks' => __( 'Answer once the reference is stored. From that moment the refund can no longer be held back waiting for the parcel.', 'careback' ), 'dispatch_already' => __( 'Answer when the shop already recorded the parcel or the proof. Deliberately not an error: from where the customer stands, nothing is wrong.', 'careback' ), 'err_form_stale' => __( 'Answer when the form was rendered longer ago than the timing check allows — almost always a page cache serving old HTML, not a bot. Nothing is lost: reloading the page fixes it, and the attempt is not counted against the visitor.', 'careback' ), 'err_already_submitted' => __( 'Answer to a submit that reuses a session already spent, for example a double click or a resent form.', 'careback' ), 'err_reason_and_comment' => __( 'Answer to a submit with an empty reason or comment, in the case where both are required because the statutory period has passed.', 'careback' ), 'err_save_failed' => __( 'Answer to a submit that passed every check but could not be written to the database.', 'careback' ), 'no_items' => __( 'Inline message under the form. Shown when submit is pressed with no item ticked.', 'careback' ), 'need_reason' => __( 'Inline message shown when submit is pressed with no reason chosen, in the case where a reason is required.', 'careback' ), 'need_comment' => __( 'Inline message shown when submit is pressed with an empty comment, in the case where a comment is required.', 'careback' ), 'no_units_left' => __( 'Answer to a submit whose every ticked unit was claimed by another request in the meantime.', 'careback' ), // Confirmation. 'thanks' => __( 'Replaces the form once a request has been filed, when the answer carries no reference (an older server). The form otherwise shows the three lines below.', 'careback' ), // Email body. 'email_subject_ack' => __( 'Subject line of the confirmation email sent right after a request is filed. Used while the acknowledgement subject in the Email templates section below is empty.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'email_received' => __( 'First line of the confirmation email, carrying the moment the request arrived. Used for a return filed under a voluntary offer, once the statutory period has passed; %s becomes that date and time.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'email_withdrawal_received' => __( 'The same line for a request recorded as a statutory withdrawal, whichever option the customer picked; %s becomes the date and time it arrived. The reason chosen never replaces this line.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'email_defect_received' => __( 'The same line for a voluntary return whose reason is one marked as a fault in the reason list; %s becomes the date and time it arrived. A withdrawal or an exchange keeps its own line above and carries the paragraph below instead.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'email_defect_neutral' => __( 'The same line while statutory withdrawal is switched off in Settings, used in place of the one above: it names no statutory right. %s becomes the date and time it arrived.', 'careback' ), 'email_fault_note' => __( 'Paragraph printed under that first line when the reason chosen is one marked as a fault in the reason list, on a withdrawal or an exchange. It is added to the line above, never in place of it.', 'careback' ), 'email_details' => __( 'Heading over the order, name and reference block of the confirmation email. Always printed.', 'careback' ), 'email_order' => __( 'Label of the order number in that block of the confirmation email. Always printed.', 'careback' ), 'email_name' => __( 'Label of the customer name in that block of the confirmation email. Always printed.', 'careback' ), 'email_name_fallback' => __( 'Stands in for the customer name on the request and in the confirmation email, when the order carries neither a name nor an email address to derive one from.', 'careback' ), 'email_reference' => __( 'Label of the request reference in that block of the confirmation email. Always printed.', 'careback' ), 'email_receipt_code' => __( 'Label of the receipt code in that block of the confirmation email: a code worked out from the request as it arrived and the moment it arrived, so the request you keep can later be shown to match what the customer was sent.', 'careback' ), 'email_items' => __( 'Heading over the item list of the confirmation email. Always printed.', 'careback' ), 'email_reason' => __( 'Label of the reason in the confirmation email. Printed only when a reason was chosen.', 'careback' ), 'email_comment' => __( 'Label of the comment in the confirmation email. Printed only when a comment was written.', 'careback' ), 'email_default_closing' => __( 'Last line of the confirmation email. Used while the closing line in the Email templates section below is empty.', 'careback' ), // Request status — portal and status emails. 'email_subject_status' => __( 'Subject line of the status email. Used for the statuses switched on in the Status update emails section below, which are all off by default, and only where that status has no subject of its own.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'email_status_default_body' => __( 'Body of the status email for a status you switched on but gave no template of its own. %1$s is the reference, %2$s the status name, %3$s the order number; HTML is kept.', 'careback' ), 'status_new' => __( 'Name the customer reads for a request that has just arrived. Used in the list of filed requests on step 2 and in the status email; the admin screens keep their own wording.', 'careback' ), 'status_confirmed' => __( 'Name the customer reads for a request you have accepted. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_label_sent' => __( 'Name the customer reads once the return instructions have gone out. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_received' => __( 'Name the customer reads once the parcel has reached you. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_inspected' => __( 'Name the customer reads once the returned item has been checked. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_refunded' => __( 'Name the customer reads once the full amount has been paid back. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_awaiting_customer' => __( 'Name the customer reads for a request waiting on something from them. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_rejected' => __( 'Name the customer reads for a request you turned down. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_duplicate' => __( 'Name the customer reads for a request that repeats one already in hand. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), 'status_cancelled' => __( 'Name the customer reads for a request that was called off. Used in the list of filed requests on step 2 and in the status email.', 'careback' ), // Personal-data export. 'privacy_group' => __( 'Name of the group the requests are filed under in a personal-data export. Appears only in an export produced through the privacy tools of the site.', 'careback' ), 'privacy_reference' => __( 'Field name of the request reference in that export. Always present.', 'careback' ), 'privacy_order' => __( 'Field name of the order number in that export. Always present.', 'careback' ), 'privacy_name' => __( 'Field name of the customer name in that export. Always present.', 'careback' ), 'privacy_items' => __( 'Field name of the returned items in that export. Always present.', 'careback' ), 'privacy_reason' => __( 'Field name of the chosen reason in that export. Always present, empty when no reason was chosen.', 'careback' ), 'privacy_comment' => __( 'Field name of the comment in that export. Always present, empty when none was written.', 'careback' ), 'privacy_status' => __( 'Field name of the request status in that export. Always present.', 'careback' ), 'privacy_browser' => __( 'Field name of the browser the request was sent from, in that export. Empty for a declaration recorded by hand.', 'careback' ), 'privacy_created' => __( 'Field name of the date the request was filed, in that export. Always present.', 'careback' ), 'privacy_resolution' => __( 'Field name of the agreed outcome, in that export. Empty until an operator settles the request by agreement.', 'careback' ), 'privacy_resolution_note' => __( 'Field name of the note on that agreed outcome, in the same export. Empty until an operator writes one.', 'careback' ), 'privacy_consent_quote' => __( 'Field name of the wording the customer agreed to for an outcome settled by agreement, in that export. Empty until an operator records it.', 'careback' ), ); return array_merge( $own, self::form_hints(), array( 'flow_return_hint_shop_pays' => __( 'The same line while the shop pays for sending the goods back (Portal and form → Portal), used in place of the one above.', 'careback' ), /* translators: a hint naming the placeholders of the text it describes; keep them exactly as written. */ 'return_single_hint_shop_pays' => __( 'The same line while the shop pays for sending the goods back, used in place of the one above. %d becomes your return period in days.', 'careback' ), ) ); } /** * The hints of the texts form_defaults() adds. * * @return array */ private static function form_hints() { return array( 'progress_label' => __( 'Name of the list of the three steps above the form, read out by screen readers.', 'careback' ), 'step_find' => __( 'Name of step 1 in that list.', 'careback' ), 'step_choose' => __( 'Name of step 2 in that list.', 'careback' ), 'step_check' => __( 'Name of step 3, the check step, in that list.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'progress_short' => __( 'The line that replaces the list on a phone: %1$d the step, %2$d the number of steps, %3$s its name.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'order_line' => __( 'First line of step 2 and the order row of the check step: %1$s the order number, %2$s the day it was placed.', 'careback' ), 'review_title_withdrawal' => __( 'Heading of the check step for a statutory withdrawal.', 'careback' ), 'review_title_return' => __( 'Heading of the check step for a voluntary return.', 'careback' ), 'review_title' => __( 'Heading of the check step for any other request.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'review_not_sent' => __( 'Line under that heading; %s becomes the words on the button that sends the request.', 'careback' ), 'review_request' => __( 'Label of the row of the check step naming what is requested.', 'careback' ), 'review_type_withdrawal' => __( 'What the request row of the check step says for a statutory withdrawal.', 'careback' ), 'review_type_return' => __( 'What the request row of the check step says for a voluntary return.', 'careback' ), 'review_order' => __( 'Label of the order row of the check step.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'review_order_value' => __( 'What the order row of the check step says: %1$s the order number, %2$s the day it was placed.', 'careback' ), 'review_items' => __( 'Label of the items row of the check step.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'review_units' => __( 'An item of the check step of which only some units are sent: %1$s the item, %2$d the units sent, %3$d the units bought.', 'careback' ), 'review_name' => __( 'Label of the name row of the check step.', 'careback' ), 'review_name_input' => __( 'Label of the name field the check step shows in place of the name row, for an order that carries no name.', 'careback' ), 'review_receipt_to' => __( 'Label of the row of the check step naming the email address the receipt goes to.', 'careback' ), 'review_policy' => __( 'Label of the row of the check step shown when the returns policy was accepted.', 'careback' ), 'review_policy_accepted' => __( 'What the returns policy row of the check step says.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'review_receipt_note' => __( 'Line under the rows of the check step; %s becomes the email address the receipt goes to.', 'careback' ), 'review_cost' => __( 'Name of the row of the check step that says who pays for sending the goods back, on a withdrawal or a return.', 'careback' ), 'return_cost' => __( 'That row while the customer pays (Portal and form → Portal). Also a line of the confirmation email of a withdrawal or a return, except a return reported as faulty.', 'careback' ), 'return_cost_shop_pays' => __( 'The same while the shop pays, used in place of the one above.', 'careback' ), 'review_need_name' => __( 'Shown beside the name field of the check step when it was left empty. That field appears only for an order that carries no name.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'err_confirm_network' => __( 'Shown on the check step when the connection failed after the button was pressed. %s becomes the words on that button.', 'careback' ), 'done_title_withdrawal' => __( 'Heading of the block that replaces the form once a statutory withdrawal has been filed.', 'careback' ), 'done_title_return' => __( 'The same heading for a voluntary return.', 'careback' ), 'done_title' => __( 'The same heading for any other request.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'done_received' => __( 'Line under that heading: %1$s the date, %2$s the time, %3$s the time zone of your site, %4$s the reference of the request.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'done_receipt' => __( 'Last line of that block; %s becomes the email address the receipt is sent to.', 'careback' ), 'policy_link' => __( 'Link to your returns policy page under the options on step 2, opening in a new tab. Shown while a published page is chosen under Portal and form → Returns policy page, except on that page itself.', 'careback' ), 'opens_new_tab' => __( 'Read out by screen readers after every link of the form that opens in a new tab.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'consent_label' => __( 'The checkbox under the comment on step 2 for a voluntary return, while the consent is switched on under Voluntary return. %s becomes the link below.', 'careback' ), 'consent_link' => __( 'The words of that checkbox that link to your returns policy page.', 'careback' ), 'need_consent' => __( 'Shown beside the returns policy checkbox when the form is continued without it ticked, on any request that asks for it; also the answer of the server to such a request.', 'careback' ), 'withdraw_link' => __( 'The text of the link in your footer or menu that opens the form. A legal text: set it under Portal and form → Legal wording.', 'careback' ), 'model_form_link' => __( 'Link under the form to the model withdrawal form, filled in with your shop\'s name, address and email, opening in a new tab. Shown while statutory withdrawal is on.', 'careback' ), 'email_policy_accepted' => __( 'Line of the confirmation email printed when the customer accepted your returns policy on the form.', 'careback' ), 'privacy_policy_accepted' => __( 'Field name of the consent with your returns policy, in a personal-data export. Present only for a request filed with that consent.', 'careback' ), /* translators: %s, %d and their numbered forms are placeholders the text names; keep them. */ 'privacy_policy_page' => __( 'Its value: %1$s the title of the page, %2$s the moment it last changed when the consent was given.', 'careback' ), ); } /** * Keys of this plugin whose value is rendered as HTML. Saved through * `wp_kses_post`; every other key is saved through `sanitize_text_field`. * An add-on names its own through `careback_text_html_keys`. */ const HTML_KEYS = array( 'email_status_default_body', 'fallback_default', ); /** * The two legal texts a shop words itself, key => the setting holding its * words: the link to the form in the footer or menu, and the button that * sends a withdrawal. Withdrawal laws name these words, and each language * has its own, so they are settings of the free part (Portal and form → * Legal wording). Set, the shop's words are what the key reads, whatever * the language and whatever wording `careback_text` lays over it; empty, * the translated default (and that wording) is. */ const LEGAL = array( 'withdraw_link' => 'legal_link_text', 'send_withdrawal' => 'legal_confirm_text', ); /** The most characters each legal setting takes. */ const LEGAL_MAX = array( 'legal_link_text' => 60, 'legal_confirm_text' => 40, ); /** True when the key's value keeps safe markup instead of being stripped. */ public static function allows_html( $key ) { $keys = (array) apply_filters( self::HTML_FILTER, self::HTML_KEYS ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- careback_text_html_keys, the final prefix. return in_array( (string) $key, $keys, true ); } /** * Display grouping for a screen that lists the texts: group key => label and * keys, in order. An add-on places its own keys and groups through * `careback_text_groups`. Keys not listed in any group fall into the last * group (grouped()), so adding a string never hides it from the merchant. * * @return array */ public static function groups() { $groups = array( 'lookup' => array( 'label' => __( 'Step 1 — finding the order', 'careback' ), 'keys' => array( 'order_number', 'email', 'continue', 'checking', 'need_order', 'need_email', 'no_order_items', 'no_script', 'no_script_return', 'fallback_default', 'withdraw_link', 'model_form_link' ), ), 'flow' => array( // The form's step 2 ("Choose items") holds the options and the items (Careback 0.84: three steps). 'label' => __( 'Step 2 — the options', 'careback' ), 'keys' => array( 'flow_question', 'flow_withdrawal', 'flow_withdrawal_hint', 'flow_withdrawal_closed', 'flow_return', 'flow_return_hint', 'flow_return_hint_shop_pays', 'flow_return_closed', 'return_single_title', 'return_single_hint', 'return_single_hint_shop_pays', 'link_returns', 'flow_none_available', 'send_withdrawal', 'send_return', 'policy_link', 'opens_new_tab' ), ), 'items' => array( 'label' => __( 'Step 2 — the items', 'careback' ), 'keys' => array( 'select_items', 'unit_claimed', 'unit_claimed_withdrawal', 'line_fully_claimed', 'units_rights_notice', 'units_rights_notice_return', 'units_available', 'quantity', 'reason', 'choose', 'comment', 'consent_label', 'consent_link', 'send', 'back', 'sending' ), ), 'errors' => array( 'label' => __( 'Validation messages', 'careback' ), 'keys' => array( 'error', 'err_no_match', 'err_throttled', 'err_session_expired', 'err_form_stale', 'err_dispatch_reference', 'err_already_submitted', 'err_reason_and_comment', 'err_save_failed', 'no_items', 'need_reason', 'need_comment', 'no_units_left', 'review_need_name', 'need_consent', 'err_confirm_network' ), ), 'dispatch' => array( 'label' => __( 'Telling us the parcel is on its way', 'careback' ), 'keys' => array( 'dispatch_prompt', 'dispatch_hint', 'dispatch_button', 'dispatch_thanks', 'dispatch_already' ), ), 'confirmation' => array( 'label' => __( 'Confirmation', 'careback' ), 'keys' => array( 'thanks', 'done_title_withdrawal', 'done_title_return', 'done_title', 'done_received', 'done_receipt' ), ), 'email' => array( 'label' => __( 'Email body', 'careback' ), 'keys' => array( 'email_subject_ack', 'email_received', 'email_withdrawal_received', 'email_defect_received', 'email_defect_neutral', 'email_fault_note', 'email_details', 'email_order', 'email_name', 'email_name_fallback', 'email_reference', 'email_receipt_code', 'email_items', 'email_reason', 'email_comment', 'email_policy_accepted', 'email_default_closing' ), ), 'status' => array( 'label' => __( 'Request status — portal and status emails', 'careback' ), // One name per registered status, in the order of the status list. 'keys' => array_merge( array( 'email_subject_status', 'email_status_default_body' ), array_values( Statuses::text_keys() ) ), ), 'privacy' => array( 'label' => __( 'Personal-data export', 'careback' ), 'keys' => array( 'privacy_group', 'privacy_reference', 'privacy_order', 'privacy_name', 'privacy_items', 'privacy_reason', 'privacy_comment', 'privacy_status', 'privacy_browser', 'privacy_created', 'privacy_resolution', 'privacy_resolution_note', 'privacy_consent_quote', 'privacy_policy_accepted', 'privacy_policy_page' ), ), ); // The steps of the form first, its check step right after the items (N-04). $groups = array( 'steps' => array( 'label' => __( 'The steps of the form', 'careback' ), 'keys' => array( 'progress_label', 'step_find', 'step_choose', 'step_check', 'progress_short', 'order_line' ), ), ) + $groups; $at = array_search( 'items', array_keys( $groups ), true ) + 1; $groups = array_slice( $groups, 0, $at, true ) + array( 'review' => array( 'label' => __( 'Check and send', 'careback' ), 'keys' => array( 'review_title_withdrawal', 'review_title_return', 'review_title', 'review_not_sent', 'review_request', 'review_type_withdrawal', 'review_type_return', 'review_order', 'review_order_value', 'review_items', 'review_units', 'review_name', 'review_name_input', 'review_receipt_to', 'review_policy', 'review_policy_accepted', 'review_cost', 'return_cost', 'return_cost_shop_pays', 'review_receipt_note' ), ), ) + array_slice( $groups, $at, null, true ); return (array) apply_filters( self::GROUPS_FILTER, $groups ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- careback_text_groups, the final prefix. } /** Groups with any unlisted key appended, so nothing can be lost from the UI. */ public static function grouped() { $groups = self::groups(); $listed = array(); foreach ( $groups as $group ) { $listed = array_merge( $listed, $group['keys'] ); } $rest = array_diff( array_keys( self::defaults() ), $listed ); if ( ! empty( $rest ) ) { $groups['other'] = array( // Given a context: the same word is a built-in reason label the // customer sees, and that one may not ship translated — a // translated built-in would win over the row the merchant wrote // and put a second language in the dropdown. 'label' => _x( 'Other', 'settings text group', 'careback' ), 'keys' => array_values( $rest ), ); } return $groups; } /** * What one key reads: its built-in wording, passed through `careback_text` * with the settings it is read for. An unknown key starts from ''. * * @param string $key Text key. * @param Settings $settings Settings the text is read for. * @return string */ public static function get( $key, Settings $settings ) { $defaults = self::defaults(); $key = self::variant( (string) $key, $defaults, $settings ); return self::resolve( $key, isset( $defaults[ $key ] ) ? $defaults[ $key ] : '', $settings ); } /** * The key a text is read under: its wording for the shop paying for sending * the goods back (SHOP_PAYS) while the shop does and that wording exists, * else the key itself. * * @param string $key Text key. * @param array $defaults Every key with its built-in wording. * @param Settings $settings Settings the text is read for. * @return string */ private static function variant( $key, array $defaults, Settings $settings ) { $shop = $key . self::SHOP_PAYS; return isset( $defaults[ $shop ] ) && Return_Costs::shop_pays( $settings ) ? $shop : $key; } /** * One key's default through `careback_text`; a legal text (LEGAL) the shop * worded itself reads its words. */ private static function resolve( $key, $default, Settings $settings ) { $value = (string) apply_filters( self::FILTER, (string) $default, (string) $key, $settings ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- careback_text, the final prefix. if ( isset( self::LEGAL[ $key ] ) ) { $own = trim( (string) $settings->get( self::LEGAL[ $key ], '' ) ); if ( '' !== $own ) { return $own; } } return $value; } /** * The texts whose number the code fills in, key => a callable that takes * the number and returns the wording in the form the reader's language * uses for it, %d kept: this plugin's own (own_counted_text()) and those an * add-on names through `careback_text_counted` (its own _n() in its own * text domain). This plugin's own keep theirs whatever a callback returns; * an entry that is not callable is left out. * * @return array */ public static function counted() { $own = self::own_counted(); $filtered = apply_filters( self::COUNTED_FILTER, $own ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- careback_text_counted, the final prefix. return array_merge( array_filter( is_array( $filtered ) ? $filtered : array(), 'is_callable' ), $own ); } /** * This plugin's counted texts: "within %d days" in one string reads wrong * for one day and, in languages such as Polish or Ukrainian, for most * numbers (step 6, translations round 2). * * @return array */ private static function own_counted() { $own = array(); foreach ( array( 'return_single_hint', 'return_single_hint_shop_pays' ) as $key ) { $own[ $key ] = static function ( $number ) use ( $key ) { return self::own_counted_text( $key, $number ); }; } return $own; } /** * The wording of one of this plugin's counted texts for a number, %d kept. * * @param string $key Text key. * @param int $number The number. * @return string */ private static function own_counted_text( $key, $number ) { $number = (int) $number; switch ( $key ) { case 'return_single_hint': /* translators: %d: the shop's return period in days. */ return _n( 'Our return offer: you can return items within %d day of delivery. The item must reach us unworn and complete, and you carry the direct cost of sending it back.', 'Our return offer: you can return items within %d days of delivery. The item must reach us unworn and complete, and you carry the direct cost of sending it back.', $number, 'careback' ); case 'return_single_hint_shop_pays': /* translators: %d: the shop's return period in days. */ return _n( 'Our return offer: you can return items within %d day of delivery. The item must reach us unworn and complete, and we pay the cost of sending it back.', 'Our return offer: you can return items within %d days of delivery. The item must reach us unworn and complete, and we pay the cost of sending it back.', $number, 'careback' ); } return ''; } /** * A counted text's built-in wording as the texts editor shows it (its * default): the form for a period such as 14 days, %d kept. * * An add-on built for 0.84.1 hands an _n_noop() array instead: its plural * is returned as written (untranslated), so the key still has a wording. * * @param callable|array $text The counted text (counted()): number => wording. * @return string */ public static function counted_default( $text ) { if ( is_callable( $text ) ) { return (string) call_user_func( $text, 14 ); } return is_array( $text ) && isset( $text['plural'] ) && is_string( $text['plural'] ) ? $text['plural'] : ''; } /** * A text whose number the code fills in (counted()): while it reads its * built-in wording, in the form the reader's language uses for that number * ("within 1 day", "within 30 days"); a wording the shop gave it (through * `careback_text`), as written with the number filled in (format()). * * @param string $key Text key. * @param Settings $settings Settings the text is read for. * @param int $number The number. * @return string */ public static function format_number( $key, Settings $settings, $number ) { $number = (int) $number; $defaults = self::defaults(); $read = self::variant( (string) $key, $defaults, $settings ); $counted = self::counted(); if ( isset( $counted[ $read ], $defaults[ $read ] ) && self::resolve( $read, $defaults[ $read ], $settings ) === $defaults[ $read ] ) { return sprintf( (string) call_user_func( $counted[ $read ], $number ), $number ); } return self::format( $key, $settings, array( $number ) ); } /** * The string with its placeholders filled in. A template whose placeholders * do not match the arguments is returned unchanged instead of raising. * * @param array $args Values for the placeholders, in order. */ public static function format( $key, Settings $settings, array $args ) { $template = self::get( $key, $settings ); try { $out = @vsprintf( $template, $args ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged } catch ( \Throwable $error ) { return $template; } return is_string( $out ) ? $out : $template; } /** * Every key as it reads for these settings, in the order of `defaults()`. * * @return array */ public static function all( Settings $settings ) { $out = array(); $defaults = self::defaults(); foreach ( $defaults as $key => $default ) { $read = self::variant( (string) $key, $defaults, $settings ); $out[ $key ] = self::resolve( $read, $defaults[ $read ], $settings ); } return $out; } }